rust_serv/throttle/
config.rs1use std::time::Duration;
4
5#[derive(Debug, Clone)]
7pub struct ThrottleConfig {
8 pub global_limit: u64,
10 pub per_ip_limit: u64,
12 pub bucket_capacity: u64,
14 pub refill_interval: Duration,
16 pub enabled: bool,
18}
19
20impl ThrottleConfig {
21 pub fn new() -> Self {
23 Self {
24 global_limit: 0,
25 per_ip_limit: 0,
26 bucket_capacity: 64 * 1024, refill_interval: Duration::from_millis(100),
28 enabled: false,
29 }
30 }
31
32 pub fn with_global_limit(mut self, limit: u64) -> Self {
34 self.global_limit = limit;
35 self
36 }
37
38 pub fn with_per_ip_limit(mut self, limit: u64) -> Self {
40 self.per_ip_limit = limit;
41 self
42 }
43
44 pub fn with_bucket_capacity(mut self, capacity: u64) -> Self {
46 self.bucket_capacity = capacity;
47 self
48 }
49
50 pub fn with_refill_interval(mut self, interval: Duration) -> Self {
52 self.refill_interval = interval;
53 self
54 }
55
56 pub fn enable(mut self) -> Self {
58 self.enabled = true;
59 self
60 }
61
62 pub fn disable(mut self) -> Self {
64 self.enabled = false;
65 self
66 }
67
68 pub fn has_global_limit(&self) -> bool {
70 self.enabled && self.global_limit > 0
71 }
72
73 pub fn has_per_ip_limit(&self) -> bool {
75 self.enabled && self.per_ip_limit > 0
76 }
77
78 pub fn is_active(&self) -> bool {
80 self.enabled && (self.global_limit > 0 || self.per_ip_limit > 0)
81 }
82
83 pub fn tokens_per_interval(&self, limit: u64) -> u64 {
85 let intervals_per_sec = 1000 / self.refill_interval.as_millis() as u64;
86 limit / intervals_per_sec
87 }
88
89 pub fn format_limit(bytes_per_sec: u64) -> String {
91 if bytes_per_sec == 0 {
92 return "unlimited".to_string();
93 }
94
95 const KB: u64 = 1024;
96 const MB: u64 = 1024 * KB;
97 const GB: u64 = 1024 * MB;
98
99 if bytes_per_sec >= GB {
100 format!("{:.1} GB/s", bytes_per_sec as f64 / GB as f64)
101 } else if bytes_per_sec >= MB {
102 format!("{:.1} MB/s", bytes_per_sec as f64 / MB as f64)
103 } else if bytes_per_sec >= KB {
104 format!("{:.1} KB/s", bytes_per_sec as f64 / KB as f64)
105 } else {
106 format!("{} B/s", bytes_per_sec)
107 }
108 }
109}
110
111impl Default for ThrottleConfig {
112 fn default() -> Self {
113 Self::new()
114 }
115}
116
117#[cfg(test)]
118mod tests {
119 use super::*;
120
121 #[test]
122 fn test_config_creation() {
123 let config = ThrottleConfig::new();
124 assert_eq!(config.global_limit, 0);
125 assert_eq!(config.per_ip_limit, 0);
126 assert!(!config.enabled);
127 }
128
129 #[test]
130 fn test_config_with_global_limit() {
131 let config = ThrottleConfig::new()
132 .with_global_limit(1024 * 1024); assert_eq!(config.global_limit, 1024 * 1024);
135 }
136
137 #[test]
138 fn test_config_with_per_ip_limit() {
139 let config = ThrottleConfig::new()
140 .with_per_ip_limit(512 * 1024); assert_eq!(config.per_ip_limit, 512 * 1024);
143 }
144
145 #[test]
146 fn test_config_with_bucket_capacity() {
147 let config = ThrottleConfig::new()
148 .with_bucket_capacity(128 * 1024);
149
150 assert_eq!(config.bucket_capacity, 128 * 1024);
151 }
152
153 #[test]
154 fn test_config_with_refill_interval() {
155 let config = ThrottleConfig::new()
156 .with_refill_interval(Duration::from_millis(50));
157
158 assert_eq!(config.refill_interval, Duration::from_millis(50));
159 }
160
161 #[test]
162 fn test_config_enable() {
163 let config = ThrottleConfig::new().enable();
164 assert!(config.enabled);
165 }
166
167 #[test]
168 fn test_config_disable() {
169 let config = ThrottleConfig::new().enable().disable();
170 assert!(!config.enabled);
171 }
172
173 #[test]
174 fn test_has_global_limit() {
175 let config = ThrottleConfig::new()
176 .enable()
177 .with_global_limit(1024);
178
179 assert!(config.has_global_limit());
180 assert!(!config.has_per_ip_limit());
181 }
182
183 #[test]
184 fn test_has_per_ip_limit() {
185 let config = ThrottleConfig::new()
186 .enable()
187 .with_per_ip_limit(1024);
188
189 assert!(!config.has_global_limit());
190 assert!(config.has_per_ip_limit());
191 }
192
193 #[test]
194 fn test_has_limit_disabled() {
195 let config = ThrottleConfig::new()
196 .with_global_limit(1024); assert!(!config.has_global_limit());
199 }
200
201 #[test]
202 fn test_is_active() {
203 let config = ThrottleConfig::new()
205 .with_global_limit(1024);
206 assert!(!config.is_active());
207
208 let config = ThrottleConfig::new()
210 .enable()
211 .with_global_limit(1024);
212 assert!(config.is_active());
213
214 let config = ThrottleConfig::new().enable();
216 assert!(!config.is_active());
217 }
218
219 #[test]
220 fn test_tokens_per_interval() {
221 let config = ThrottleConfig::new()
222 .with_refill_interval(Duration::from_millis(100));
223
224 assert_eq!(config.tokens_per_interval(1000), 100);
226
227 assert_eq!(config.tokens_per_interval(10 * 1024 * 1024), 1024 * 1024);
229 }
230
231 #[test]
232 fn test_format_limit_unlimited() {
233 assert_eq!(ThrottleConfig::format_limit(0), "unlimited");
234 }
235
236 #[test]
237 fn test_format_limit_bytes() {
238 assert_eq!(ThrottleConfig::format_limit(500), "500 B/s");
239 }
240
241 #[test]
242 fn test_format_limit_kb() {
243 let result = ThrottleConfig::format_limit(1024);
244 assert!(result.contains("KB/s"));
245 }
246
247 #[test]
248 fn test_format_limit_mb() {
249 let result = ThrottleConfig::format_limit(1024 * 1024);
250 assert!(result.contains("MB/s"));
251 }
252
253 #[test]
254 fn test_format_limit_gb() {
255 let result = ThrottleConfig::format_limit(1024 * 1024 * 1024);
256 assert!(result.contains("GB/s"));
257 }
258
259 #[test]
260 fn test_default() {
261 let config = ThrottleConfig::default();
262 assert!(!config.enabled);
263 assert_eq!(config.global_limit, 0);
264 }
265}