bybit_rust_api/utils/
rate_limiter.rs1use std::sync::Arc;
11use std::time::{Duration, Instant};
12use tokio::sync::Mutex;
13
14#[derive(Clone)]
19pub struct RateLimiter {
20 inner: Arc<Mutex<Bucket>>,
21}
22
23struct Bucket {
24 tokens: f64,
25 capacity: f64,
26 refill_rate: f64, last_refill: Instant,
28}
29
30impl RateLimiter {
31 pub fn new(rate: u32, burst: Option<u32>) -> Self {
37 let burst = burst.unwrap_or(rate);
38 RateLimiter {
39 inner: Arc::new(Mutex::new(Bucket {
40 tokens: burst as f64,
41 capacity: burst as f64,
42 refill_rate: rate as f64,
43 last_refill: Instant::now(),
44 })),
45 }
46 }
47
48 pub async fn acquire(&self) {
53 let wait = {
54 let mut bucket = self.inner.lock().await;
55 bucket.refill();
56 if bucket.tokens >= 1.0 {
57 bucket.tokens -= 1.0;
58 None
59 } else {
60 let needed = 1.0 - bucket.tokens;
62 let wait_secs = needed / bucket.refill_rate;
63 Some(Duration::from_secs_f64(wait_secs))
64 }
65 };
66
67 if let Some(duration) = wait {
68 tokio::time::sleep(duration).await;
69 let mut bucket = self.inner.lock().await;
71 bucket.refill();
72 if bucket.tokens >= 1.0 {
73 bucket.tokens -= 1.0;
74 }
75 }
76 }
77
78 pub async fn try_acquire(&self) -> bool {
82 let mut bucket = self.inner.lock().await;
83 bucket.refill();
84 if bucket.tokens >= 1.0 {
85 bucket.tokens -= 1.0;
86 true
87 } else {
88 false
89 }
90 }
91
92 pub async fn available(&self) -> f64 {
94 let mut bucket = self.inner.lock().await;
95 bucket.refill();
96 bucket.tokens
97 }
98
99 pub fn public_rest() -> Self {
101 RateLimiter::new(50, Some(50))
102 }
103
104 pub fn private_rest() -> Self {
106 RateLimiter::new(50, Some(50))
107 }
108
109 pub fn ws_order_entry() -> Self {
111 RateLimiter::new(20, Some(20))
112 }
113}
114
115impl Bucket {
116 fn refill(&mut self) {
117 let now = Instant::now();
118 let elapsed = now.duration_since(self.last_refill).as_secs_f64();
119 self.tokens = (self.tokens + elapsed * self.refill_rate).min(self.capacity);
120 self.last_refill = now;
121 }
122}
123
124#[cfg(test)]
125mod tests {
126 use super::*;
127
128 #[tokio::test]
129 async fn test_initial_tokens_available() {
130 let limiter = RateLimiter::new(10, Some(10));
131 let available = limiter.available().await;
132 assert!(available > 9.0);
133 }
134
135 #[tokio::test]
136 async fn test_acquire_consumes_token() {
137 let limiter = RateLimiter::new(10, Some(10));
138 let before = limiter.available().await;
139 limiter.acquire().await;
140 let after = limiter.available().await;
141 assert!(after < before);
142 }
143
144 #[tokio::test]
145 async fn test_try_acquire() {
146 let limiter = RateLimiter::new(100, Some(100));
147 assert!(limiter.try_acquire().await);
148 assert!(limiter.try_acquire().await);
149 }
150
151 #[tokio::test]
152 async fn test_burst_behavior() {
153 let limiter = RateLimiter::new(100, Some(5));
154 for _ in 0..5 {
156 assert!(limiter.try_acquire().await);
157 }
158 assert!(!limiter.try_acquire().await);
160 }
161
162 #[test]
163 fn test_default_constructors() {
164 let _public = RateLimiter::public_rest();
165 let _private = RateLimiter::private_rest();
166 let _ws = RateLimiter::ws_order_entry();
167 }
168}