1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
//! Rate limiting with a pluggable backend and algorithm.
//!
//! A [`RateLimiter`] records requests against a string key and reports whether
//! each is [`Allowed`](RateLimitOutcome::Allowed) or
//! [`Limited`](RateLimitOutcome::Limited), permitting up to `max` per `window`.
//! All implementations share that `(max, window)` API, so they're
//! interchangeable behind `Arc<dyn RateLimiter>`.
//!
//! **Fixed-window** (hard reset each window):
//!
//! * [`InMemoryRateLimiter`] — a clock-injected `Mutex<HashMap>`, per-process
//! (each replica counts independently). Ideal for single-node deployments and
//! tests (drive it with a `FixedClock`).
//! * [`RedisRateLimiter`] (`redis` feature) — a shared counter in Redis, so a
//! fleet of replicas enforces one global budget per key.
//!
//! **Token-bucket** (continuous refill — smooths traffic, allows short bursts up
//! to `max`): [`InMemoryTokenBucket`] and [`RedisTokenBucket`] (`redis`),
//! with the same `(max, window)` parameters (`max` = burst capacity, refilled at
//! `max / window`).
//!
//! ```
//! use std::sync::Arc;
//! use std::time::Duration;
//! use klauthed_core::time::FixedClock;
//! use klauthed_data::rate_limit::{InMemoryRateLimiter, RateLimiter, RateLimitOutcome};
//!
//! # #[tokio::main]
//! # async fn main() -> Result<(), klauthed_data::DataError> {
//! let clock = Arc::new(FixedClock::at_unix_millis(0));
//! let limiter = InMemoryRateLimiter::new(clock.clone());
//! let window = Duration::from_secs(60);
//!
//! // First request of two is allowed.
//! assert!(matches!(limiter.check("ip:1.2.3.4", 2, window).await?, RateLimitOutcome::Allowed { .. }));
//! limiter.check("ip:1.2.3.4", 2, window).await?; // second
//! // Third exceeds the budget.
//! assert!(matches!(limiter.check("ip:1.2.3.4", 2, window).await?, RateLimitOutcome::Limited { .. }));
//! # Ok(())
//! # }
//! ```
use Duration;
use async_trait;
use crateDataError;
pub use ;
pub use ;
/// The result of recording one request against a key in its current window.
/// A fixed-window rate limiter keyed by an arbitrary string.
///
/// Implementations are `Send + Sync` so a limiter can be shared as
/// `Arc<dyn RateLimiter>` across worker threads.