AirLibrary/Downloader/
RateLimit.rs1use std::time::{Duration, Instant};
10
11use crate::Result;
12
13#[derive(Debug)]
16pub struct TokenBucket {
17 tokens:f64,
19
20 capacity:f64,
22
23 refill_rate:f64,
25
26 last_refill:Instant,
28}
29
30impl TokenBucket {
31 pub fn new(bytes_per_sec:u64, capacity_factor:f64) -> Self {
34 let refill_rate = bytes_per_sec as f64;
35
36 let capacity = refill_rate * capacity_factor;
37
38 Self { tokens:capacity, capacity, refill_rate, last_refill:Instant::now() }
39 }
40
41 pub fn refill(&mut self) {
43 let elapsed = self.last_refill.elapsed().as_secs_f64();
44
45 if elapsed > 0.0 {
46 self.tokens = (self.tokens + elapsed * self.refill_rate).min(self.capacity);
47
48 self.last_refill = Instant::now();
49 }
50 }
51
52 pub fn try_consume(&mut self, bytes:u64) -> u64 {
56 self.refill();
57
58 let bytes = bytes as f64;
59
60 if self.tokens >= bytes {
61 self.tokens -= bytes;
62
63 bytes as u64
64 } else {
65 let available = self.tokens;
66
67 self.tokens = 0.0;
68
69 available as u64
70 }
71 }
72
73 pub async fn consume(&mut self, bytes:u64) -> Result<()> {
76 let bytes_needed = bytes as f64;
77
78 loop {
79 self.refill();
80
81 if self.tokens >= bytes_needed {
82 self.tokens -= bytes_needed;
83
84 return Ok(());
85 }
86
87 let tokens_needed = bytes_needed - self.tokens;
88
89 let wait_secs = (tokens_needed / self.refill_rate).min(0.1);
90
91 tokio::time::sleep(Duration::from_secs_f64(wait_secs)).await;
92 }
93 }
94
95 pub fn set_rate(&mut self, bytes_per_sec:u64) {
97 self.refill_rate = bytes_per_sec as f64;
98
99 self.capacity = self.refill_rate * 5.0;
100 }
101}