1#[cfg(feature = "schema")]
7use schemars::JsonSchema;
8use serde::{Deserialize, Serialize};
9
10use super::core::Bytes;
11
12#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
37#[cfg_attr(feature = "schema", derive(JsonSchema))]
38pub struct StorageQuota {
39 pub total_bytes: Bytes,
41 pub used_bytes: Bytes,
43 pub reserved_bytes: Bytes,
45}
46
47impl StorageQuota {
48 pub fn new(total_bytes: Bytes, used_bytes: Bytes, reserved_bytes: Bytes) -> Self {
50 Self {
51 total_bytes,
52 used_bytes,
53 reserved_bytes,
54 }
55 }
56
57 pub fn available_bytes(&self) -> Bytes {
59 self.total_bytes
60 .saturating_sub(self.used_bytes)
61 .saturating_sub(self.reserved_bytes)
62 }
63
64 pub fn utilization(&self) -> f64 {
66 if self.total_bytes == 0 {
67 0.0
68 } else {
69 self.used_bytes as f64 / self.total_bytes as f64
70 }
71 }
72
73 pub fn can_allocate(&self, bytes: Bytes) -> bool {
75 self.available_bytes() >= bytes
76 }
77
78 pub fn is_nearly_full(&self) -> bool {
80 self.utilization() > 0.9
81 }
82
83 pub fn allocated_bytes(&self) -> Bytes {
85 self.used_bytes.saturating_add(self.reserved_bytes)
86 }
87}
88
89impl Default for StorageQuota {
90 fn default() -> Self {
91 Self::new(0, 0, 0)
92 }
93}
94
95#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
123#[cfg_attr(feature = "schema", derive(JsonSchema))]
124pub struct BandwidthQuota {
125 pub total_bytes: Bytes,
127 pub used_bytes: Bytes,
129 pub period_seconds: u64,
131 pub period_start_ms: u64,
133}
134
135impl BandwidthQuota {
136 pub fn new(
138 total_bytes: Bytes,
139 used_bytes: Bytes,
140 period_seconds: u64,
141 period_start_ms: u64,
142 ) -> Self {
143 Self {
144 total_bytes,
145 used_bytes,
146 period_seconds,
147 period_start_ms,
148 }
149 }
150
151 pub fn remaining_bytes(&self) -> Bytes {
153 self.total_bytes.saturating_sub(self.used_bytes)
154 }
155
156 pub fn utilization(&self) -> f64 {
158 if self.total_bytes == 0 {
159 0.0
160 } else {
161 self.used_bytes as f64 / self.total_bytes as f64
162 }
163 }
164
165 pub fn can_consume(&self, bytes: Bytes) -> bool {
167 self.remaining_bytes() >= bytes
168 }
169
170 pub fn is_exceeded(&self) -> bool {
172 self.used_bytes >= self.total_bytes
173 }
174
175 pub fn avg_bytes_per_second(&self) -> f64 {
177 if self.period_seconds == 0 {
178 0.0
179 } else {
180 self.used_bytes as f64 / self.period_seconds as f64
181 }
182 }
183
184 pub fn is_period_expired(&self, current_time_ms: u64) -> bool {
186 let elapsed_ms = current_time_ms.saturating_sub(self.period_start_ms);
187 let period_ms = self.period_seconds * 1000;
188 elapsed_ms >= period_ms
189 }
190}
191
192impl Default for BandwidthQuota {
193 fn default() -> Self {
194 Self::new(0, 0, 0, 0)
195 }
196}
197
198#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
200#[cfg_attr(feature = "schema", derive(JsonSchema))]
201pub struct RateLimitQuota {
202 pub max_requests: u32,
204 pub current_requests: u32,
206 pub period_seconds: u64,
208 pub period_start_ms: u64,
210}
211
212impl RateLimitQuota {
213 pub fn new(
215 max_requests: u32,
216 current_requests: u32,
217 period_seconds: u64,
218 period_start_ms: u64,
219 ) -> Self {
220 Self {
221 max_requests,
222 current_requests,
223 period_seconds,
224 period_start_ms,
225 }
226 }
227
228 pub fn remaining_requests(&self) -> u32 {
230 self.max_requests.saturating_sub(self.current_requests)
231 }
232
233 pub fn is_allowed(&self) -> bool {
235 self.current_requests < self.max_requests
236 }
237
238 pub fn is_exceeded(&self) -> bool {
240 self.current_requests >= self.max_requests
241 }
242
243 pub fn utilization(&self) -> f64 {
245 if self.max_requests == 0 {
246 0.0
247 } else {
248 self.current_requests as f64 / self.max_requests as f64
249 }
250 }
251
252 pub fn is_period_expired(&self, current_time_ms: u64) -> bool {
254 let elapsed_ms = current_time_ms.saturating_sub(self.period_start_ms);
255 let period_ms = self.period_seconds * 1000;
256 elapsed_ms >= period_ms
257 }
258}
259
260impl Default for RateLimitQuota {
261 fn default() -> Self {
262 Self::new(0, 0, 0, 0)
263 }
264}
265
266#[derive(Debug, Clone, Serialize, Deserialize)]
268#[cfg_attr(feature = "schema", derive(JsonSchema))]
269pub struct UserQuota {
270 pub storage: StorageQuota,
272 pub bandwidth: BandwidthQuota,
274 pub rate_limit: RateLimitQuota,
276}
277
278impl UserQuota {
279 pub fn new(
281 storage: StorageQuota,
282 bandwidth: BandwidthQuota,
283 rate_limit: RateLimitQuota,
284 ) -> Self {
285 Self {
286 storage,
287 bandwidth,
288 rate_limit,
289 }
290 }
291
292 pub fn can_perform_operation(&self, storage_bytes: Bytes, bandwidth_bytes: Bytes) -> bool {
294 self.storage.can_allocate(storage_bytes) && self.bandwidth.can_consume(bandwidth_bytes)
295 }
296
297 pub fn has_warning_threshold(&self) -> bool {
299 self.storage.is_nearly_full()
300 || self.bandwidth.utilization() > 0.9
301 || self.rate_limit.utilization() > 0.9
302 }
303}
304
305impl Default for UserQuota {
306 fn default() -> Self {
307 Self::new(
308 StorageQuota::default(),
309 BandwidthQuota::default(),
310 RateLimitQuota::default(),
311 )
312 }
313}
314
315#[derive(Debug, Default)]
317pub struct StorageQuotaBuilder {
318 total_bytes: Option<Bytes>,
319 used_bytes: Option<Bytes>,
320 reserved_bytes: Option<Bytes>,
321}
322
323impl StorageQuotaBuilder {
324 pub fn new() -> Self {
326 Self::default()
327 }
328
329 pub fn total_bytes(mut self, bytes: Bytes) -> Self {
331 self.total_bytes = Some(bytes);
332 self
333 }
334
335 pub fn used_bytes(mut self, bytes: Bytes) -> Self {
337 self.used_bytes = Some(bytes);
338 self
339 }
340
341 pub fn reserved_bytes(mut self, bytes: Bytes) -> Self {
343 self.reserved_bytes = Some(bytes);
344 self
345 }
346
347 pub fn build(self) -> StorageQuota {
349 StorageQuota::new(
350 self.total_bytes.unwrap_or(0),
351 self.used_bytes.unwrap_or(0),
352 self.reserved_bytes.unwrap_or(0),
353 )
354 }
355}
356
357#[cfg(test)]
358mod tests {
359 use super::*;
360
361 #[test]
362 fn test_storage_quota() {
363 let quota = StorageQuota::new(1000, 400, 100);
364 assert_eq!(quota.available_bytes(), 500);
365 assert_eq!(quota.utilization(), 0.4);
366 assert!(quota.can_allocate(400));
367 assert!(!quota.can_allocate(600));
368 assert!(!quota.is_nearly_full());
369 assert_eq!(quota.allocated_bytes(), 500);
370 }
371
372 #[test]
373 fn test_storage_quota_nearly_full() {
374 let quota = StorageQuota::new(1000, 950, 0);
375 assert!(quota.is_nearly_full());
376 }
377
378 #[test]
379 fn test_storage_quota_saturating() {
380 let quota = StorageQuota::new(100, 80, 50);
381 assert_eq!(quota.available_bytes(), 0); }
383
384 #[test]
385 fn test_bandwidth_quota() {
386 let quota = BandwidthQuota::new(1000, 400, 3600, 0);
387 assert_eq!(quota.remaining_bytes(), 600);
388 assert_eq!(quota.utilization(), 0.4);
389 assert!(quota.can_consume(500));
390 assert!(!quota.can_consume(700));
391 assert!(!quota.is_exceeded());
392 }
393
394 #[test]
395 fn test_bandwidth_quota_exceeded() {
396 let quota = BandwidthQuota::new(1000, 1200, 3600, 0);
397 assert!(quota.is_exceeded());
398 assert_eq!(quota.remaining_bytes(), 0);
399 }
400
401 #[test]
402 fn test_bandwidth_quota_period_expired() {
403 let quota = BandwidthQuota::new(1000, 400, 3600, 0);
404 assert!(!quota.is_period_expired(1000 * 1000)); assert!(quota.is_period_expired(3600 * 1000 + 1)); }
407
408 #[test]
409 fn test_bandwidth_quota_avg_bps() {
410 let quota = BandwidthQuota::new(1000, 500, 10, 0);
411 assert_eq!(quota.avg_bytes_per_second(), 50.0);
412 }
413
414 #[test]
415 fn test_rate_limit_quota() {
416 let quota = RateLimitQuota::new(100, 40, 60, 0);
417 assert_eq!(quota.remaining_requests(), 60);
418 assert!(quota.is_allowed());
419 assert!(!quota.is_exceeded());
420 assert_eq!(quota.utilization(), 0.4);
421 }
422
423 #[test]
424 fn test_rate_limit_quota_exceeded() {
425 let quota = RateLimitQuota::new(100, 120, 60, 0);
426 assert!(!quota.is_allowed());
427 assert!(quota.is_exceeded());
428 assert_eq!(quota.remaining_requests(), 0);
429 }
430
431 #[test]
432 fn test_rate_limit_period_expired() {
433 let quota = RateLimitQuota::new(100, 40, 60, 0);
434 assert!(!quota.is_period_expired(30 * 1000)); assert!(quota.is_period_expired(60 * 1000 + 1)); }
437
438 #[test]
439 fn test_user_quota() {
440 let storage = StorageQuota::new(1000, 400, 0);
441 let bandwidth = BandwidthQuota::new(2000, 800, 3600, 0);
442 let rate_limit = RateLimitQuota::new(100, 40, 60, 0);
443
444 let user_quota = UserQuota::new(storage, bandwidth, rate_limit);
445
446 assert!(user_quota.can_perform_operation(500, 1000));
447 assert!(!user_quota.can_perform_operation(700, 1000)); assert!(!user_quota.can_perform_operation(500, 1500)); assert!(!user_quota.has_warning_threshold());
450 }
451
452 #[test]
453 fn test_user_quota_warning() {
454 let storage = StorageQuota::new(1000, 950, 0);
455 let bandwidth = BandwidthQuota::new(2000, 800, 3600, 0);
456 let rate_limit = RateLimitQuota::new(100, 40, 60, 0);
457
458 let user_quota = UserQuota::new(storage, bandwidth, rate_limit);
459 assert!(user_quota.has_warning_threshold());
460 }
461
462 #[test]
463 fn test_storage_quota_serialization() {
464 let quota = StorageQuota::new(1000, 400, 100);
465 let json = serde_json::to_string("a).unwrap();
466 let deserialized: StorageQuota = serde_json::from_str(&json).unwrap();
467 assert_eq!(quota, deserialized);
468 }
469
470 #[test]
471 fn test_storage_quota_builder() {
472 let quota = StorageQuotaBuilder::new()
473 .total_bytes(1000)
474 .used_bytes(400)
475 .reserved_bytes(100)
476 .build();
477
478 assert_eq!(quota.total_bytes, 1000);
479 assert_eq!(quota.used_bytes, 400);
480 assert_eq!(quota.reserved_bytes, 100);
481 }
482
483 #[test]
484 fn test_storage_quota_builder_partial() {
485 let quota = StorageQuotaBuilder::new().total_bytes(1000).build();
486
487 assert_eq!(quota.total_bytes, 1000);
488 assert_eq!(quota.used_bytes, 0);
489 assert_eq!(quota.reserved_bytes, 0);
490 }
491}