Use the tokio runtime with std::sync::Mutex and std::collections::HashMap to track request timestamps per client. This approach blocks the async task briefly to check the limit, then allows the request to proceed if under the threshold.
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use std::time::{SystemTime, UNIX_EPOCH};
struct RateLimiter {
requests: Mutex<HashMap<String, Vec<u64>>>,
max_requests: usize,
window_seconds: u64,
}
impl RateLimiter {
fn new(max_requests: usize, window_seconds: u64) -> Self {
Self {
requests: Mutex::new(HashMap::new()),
max_requests,
window_seconds,
}
}
fn is_allowed(&self, client_id: &str) -> bool {
let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs();
let mut map = self.requests.lock().unwrap();
let entry = map.entry(client_id.to_string()).or_insert_with(Vec::new);
entry.retain(|&t| now - t < self.window_seconds);
let allowed = entry.len() < self.max_requests;
if allowed {
entry.push(now);
}
allowed
}
}
#[tokio::main]
async fn main() {
let limiter = Arc::new(RateLimiter::new(5, 60));
let client_id = "user_123";
if limiter.is_allowed(client_id) {
println!("Request allowed");
} else {
println!("Rate limit exceeded");
}
}