use dashmap::DashMap;
use dashmap::Entry;
use std::hash::Hash;
use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::sync::Mutex;
use tokio::task::yield_now;
use tokio::time::sleep;
#[derive(Clone)]
pub struct RateLimiter {
rate: u64,
interval: Duration,
state: Arc<Mutex<Inner>>,
}
struct Inner {
count: u64,
last_reset: Instant,
}
impl RateLimiter {
pub fn new_rate(rate: u64) -> Self {
Self::new_rate_interval(rate, Duration::from_secs(1))
}
pub fn new_rate_interval(rate: u64, interval: Duration) -> Self {
RateLimiter {
rate,
interval,
state: Arc::new(Mutex::new(Inner {
count: 0,
last_reset: Instant::now(),
})),
}
}
pub async fn check(&self) -> bool {
let mut state = self.state.lock().await;
let now = Instant::now();
if now >= state.last_reset + self.interval {
state.count = 0;
state.last_reset = now;
}
if state.count < self.rate {
state.count += 1;
true
} else {
false
}
}
pub async fn time_until_available(&self) -> Duration {
if self.rate == 0 {
return Duration::MAX;
}
let state = self.state.lock().await;
let now = Instant::now();
let window_end = state.last_reset + self.interval;
if now >= window_end || state.count < self.rate {
Duration::ZERO
} else {
window_end - now
}
}
pub async fn wait(&self) {
loop {
let mut state = self.state.lock().await;
let now = Instant::now();
if now >= state.last_reset + self.interval {
state.count = 0;
state.last_reset = now;
}
if state.count < self.rate {
state.count += 1;
return;
}
let wait = (state.last_reset + self.interval).saturating_duration_since(now);
drop(state);
if wait > Duration::ZERO {
sleep(wait).await;
} else {
yield_now().await;
}
}
}
}
#[derive(Clone)]
pub struct RateLimiterMap<K> {
map: Arc<DashMap<K, RateLimiter>>,
}
impl<K> RateLimiterMap<K>
where
K: Hash + Eq + Clone + Send + Sync + 'static,
{
pub fn new() -> Self {
RateLimiterMap {
map: Arc::new(DashMap::new()),
}
}
pub fn insert_rate(&self, key: K, rate: u64) {
self.insert_rate_interval(key, rate, Duration::from_secs(1))
}
pub fn insert_rate_interval(&self, key: K, rate: u64, interval: Duration) {
let limiter = RateLimiter::new_rate_interval(rate, interval);
self.map.insert(key, limiter);
}
pub fn remove(&self, key: &K) {
self.map.remove(key);
}
pub fn len(&self) -> usize {
self.map.len()
}
pub fn is_empty(&self) -> bool {
self.map.is_empty()
}
pub fn contains_key(&self, key: &K) -> bool {
self.map.contains_key(key)
}
pub fn clear(&self) {
self.map.clear();
}
pub fn retain(&self, f: impl FnMut(&K, &mut RateLimiter) -> bool) {
self.map.retain(f);
}
pub fn entry(&self, key: K) -> Entry<'_, K, RateLimiter> {
self.map.entry(key)
}
pub async fn check(&self, key: &K) -> bool {
match self.map.get(key).map(|r| r.clone()) {
Some(limiter) => limiter.check().await,
None => false,
}
}
pub async fn check_opt(&self, key: &K) -> Option<bool> {
match self.map.get(key).map(|r| r.clone()) {
Some(limiter) => Some(limiter.check().await),
None => None,
}
}
pub async fn time_until_available(&self, key: &K) -> Duration {
match self.map.get(key).map(|r| r.clone()) {
Some(limiter) => limiter.time_until_available().await,
None => Duration::MAX,
}
}
pub async fn wait(&self, key: &K) {
if let Some(limiter) = self.map.get(key).map(|r| r.clone()) {
limiter.wait().await;
}
}
}