use std::collections::HashMap;
use std::sync::Arc;
use std::time::Instant;
use tokio::sync::RwLock;
pub struct RateLimiter {
tokens: Arc<RwLock<f64>>,
capacity: f64,
refill_rate: f64,
last_refill: Arc<RwLock<Instant>>,
}
impl RateLimiter {
pub fn new(rate: f64, burst: usize) -> Self {
Self {
tokens: Arc::new(RwLock::new(burst as f64)),
capacity: burst as f64,
refill_rate: rate,
last_refill: Arc::new(RwLock::new(Instant::now())),
}
}
pub async fn check(&self) -> bool {
self.refill().await;
let tokens = self.tokens.read().await;
*tokens >= 1.0
}
pub async fn check_and_consume(&self) -> bool {
self.refill().await;
let mut tokens = self.tokens.write().await;
if *tokens >= 1.0 {
*tokens -= 1.0;
true
} else {
false
}
}
pub async fn available_tokens(&self) -> f64 {
self.refill().await;
*self.tokens.read().await
}
async fn refill(&self) {
let now = Instant::now();
let mut last_refill = self.last_refill.write().await;
let elapsed = now.duration_since(*last_refill).as_secs_f64();
if elapsed > 0.0 {
let tokens_to_add = elapsed * self.refill_rate;
let mut tokens = self.tokens.write().await;
*tokens = (*tokens + tokens_to_add).min(self.capacity);
*last_refill = now;
}
}
pub async fn reset(&self) {
let mut tokens = self.tokens.write().await;
*tokens = self.capacity;
let mut last_refill = self.last_refill.write().await;
*last_refill = Instant::now();
}
}
#[derive(Debug, Clone)]
pub struct RateLimit {
pub rate: f64,
pub burst: usize,
}
impl RateLimit {
pub fn new(rate: f64, burst: usize) -> Self {
Self { rate, burst }
}
pub fn per_second(rate: f64) -> Self {
Self {
rate,
burst: (rate * 2.0) as usize,
}
}
pub fn per_minute(rate: f64) -> Self {
let per_sec = rate / 60.0;
Self {
rate: per_sec,
burst: (per_sec * 2.0) as usize,
}
}
pub fn unlimited() -> Self {
Self {
rate: f64::MAX,
burst: usize::MAX,
}
}
}
pub struct MultiKeyRateLimiter {
limiters: Arc<RwLock<HashMap<String, RateLimiter>>>,
default_limit: RateLimit,
}
impl MultiKeyRateLimiter {
pub fn new() -> Self {
Self {
limiters: Arc::new(RwLock::new(HashMap::new())),
default_limit: RateLimit::unlimited(),
}
}
pub fn with_default(default: RateLimit) -> Self {
Self {
limiters: Arc::new(RwLock::new(HashMap::new())),
default_limit: default,
}
}
pub async fn set_limit(&self, key: impl Into<String>, limit: RateLimit) {
let key = key.into();
let limiter = RateLimiter::new(limit.rate, limit.burst);
let mut limiters = self.limiters.write().await;
limiters.insert(key, limiter);
}
pub async fn check(&self, key: &str) -> bool {
let limiters = self.limiters.read().await;
if let Some(limiter) = limiters.get(key) {
limiter.check().await
} else if self.default_limit.rate == f64::MAX {
true
} else {
drop(limiters);
self.set_limit(key, self.default_limit.clone()).await;
true
}
}
pub async fn check_and_consume(&self, key: &str) -> bool {
let should_create = {
let limiters = self.limiters.read().await;
!limiters.contains_key(key) && self.default_limit.rate != f64::MAX
};
if should_create {
self.set_limit(key, self.default_limit.clone()).await;
}
let limiters = self.limiters.read().await;
if let Some(limiter) = limiters.get(key) {
limiter.check_and_consume().await
} else {
true
}
}
pub async fn available_tokens(&self, key: &str) -> Option<f64> {
let limiters = self.limiters.read().await;
if let Some(limiter) = limiters.get(key) {
Some(limiter.available_tokens().await)
} else {
None
}
}
pub async fn clear(&self) {
let mut limiters = self.limiters.write().await;
limiters.clear();
}
}
impl Default for MultiKeyRateLimiter {
fn default() -> Self {
Self::new()
}
}
pub struct RateLimiterManager {
node_limiters: Arc<MultiKeyRateLimiter>,
}
impl RateLimiterManager {
pub fn new() -> Self {
Self {
node_limiters: Arc::new(MultiKeyRateLimiter::new()),
}
}
pub async fn check_node(&self, node_id: &str) -> bool {
self.node_limiters.check_and_consume(node_id).await
}
}
impl Default for RateLimiterManager {
fn default() -> Self {
Self::new()
}
}