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}