use std::{collections::HashMap, time::Instant};
use crate::{Selfb, TokenBucket};
impl TokenBucket {
pub fn new(capacity: u64, rates: f64) -> Self {
let rates = rates / 1000.0;
Self {
capacity,
rates,
last_update: HashMap::new(),
}
}
fn bucket(&mut self, key: String) {
let now = Instant::now();
let (tokens, b) = self.last_update.entry(key).or_insert((0.0, now));
let current = now.duration_since(*b).as_millis();
let btoken = (self.rates * current as f64).ceil();
*tokens = (*tokens + btoken).min(self.capacity as f64);
*b = now;
}
pub fn allow(&mut self, key: impl Into<String> + Copy, token: impl Into<f64>) -> Selfb {
let key = key.into();
let token = token.into();
self.bucket(key.clone());
let (tokens, _) = self.last_update.get_mut(&key).unwrap();
if token <= *tokens {
*tokens -= token;
Selfb {
is_allowed: true,
remaning_count: *tokens as u64,
}
} else {
Selfb {
is_allowed: false,
remaning_count: *tokens as u64,
}
}
}
}