1use anyhow::Result;
35use serde::{Deserialize, Serialize};
36use std::collections::HashMap;
37use std::sync::Arc;
38use std::time::{Duration, SystemTime, UNIX_EPOCH};
39use tokio::sync::RwLock;
40
41#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
43pub enum RateLimitAlgorithm {
44 TokenBucket,
46 SlidingWindow,
48 FixedWindow,
50 Adaptive,
52}
53
54#[derive(Debug, Clone, Serialize, Deserialize)]
56pub struct RateLimitConfig {
57 pub algorithm: RateLimitAlgorithm,
59 pub max_requests: u32,
61 pub window_seconds: u64,
63 pub complexity_based: bool,
65 pub max_complexity: Option<u32>,
67 pub distributed: bool,
69 pub redis_url: Option<String>,
71 pub adaptive: bool,
73 pub adaptive_cpu_target: Option<f32>,
75 pub adaptive_memory_target: Option<f32>,
77}
78
79impl Default for RateLimitConfig {
80 fn default() -> Self {
81 Self {
82 algorithm: RateLimitAlgorithm::TokenBucket,
83 max_requests: 100,
84 window_seconds: 60,
85 complexity_based: true,
86 max_complexity: Some(10000),
87 distributed: false,
88 redis_url: None,
89 adaptive: false,
90 adaptive_cpu_target: Some(80.0),
91 adaptive_memory_target: Some(90.0),
92 }
93 }
94}
95
96#[derive(Debug, Clone, Serialize, Deserialize)]
98pub struct RateLimitPolicy {
99 pub client_id: String,
101 pub config: RateLimitConfig,
103 pub priority: u32,
105}
106
107impl RateLimitPolicy {
108 pub fn new(client_id: String, config: RateLimitConfig) -> Self {
109 Self {
110 client_id,
111 config,
112 priority: 0,
113 }
114 }
115
116 pub fn with_priority(mut self, priority: u32) -> Self {
117 self.priority = priority;
118 self
119 }
120}
121
122#[derive(Debug, Clone, Serialize, Deserialize)]
124struct TokenBucket {
125 tokens: f64,
127 capacity: f64,
129 refill_rate: f64,
131 last_refill: u64,
133}
134
135impl TokenBucket {
136 fn new(capacity: u32, refill_rate: f64) -> Self {
137 Self {
138 tokens: capacity as f64,
139 capacity: capacity as f64,
140 refill_rate,
141 last_refill: Self::now(),
142 }
143 }
144
145 fn now() -> u64 {
146 SystemTime::now()
147 .duration_since(UNIX_EPOCH)
148 .expect("SystemTime should be after UNIX_EPOCH")
149 .as_secs()
150 }
151
152 fn refill(&mut self) {
153 let now = Self::now();
154 let elapsed = now.saturating_sub(self.last_refill) as f64;
155 let new_tokens = elapsed * self.refill_rate;
156 self.tokens = (self.tokens + new_tokens).min(self.capacity);
157 self.last_refill = now;
158 }
159
160 fn consume(&mut self, tokens: f64) -> bool {
161 self.refill();
162 if self.tokens >= tokens {
163 self.tokens -= tokens;
164 true
165 } else {
166 false
167 }
168 }
169
170 fn available(&mut self) -> f64 {
171 self.refill();
172 self.tokens
173 }
174}
175
176#[derive(Debug, Clone, Serialize, Deserialize)]
178struct SlidingWindowCounter {
179 current_window: u64,
181 current_count: u32,
183 previous_count: u32,
185 window_duration: u64,
187}
188
189impl SlidingWindowCounter {
190 fn new(window_duration: u64) -> Self {
191 Self {
192 current_window: Self::current_window(window_duration),
193 current_count: 0,
194 previous_count: 0,
195 window_duration,
196 }
197 }
198
199 fn current_window(window_duration: u64) -> u64 {
200 SystemTime::now()
201 .duration_since(UNIX_EPOCH)
202 .expect("SystemTime should be after UNIX_EPOCH")
203 .as_secs()
204 / window_duration
205 }
206
207 fn now_seconds() -> u64 {
208 SystemTime::now()
209 .duration_since(UNIX_EPOCH)
210 .expect("SystemTime should be after UNIX_EPOCH")
211 .as_secs()
212 }
213
214 fn increment(&mut self, amount: u32) {
215 let now_window = Self::current_window(self.window_duration);
216
217 if now_window > self.current_window + 1 {
218 self.previous_count = 0;
220 self.current_count = amount;
221 self.current_window = now_window;
222 } else if now_window > self.current_window {
223 self.previous_count = self.current_count;
225 self.current_count = amount;
226 self.current_window = now_window;
227 } else {
228 self.current_count += amount;
230 }
231 }
232
233 fn count(&self, max_requests: u32) -> Result<(), String> {
234 let now_window = Self::current_window(self.window_duration);
235
236 if now_window > self.current_window + 1 {
237 return Ok(());
239 }
240
241 if now_window > self.current_window {
242 let now = Self::now_seconds();
244 let window_progress = (now % self.window_duration) as f64 / self.window_duration as f64;
245 let weighted_count =
246 (self.previous_count as f64 * (1.0 - window_progress)) + self.current_count as f64;
247
248 if weighted_count >= max_requests as f64 {
249 return Err(format!(
250 "Rate limit exceeded: {:.0}/{} requests in sliding window",
251 weighted_count, max_requests
252 ));
253 }
254 } else {
255 if self.current_count >= max_requests {
257 return Err(format!(
258 "Rate limit exceeded: {}/{} requests in window",
259 self.current_count, max_requests
260 ));
261 }
262 }
263
264 Ok(())
265 }
266}
267
268#[derive(Debug, Clone, Serialize, Deserialize)]
270struct FixedWindowCounter {
271 window_start: u64,
273 count: u32,
275 window_duration: u64,
277}
278
279impl FixedWindowCounter {
280 fn new(window_duration: u64) -> Self {
281 Self {
282 window_start: Self::now(),
283 count: 0,
284 window_duration,
285 }
286 }
287
288 fn now() -> u64 {
289 SystemTime::now()
290 .duration_since(UNIX_EPOCH)
291 .expect("SystemTime should be after UNIX_EPOCH")
292 .as_secs()
293 }
294
295 fn increment(&mut self, amount: u32) {
296 let now = Self::now();
297
298 if now >= self.window_start + self.window_duration {
299 self.window_start = now;
301 self.count = amount;
302 } else {
303 self.count += amount;
305 }
306 }
307
308 fn check(&self, max_requests: u32) -> Result<(), String> {
309 let now = Self::now();
310
311 if now >= self.window_start + self.window_duration {
312 Ok(())
314 } else if self.count >= max_requests {
315 Err(format!(
316 "Rate limit exceeded: {}/{} requests in window",
317 self.count, max_requests
318 ))
319 } else {
320 Ok(())
321 }
322 }
323}
324
325#[derive(Debug, Clone, Serialize, Deserialize)]
327enum RateLimitState {
328 TokenBucket(TokenBucket),
329 SlidingWindow(SlidingWindowCounter),
330 FixedWindow(FixedWindowCounter),
331}
332
333#[derive(Debug, Clone, Serialize, Deserialize)]
335pub struct RateLimitResult {
336 pub allowed: bool,
338 pub limit: u32,
340 pub remaining: u32,
342 pub reset_after: u64,
344 pub retry_after: Option<u64>,
346}
347
348pub struct RateLimiter {
350 config: Arc<RateLimitConfig>,
352 states: Arc<RwLock<HashMap<String, RateLimitState>>>,
354 policies: Arc<RwLock<HashMap<String, RateLimitPolicy>>>,
356 load_monitor: Arc<RwLock<SystemLoad>>,
358}
359
360#[derive(Debug, Clone)]
361struct SystemLoad {
362 cpu_usage: f32,
363 memory_usage: f32,
364 last_update: std::time::Instant,
365}
366
367impl SystemLoad {
368 fn new() -> Self {
369 Self {
370 cpu_usage: 0.0,
371 memory_usage: 0.0,
372 last_update: std::time::Instant::now(),
373 }
374 }
375
376 fn update(&mut self) {
377 if self.last_update.elapsed() < Duration::from_secs(5) {
379 return;
380 }
381
382 use sysinfo::{CpuRefreshKind, MemoryRefreshKind, RefreshKind, System};
383
384 let mut sys = System::new_with_specifics(
385 RefreshKind::nothing()
386 .with_cpu(CpuRefreshKind::everything())
387 .with_memory(MemoryRefreshKind::everything()),
388 );
389 sys.refresh_all();
390
391 let cpus = sys.cpus();
393 if !cpus.is_empty() {
394 self.cpu_usage =
395 cpus.iter().map(|cpu| cpu.cpu_usage()).sum::<f32>() / cpus.len() as f32;
396 }
397
398 self.memory_usage = (sys.used_memory() as f64 / sys.total_memory() as f64 * 100.0) as f32;
399 self.last_update = std::time::Instant::now();
400 }
401
402 fn should_reduce_limits(&self, cpu_target: f32, memory_target: f32) -> bool {
403 self.cpu_usage > cpu_target || self.memory_usage > memory_target
404 }
405}
406
407impl RateLimiter {
408 pub fn new(config: RateLimitConfig) -> Self {
410 Self {
411 config: Arc::new(config),
412 states: Arc::new(RwLock::new(HashMap::new())),
413 policies: Arc::new(RwLock::new(HashMap::new())),
414 load_monitor: Arc::new(RwLock::new(SystemLoad::new())),
415 }
416 }
417
418 pub async fn add_policy(&self, policy: RateLimitPolicy) -> Result<()> {
420 let mut policies = self.policies.write().await;
421 policies.insert(policy.client_id.clone(), policy);
422 Ok(())
423 }
424
425 pub async fn remove_policy(&self, client_id: &str) -> Result<()> {
427 let mut policies = self.policies.write().await;
428 policies.remove(client_id);
429 Ok(())
430 }
431
432 pub async fn check_rate_limit(
434 &self,
435 client_id: &str,
436 cost: Option<u32>,
437 ) -> Result<RateLimitResult> {
438 let effective_config = {
440 let policies = self.policies.read().await;
441 policies
442 .get(client_id)
443 .map(|p| p.config.clone())
444 .unwrap_or_else(|| (*self.config).clone())
445 };
446
447 if effective_config.adaptive {
449 let mut load_monitor = self.load_monitor.write().await;
450 load_monitor.update();
451
452 if load_monitor.should_reduce_limits(
453 effective_config.adaptive_cpu_target.unwrap_or(80.0),
454 effective_config.adaptive_memory_target.unwrap_or(90.0),
455 ) {
456 return Ok(RateLimitResult {
458 allowed: false,
459 limit: effective_config.max_requests,
460 remaining: 0,
461 reset_after: effective_config.window_seconds,
462 retry_after: Some(5),
463 });
464 }
465 }
466
467 let request_cost = if effective_config.complexity_based {
468 cost.unwrap_or(1)
469 } else {
470 1
471 };
472
473 let mut states = self.states.write().await;
474 let state = states
475 .entry(client_id.to_string())
476 .or_insert_with(|| Self::create_state(&effective_config));
477
478 match state {
479 RateLimitState::TokenBucket(bucket) => {
480 let allowed = bucket.consume(request_cost as f64);
481 let remaining = bucket.available() as u32;
482
483 Ok(RateLimitResult {
484 allowed,
485 limit: effective_config.max_requests,
486 remaining,
487 reset_after: effective_config.window_seconds,
488 retry_after: if !allowed { Some(1) } else { None },
489 })
490 }
491 RateLimitState::SlidingWindow(counter) => {
492 let check_result = counter.count(effective_config.max_requests);
493
494 if check_result.is_ok() {
495 counter.increment(request_cost);
496 Ok(RateLimitResult {
497 allowed: true,
498 limit: effective_config.max_requests,
499 remaining: effective_config
500 .max_requests
501 .saturating_sub(counter.current_count),
502 reset_after: effective_config.window_seconds,
503 retry_after: None,
504 })
505 } else {
506 Ok(RateLimitResult {
507 allowed: false,
508 limit: effective_config.max_requests,
509 remaining: 0,
510 reset_after: effective_config.window_seconds,
511 retry_after: Some(effective_config.window_seconds),
512 })
513 }
514 }
515 RateLimitState::FixedWindow(counter) => {
516 let check_result = counter.check(effective_config.max_requests);
517
518 if check_result.is_ok() {
519 counter.increment(request_cost);
520 Ok(RateLimitResult {
521 allowed: true,
522 limit: effective_config.max_requests,
523 remaining: effective_config.max_requests.saturating_sub(counter.count),
524 reset_after: effective_config.window_seconds,
525 retry_after: None,
526 })
527 } else {
528 Ok(RateLimitResult {
529 allowed: false,
530 limit: effective_config.max_requests,
531 remaining: 0,
532 reset_after: effective_config.window_seconds,
533 retry_after: Some(effective_config.window_seconds),
534 })
535 }
536 }
537 }
538 }
539
540 pub async fn reset_client(&self, client_id: &str) -> Result<()> {
542 let mut states = self.states.write().await;
543 states.remove(client_id);
544 Ok(())
545 }
546
547 pub async fn get_statistics(&self) -> HashMap<String, String> {
549 let states = self.states.read().await;
550 states
551 .iter()
552 .map(|(id, state)| {
553 let info = match state {
554 RateLimitState::TokenBucket(b) => {
555 format!("TokenBucket(tokens: {:.2})", b.tokens)
556 }
557 RateLimitState::SlidingWindow(c) => {
558 format!("SlidingWindow(current: {})", c.current_count)
559 }
560 RateLimitState::FixedWindow(c) => {
561 format!("FixedWindow(count: {})", c.count)
562 }
563 };
564 (id.clone(), info)
565 })
566 .collect()
567 }
568
569 fn create_state(config: &RateLimitConfig) -> RateLimitState {
570 match config.algorithm {
571 RateLimitAlgorithm::TokenBucket => {
572 let refill_rate = config.max_requests as f64 / config.window_seconds as f64;
573 RateLimitState::TokenBucket(TokenBucket::new(config.max_requests, refill_rate))
574 }
575 RateLimitAlgorithm::SlidingWindow => {
576 RateLimitState::SlidingWindow(SlidingWindowCounter::new(config.window_seconds))
577 }
578 RateLimitAlgorithm::FixedWindow | RateLimitAlgorithm::Adaptive => {
579 RateLimitState::FixedWindow(FixedWindowCounter::new(config.window_seconds))
580 }
581 }
582 }
583}
584
585#[cfg(test)]
586mod tests {
587 use super::*;
588
589 #[tokio::test]
590 async fn test_rate_limit_config_default() {
591 let config = RateLimitConfig::default();
592 assert_eq!(config.algorithm, RateLimitAlgorithm::TokenBucket);
593 assert_eq!(config.max_requests, 100);
594 assert_eq!(config.window_seconds, 60);
595 assert!(config.complexity_based);
596 }
597
598 #[tokio::test]
599 async fn test_token_bucket_creation() {
600 let bucket = TokenBucket::new(100, 10.0);
601 assert_eq!(bucket.capacity, 100.0);
602 assert_eq!(bucket.refill_rate, 10.0);
603 }
604
605 #[tokio::test]
606 async fn test_token_bucket_consume() {
607 let mut bucket = TokenBucket::new(100, 10.0);
608 assert!(bucket.consume(50.0));
609 assert!(bucket.tokens < 51.0 && bucket.tokens > 49.0);
610 }
611
612 #[tokio::test]
613 async fn test_sliding_window_counter() {
614 let mut counter = SlidingWindowCounter::new(60);
615 counter.increment(10);
616 assert_eq!(counter.current_count, 10);
617 }
618
619 #[tokio::test]
620 async fn test_fixed_window_counter() {
621 let mut counter = FixedWindowCounter::new(60);
622 counter.increment(10);
623 assert_eq!(counter.count, 10);
624
625 let result = counter.check(100);
626 assert!(result.is_ok());
627 }
628
629 #[tokio::test]
630 async fn test_rate_limiter_creation() {
631 let config = RateLimitConfig::default();
632 let _limiter = RateLimiter::new(config);
633 }
634
635 #[tokio::test]
636 async fn test_rate_limiter_check_allowed() {
637 let config = RateLimitConfig {
638 max_requests: 10,
639 ..Default::default()
640 };
641 let limiter = RateLimiter::new(config);
642
643 let result = limiter.check_rate_limit("client1", Some(1)).await;
644 assert!(result.is_ok());
645 let result = result.expect("should succeed");
646 assert!(result.allowed);
647 }
648
649 #[tokio::test]
650 async fn test_rate_limiter_check_exceeded() {
651 let config = RateLimitConfig {
652 algorithm: RateLimitAlgorithm::FixedWindow,
653 max_requests: 5,
654 window_seconds: 60,
655 ..Default::default()
656 };
657 let limiter = RateLimiter::new(config);
658
659 for _ in 0..5 {
661 let result = limiter
662 .check_rate_limit("client1", Some(1))
663 .await
664 .expect("should succeed");
665 assert!(result.allowed);
666 }
667
668 let result = limiter
670 .check_rate_limit("client1", Some(1))
671 .await
672 .expect("should succeed");
673 assert!(!result.allowed);
674 assert!(result.retry_after.is_some());
675 }
676
677 #[tokio::test]
678 async fn test_rate_limiter_custom_policy() {
679 let default_config = RateLimitConfig {
680 max_requests: 10,
681 ..Default::default()
682 };
683 let limiter = RateLimiter::new(default_config);
684
685 let vip_policy = RateLimitPolicy::new(
687 "vip_client".to_string(),
688 RateLimitConfig {
689 max_requests: 1000,
690 ..RateLimitConfig::default()
691 },
692 );
693 limiter
694 .add_policy(vip_policy)
695 .await
696 .expect("should succeed");
697
698 let result = limiter
700 .check_rate_limit("vip_client", Some(1))
701 .await
702 .expect("should succeed");
703 assert!(result.allowed);
704 assert_eq!(result.limit, 1000);
705 }
706
707 #[tokio::test]
708 async fn test_complexity_based_limiting() {
709 let config = RateLimitConfig {
710 complexity_based: true,
711 max_requests: 100,
712 max_complexity: Some(1000),
713 ..Default::default()
714 };
715 let limiter = RateLimiter::new(config);
716
717 let result = limiter
719 .check_rate_limit("client1", Some(50))
720 .await
721 .expect("should succeed");
722 assert!(result.allowed);
723 }
724
725 #[tokio::test]
726 async fn test_rate_limiter_reset() {
727 let config = RateLimitConfig {
728 algorithm: RateLimitAlgorithm::FixedWindow,
729 max_requests: 5,
730 ..Default::default()
731 };
732 let limiter = RateLimiter::new(config);
733
734 for _ in 0..5 {
736 let _ = limiter.check_rate_limit("client1", Some(1)).await;
737 }
738
739 let result = limiter
741 .check_rate_limit("client1", Some(1))
742 .await
743 .expect("should succeed");
744 assert!(!result.allowed);
745
746 limiter
748 .reset_client("client1")
749 .await
750 .expect("should succeed");
751
752 let result = limiter
754 .check_rate_limit("client1", Some(1))
755 .await
756 .expect("should succeed");
757 assert!(result.allowed);
758 }
759}