chie_shared/config/
rate_limit.rs

1//! Rate limiting configuration
2
3use serde::{Deserialize, Serialize};
4
5/// Rate limiting configuration
6///
7/// # Examples
8///
9/// Using the default configuration:
10/// ```
11/// use chie_shared::RateLimitConfig;
12///
13/// let config = RateLimitConfig::default();
14/// assert_eq!(config.max_requests, 100);
15/// assert_eq!(config.window_secs, 60);
16/// assert_eq!(config.burst_size, 20);
17/// assert!(config.enabled);
18/// assert!(config.validate().is_ok());
19/// ```
20///
21/// Building a strict rate limit configuration:
22/// ```
23/// use chie_shared::RateLimitConfigBuilder;
24///
25/// let config = RateLimitConfigBuilder::new()
26///     .max_requests(10)
27///     .window_secs(1)  // 10 requests per second
28///     .burst_size(5)   // Allow small bursts
29///     .enabled(true)
30///     .build();
31///
32/// assert_eq!(config.max_requests, 10);
33/// assert_eq!(config.window_secs, 1);
34/// assert!(config.validate().is_ok());
35/// ```
36#[derive(Debug, Clone, Serialize, Deserialize)]
37pub struct RateLimitConfig {
38    /// Maximum requests per time window
39    pub max_requests: u32,
40    /// Time window in seconds
41    pub window_secs: u64,
42    /// Burst allowance (requests above limit temporarily)
43    pub burst_size: u32,
44    /// Enable rate limiting
45    pub enabled: bool,
46}
47
48impl Default for RateLimitConfig {
49    fn default() -> Self {
50        Self {
51            max_requests: 100,
52            window_secs: 60,
53            burst_size: 20,
54            enabled: true,
55        }
56    }
57}
58
59impl RateLimitConfig {
60    /// Validate the rate limit configuration
61    ///
62    /// # Errors
63    ///
64    /// Returns error if configuration is invalid
65    pub fn validate(&self) -> crate::ChieResult<()> {
66        use crate::ChieError;
67
68        if self.enabled {
69            if self.max_requests == 0 {
70                return Err(ChieError::validation(
71                    "max_requests must be greater than 0 when rate limiting is enabled",
72                ));
73            }
74
75            if self.window_secs == 0 {
76                return Err(ChieError::validation(
77                    "window_secs must be greater than 0 when rate limiting is enabled",
78                ));
79            }
80
81            if self.burst_size > self.max_requests {
82                return Err(ChieError::validation(
83                    "burst_size must not exceed max_requests",
84                ));
85            }
86        }
87
88        Ok(())
89    }
90}
91
92/// Builder for `RateLimitConfig`
93///
94/// # Examples
95///
96/// Building a generous rate limit for authenticated users:
97/// ```
98/// use chie_shared::RateLimitConfigBuilder;
99///
100/// let config = RateLimitConfigBuilder::new()
101///     .max_requests(1000)
102///     .window_secs(60)  // 1000 requests per minute
103///     .burst_size(200)  // Allow larger bursts
104///     .enabled(true)
105///     .build();
106///
107/// assert_eq!(config.max_requests, 1000);
108/// assert!(config.validate().is_ok());
109/// ```
110///
111/// Disabling rate limiting for internal services:
112/// ```
113/// use chie_shared::RateLimitConfigBuilder;
114///
115/// let config = RateLimitConfigBuilder::new()
116///     .enabled(false)
117///     .build();
118///
119/// assert!(!config.enabled);
120/// assert!(config.validate().is_ok());
121/// ```
122#[derive(Debug, Default)]
123pub struct RateLimitConfigBuilder {
124    config: RateLimitConfig,
125}
126
127impl RateLimitConfigBuilder {
128    /// Create a new builder with default values
129    #[must_use]
130    pub fn new() -> Self {
131        Self::default()
132    }
133
134    /// Set maximum requests per window
135    #[must_use]
136    pub const fn max_requests(mut self, max: u32) -> Self {
137        self.config.max_requests = max;
138        self
139    }
140
141    /// Set time window in seconds
142    #[must_use]
143    pub const fn window_secs(mut self, secs: u64) -> Self {
144        self.config.window_secs = secs;
145        self
146    }
147
148    /// Set burst size
149    #[must_use]
150    pub const fn burst_size(mut self, size: u32) -> Self {
151        self.config.burst_size = size;
152        self
153    }
154
155    /// Enable or disable rate limiting
156    #[must_use]
157    pub const fn enabled(mut self, enable: bool) -> Self {
158        self.config.enabled = enable;
159        self
160    }
161
162    /// Build the configuration
163    #[must_use]
164    pub const fn build(self) -> RateLimitConfig {
165        self.config
166    }
167}