onionwire/src/ratelimit.rs

46 lines
1.2 KiB
Rust
Raw Normal View History

//! App-level token bucket for incoming rendezvous accepts.
use std::time::{Duration, Instant};
pub struct TokenBucket {
rate_per_sec: f64,
burst: f64,
tokens: f64,
last: Instant,
}
impl TokenBucket {
/// `count` tokens replenished over `window`, starting full up to `burst`.
pub fn new(count: u32, window: Duration, burst: u32) -> Self {
let secs = window.as_secs_f64().max(f64::EPSILON);
Self {
rate_per_sec: f64::from(count) / secs,
burst: f64::from(burst),
tokens: f64::from(burst),
last: Instant::now(),
}
}
pub fn try_acquire(&mut self) -> bool {
self.try_acquire_at(Instant::now())
}
pub fn try_acquire_at(&mut self, now: Instant) -> bool {
let elapsed = now.saturating_duration_since(self.last).as_secs_f64();
self.last = now;
self.tokens = (self.tokens + elapsed * self.rate_per_sec).min(self.burst);
if self.tokens >= 1.0 {
self.tokens -= 1.0;
true
} else {
false
}
}
}
impl Default for TokenBucket {
fn default() -> Self {
Self::new(30, Duration::from_secs(60), 10)
}
}