//! Admin rate limit model and request/response types. //! //! Per-provider rate limit configuration managed by admins. //! Controls the maximum number of API requests allowed within //! a sliding time window for each LLM provider. use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; use uuid::Uuid; /// An admin rate limit record from the database. #[derive(Debug, Clone, Serialize)] pub struct AdminRateLimit { pub id: Uuid, pub provider_name: String, pub max_requests: i32, pub time_window_seconds: i32, pub updated_at: DateTime, } /// Request body for `PUT /api/v1/admin/rate-limits/:provider_name`. #[derive(Debug, Deserialize)] pub struct UpdateRateLimitRequest { pub max_requests: i32, pub time_window_seconds: i32, } impl UpdateRateLimitRequest { /// Validate the rate limit update request. /// /// - `max_requests` must be between 1 and 1000. /// - `time_window_seconds` must be between 1 and 3600. pub fn validate(&self) -> Result<(), String> { if self.max_requests < 1 || self.max_requests > 1000 { return Err("max_requests must be between 1 and 1000".into()); } if self.time_window_seconds < 1 || self.time_window_seconds > 3600 { return Err("time_window_seconds must be between 1 and 3600".into()); } Ok(()) } } /// Response shape for rate limit endpoints. #[derive(Debug, Serialize)] pub struct RateLimitResponse { pub id: Uuid, pub provider_name: String, pub max_requests: i32, pub time_window_seconds: i32, pub updated_at: DateTime, } impl From for RateLimitResponse { fn from(rl: AdminRateLimit) -> Self { Self { id: rl.id, provider_name: rl.provider_name, max_requests: rl.max_requests, time_window_seconds: rl.time_window_seconds, updated_at: rl.updated_at, } } } #[cfg(test)] mod tests { use super::*; #[test] fn test_valid_rate_limit_request() { let req = UpdateRateLimitRequest { max_requests: 30, time_window_seconds: 60, }; assert!(req.validate().is_ok()); } #[test] fn test_max_requests_too_low() { let req = UpdateRateLimitRequest { max_requests: 0, time_window_seconds: 60, }; let err = req.validate().unwrap_err(); assert!(err.contains("max_requests")); } #[test] fn test_max_requests_too_high() { let req = UpdateRateLimitRequest { max_requests: 1001, time_window_seconds: 60, }; let err = req.validate().unwrap_err(); assert!(err.contains("max_requests")); } #[test] fn test_time_window_too_low() { let req = UpdateRateLimitRequest { max_requests: 30, time_window_seconds: 0, }; let err = req.validate().unwrap_err(); assert!(err.contains("time_window_seconds")); } #[test] fn test_time_window_too_high() { let req = UpdateRateLimitRequest { max_requests: 30, time_window_seconds: 3601, }; let err = req.validate().unwrap_err(); assert!(err.contains("time_window_seconds")); } #[test] fn test_boundary_values() { let req_min = UpdateRateLimitRequest { max_requests: 1, time_window_seconds: 1, }; assert!(req_min.validate().is_ok()); let req_max = UpdateRateLimitRequest { max_requests: 1000, time_window_seconds: 3600, }; assert!(req_max.validate().is_ok()); } }