use {std::time::Duration, tokio::time::Instant};
#[derive(Debug)]
pub struct RateLimiter {
pub(crate) count: u64,
throttle_start_instant: Instant,
interval: Duration,
limit: u64,
}
impl RateLimiter {
pub fn new(limit: u64, interval: Duration) -> Self {
Self {
count: 0,
throttle_start_instant: Instant::now(),
interval,
limit,
}
}
pub fn reset_throttling_params_if_needed(&mut self) {
if Instant::now().duration_since(self.throttle_start_instant) > self.interval {
self.throttle_start_instant = Instant::now();
self.count = 0;
}
}
pub fn check_and_update(&mut self) -> bool {
self.reset_throttling_params_if_needed();
if self.count >= self.limit {
return false;
}
self.count = self.count.saturating_add(1);
true
}
pub fn throttle_start_instant(&self) -> &Instant {
&self.throttle_start_instant
}
}
#[cfg(test)]
pub mod test {
use {super::*, tokio::time::sleep};
#[tokio::test]
async fn test_rate_limiter() {
let mut limiter = RateLimiter::new(2, Duration::from_millis(100));
assert!(limiter.check_and_update());
assert!(limiter.check_and_update());
assert!(!limiter.check_and_update());
let instant1 = *limiter.throttle_start_instant();
sleep(Duration::from_millis(150)).await;
assert!(limiter.check_and_update());
assert!(limiter.check_and_update());
assert!(!limiter.check_and_update());
let instant2 = *limiter.throttle_start_instant();
assert!(instant2 > instant1);
}
}