fedimint_gateway_server/
rate_limit.rs1use std::sync::Mutex;
2use std::time::SystemTime;
3
4use fedimint_core::time::now;
5
6#[derive(Debug)]
15pub struct TokenBucketRateLimiter {
16 burst: f64,
17 refill_per_second: f64,
18 state: Mutex<TokenBucketState>,
19}
20
21#[derive(Debug)]
22struct TokenBucketState {
23 tokens: f64,
24 last_refill: SystemTime,
25}
26
27impl TokenBucketRateLimiter {
28 pub fn new(burst: u32, refill_per_second: u32) -> Self {
29 Self {
30 burst: f64::from(burst),
31 refill_per_second: f64::from(refill_per_second),
32 state: Mutex::new(TokenBucketState {
33 tokens: f64::from(burst),
34 last_refill: now(),
35 }),
36 }
37 }
38
39 pub fn try_acquire(&self) -> bool {
42 self.try_acquire_at(now())
43 }
44
45 fn try_acquire_at(&self, now: SystemTime) -> bool {
46 let mut state = self
47 .state
48 .lock()
49 .expect("No code holding the lock can panic");
50
51 let elapsed = now
54 .duration_since(state.last_refill)
55 .unwrap_or_default()
56 .as_secs_f64();
57 state.tokens = (state.tokens + elapsed * self.refill_per_second).min(self.burst);
58 state.last_refill = now;
59
60 if state.tokens >= 1.0 {
61 state.tokens -= 1.0;
62 true
63 } else {
64 false
65 }
66 }
67}
68
69#[cfg(test)]
70mod tests;