@@ -12,61 +12,6 @@ use tokio::sync::RwLock;
1212use tokio:: time:: interval;
1313use tracing:: { debug, warn} ;
1414
15- /// Time provider trait for mocking in tests
16- #[ cfg( test) ]
17- pub trait TimeProvider {
18- fn now ( & self ) -> Instant ;
19- fn advance ( & mut self , duration : Duration ) ;
20- }
21-
22- /// Real time provider for production
23- #[ cfg( test) ]
24- pub struct RealTimeProvider ;
25-
26- #[ cfg( test) ]
27- impl TimeProvider for RealTimeProvider {
28- fn now ( & self ) -> Instant {
29- Instant :: now ( )
30- }
31-
32- fn advance ( & mut self , _duration : Duration ) {
33- // No-op for real time
34- }
35- }
36-
37- /// Mock time provider for tests
38- #[ cfg( test) ]
39- pub struct MockTimeProvider {
40- current_time : Instant ,
41- }
42-
43- #[ cfg( test) ]
44- impl MockTimeProvider {
45- pub fn new ( ) -> Self {
46- Self {
47- current_time : Instant :: now ( ) ,
48- }
49- }
50- }
51-
52- #[ cfg( test) ]
53- impl Default for MockTimeProvider {
54- fn default ( ) -> Self {
55- Self :: new ( )
56- }
57- }
58-
59- #[ cfg( test) ]
60- impl TimeProvider for MockTimeProvider {
61- fn now ( & self ) -> Instant {
62- self . current_time
63- }
64-
65- fn advance ( & mut self , duration : Duration ) {
66- self . current_time += duration;
67- }
68- }
69-
7015/// Configuration for rate limiting
7116#[ derive( Clone , Debug ) ]
7217pub struct RateLimitConfig {
@@ -92,16 +37,6 @@ impl Default for RateLimitConfig {
9237}
9338
9439/// Token bucket for rate limiting
95- #[ cfg( test) ]
96- pub struct TokenBucket {
97- tokens : AtomicU32 ,
98- max_tokens : u32 ,
99- refill_rate : u32 , // tokens per refill interval
100- last_refill : RwLock < Instant > ,
101- time_provider : Arc < RwLock < Box < dyn TimeProvider + Send + Sync > > > ,
102- }
103-
104- #[ cfg( not( test) ) ]
10540struct TokenBucket {
10641 tokens : AtomicU32 ,
10742 max_tokens : u32 ,
@@ -128,7 +63,6 @@ impl std::fmt::Debug for TokenBucket {
12863}
12964
13065impl TokenBucket {
131- #[ cfg( not( test) ) ]
13266 fn new ( max_tokens : u32 , refill_rate : u32 ) -> Self {
13367 Self {
13468 tokens : AtomicU32 :: new ( max_tokens) ,
@@ -138,34 +72,7 @@ impl TokenBucket {
13872 }
13973 }
14074
141- #[ cfg( test) ]
142- pub fn new ( max_tokens : u32 , refill_rate : u32 ) -> Self {
143- Self {
144- tokens : AtomicU32 :: new ( max_tokens) ,
145- max_tokens,
146- refill_rate,
147- last_refill : RwLock :: new ( Instant :: now ( ) ) ,
148- time_provider : Arc :: new ( RwLock :: new ( Box :: new ( RealTimeProvider ) ) ) ,
149- }
150- }
151-
152- #[ cfg( test) ]
153- pub fn new_with_time_provider (
154- max_tokens : u32 ,
155- refill_rate : u32 ,
156- time_provider : Box < dyn TimeProvider + Send + Sync > ,
157- ) -> Self {
158- Self {
159- tokens : AtomicU32 :: new ( max_tokens) ,
160- max_tokens,
161- refill_rate,
162- last_refill : RwLock :: new ( Instant :: now ( ) ) ,
163- time_provider : Arc :: new ( RwLock :: new ( time_provider) ) ,
164- }
165- }
166-
16775 /// Try to consume a token. Returns true if successful, false if rate limited.
168- #[ cfg( not( test) ) ]
16976 async fn try_consume ( & self ) -> bool {
17077 self . refill ( ) . await ;
17178
@@ -192,35 +99,7 @@ impl TokenBucket {
19299 }
193100 }
194101
195- #[ cfg( test) ]
196- pub async fn try_consume ( & self ) -> bool {
197- self . refill ( ) . await ;
198-
199- // Use a loop instead of recursion to avoid boxing
200- loop {
201- let current_tokens = self . tokens . load ( Ordering :: Acquire ) ;
202- if current_tokens > 0 {
203- // Try to decrement atomically
204- match self . tokens . compare_exchange_weak (
205- current_tokens,
206- current_tokens - 1 ,
207- Ordering :: Release ,
208- Ordering :: Relaxed ,
209- ) {
210- Ok ( _) => return true ,
211- Err ( _) => {
212- // Someone else consumed the token, try again
213- continue ;
214- }
215- }
216- } else {
217- return false ;
218- }
219- }
220- }
221-
222102 /// Refill tokens based on elapsed time
223- #[ cfg( not( test) ) ]
224103 async fn refill ( & self ) {
225104 let now = Instant :: now ( ) ;
226105
@@ -248,51 +127,10 @@ impl TokenBucket {
248127 }
249128 }
250129
251- #[ cfg( test) ]
252- pub async fn refill ( & self ) {
253- #[ cfg( test) ]
254- let now = {
255- let time_provider = self . time_provider . read ( ) . await ;
256- time_provider. now ( )
257- } ;
258- #[ cfg( not( test) ) ]
259- let now = Instant :: now ( ) ;
260-
261- let mut last_refill = self . last_refill . write ( ) . await ;
262-
263- let elapsed = now. duration_since ( * last_refill) ;
264- if elapsed >= Duration :: from_secs ( 1 ) {
265- let seconds_passed = elapsed. as_secs ( ) as u32 ;
266- let tokens_to_add = seconds_passed * self . refill_rate ;
267-
268- if tokens_to_add > 0 {
269- let current_tokens = self . tokens . load ( Ordering :: Acquire ) ;
270- let new_tokens = ( current_tokens + tokens_to_add) . min ( self . max_tokens ) ;
271- self . tokens . store ( new_tokens, Ordering :: Release ) ;
272- * last_refill = now;
273-
274- // Only log if we actually added tokens and it's significant
275- if tokens_to_add > 0 && current_tokens < self . max_tokens / 2 {
276- debug ! (
277- "Refilled {} tokens, current: {}/{}" ,
278- tokens_to_add, new_tokens, self . max_tokens
279- ) ;
280- }
281- }
282- }
283- }
284-
285130 /// Get current token count (for monitoring)
286131 fn current_tokens ( & self ) -> u32 {
287132 self . tokens . load ( Ordering :: Acquire )
288133 }
289-
290- #[ cfg( test) ]
291- /// Advance time for testing
292- pub async fn advance_time ( & self , duration : Duration ) {
293- let mut time_provider = self . time_provider . write ( ) . await ;
294- time_provider. advance ( duration) ;
295- }
296134}
297135
298136/// Rate limiter with global and per-IP limits
0 commit comments