ultrafast_mcp_core/config/
base.rs1use crate::error::{MCPResult, ValidationError};
7use crate::validation::timeout::{
8 validate_backoff_multiplier, validate_retry_count, validate_timeout,
9};
10use serde::{Deserialize, Serialize};
11use std::time::Duration;
12
13pub trait ConfigDefaults {
15 fn default_timeout() -> Duration {
16 Duration::from_secs(30)
17 }
18
19 fn default_retries() -> u32 {
20 3
21 }
22
23 fn default_backoff_multiplier() -> f64 {
24 2.0
25 }
26
27 fn default_host() -> String {
28 "127.0.0.1".to_string()
29 }
30
31 fn default_port() -> u16 {
32 8080
33 }
34}
35
36pub trait BaseConfig:
38 Default + Serialize + for<'de> Deserialize<'de> + Clone + Send + Sync
39{
40 fn validate(&self) -> MCPResult<()>;
42
43 fn config_name(&self) -> &'static str;
45}
46
47#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
49pub struct TimeoutConfig {
50 pub connect_timeout: Duration,
51 pub request_timeout: Duration,
52 pub shutdown_timeout: Duration,
53}
54
55impl Default for TimeoutConfig {
56 fn default() -> Self {
57 Self {
58 connect_timeout: Duration::from_secs(10),
59 request_timeout: Self::default_timeout(),
60 shutdown_timeout: Duration::from_secs(5),
61 }
62 }
63}
64
65impl ConfigDefaults for TimeoutConfig {}
66
67impl BaseConfig for TimeoutConfig {
68 fn validate(&self) -> MCPResult<()> {
69 validate_timeout(self.connect_timeout)?;
70 validate_timeout(self.request_timeout)?;
71 validate_timeout(self.shutdown_timeout)?;
72 Ok(())
73 }
74
75 fn config_name(&self) -> &'static str {
76 "TimeoutConfig"
77 }
78}
79
80#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
82pub struct RetryConfig {
83 pub max_retries: u32,
84 pub initial_delay: Duration,
85 pub max_delay: Duration,
86 pub backoff_multiplier: f64,
87 pub enable_jitter: bool,
88}
89
90impl Default for RetryConfig {
91 fn default() -> Self {
92 Self {
93 max_retries: Self::default_retries(),
94 initial_delay: Duration::from_millis(100),
95 max_delay: Duration::from_secs(30),
96 backoff_multiplier: Self::default_backoff_multiplier(),
97 enable_jitter: true,
98 }
99 }
100}
101
102impl ConfigDefaults for RetryConfig {}
103
104impl BaseConfig for RetryConfig {
105 fn validate(&self) -> MCPResult<()> {
106 validate_retry_count(self.max_retries)?;
107 validate_timeout(self.initial_delay)?;
108 validate_timeout(self.max_delay)?;
109 validate_backoff_multiplier(self.backoff_multiplier)?;
110
111 if self.initial_delay > self.max_delay {
112 return Err(ValidationError::InvalidFormat {
113 field: "initial_delay".to_string(),
114 expected: "less than or equal to max_delay".to_string(),
115 }
116 .into());
117 }
118
119 Ok(())
120 }
121
122 fn config_name(&self) -> &'static str {
123 "RetryConfig"
124 }
125}
126
127#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
129pub struct NetworkConfig {
130 pub host: String,
131 pub port: u16,
132 pub bind_address: Option<String>,
133 pub enable_keepalive: bool,
134 pub keepalive_timeout: Duration,
135}
136
137impl Default for NetworkConfig {
138 fn default() -> Self {
139 Self {
140 host: Self::default_host(),
141 port: Self::default_port(),
142 bind_address: None,
143 enable_keepalive: true,
144 keepalive_timeout: Duration::from_secs(60),
145 }
146 }
147}
148
149impl ConfigDefaults for NetworkConfig {}
150
151impl BaseConfig for NetworkConfig {
152 fn validate(&self) -> MCPResult<()> {
153 if self.host.is_empty() {
154 return Err(ValidationError::RequiredField {
155 field: "host".to_string(),
156 }
157 .into());
158 }
159
160 if self.port == 0 {
161 return Err(ValidationError::ValueOutOfRange {
162 field: "port".to_string(),
163 min: "1".to_string(),
164 max: "65535".to_string(),
165 actual: "0".to_string(),
166 }
167 .into());
168 }
169
170 validate_timeout(self.keepalive_timeout)?;
171
172 Ok(())
173 }
174
175 fn config_name(&self) -> &'static str {
176 "NetworkConfig"
177 }
178}
179
180#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
182pub struct SecurityConfig {
183 pub enable_tls: bool,
184 pub cert_path: Option<String>,
185 pub key_path: Option<String>,
186 pub ca_cert_path: Option<String>,
187 pub allow_insecure: bool,
188 pub allowed_origins: Vec<String>,
189}
190
191impl Default for SecurityConfig {
192 fn default() -> Self {
193 Self {
194 enable_tls: false,
195 cert_path: None,
196 key_path: None,
197 ca_cert_path: None,
198 allow_insecure: true, allowed_origins: vec!["*".to_string()], }
201 }
202}
203
204impl BaseConfig for SecurityConfig {
205 fn validate(&self) -> MCPResult<()> {
206 if self.enable_tls {
207 if self.cert_path.is_none() {
208 return Err(ValidationError::RequiredField {
209 field: "cert_path".to_string(),
210 }
211 .into());
212 }
213
214 if self.key_path.is_none() {
215 return Err(ValidationError::RequiredField {
216 field: "key_path".to_string(),
217 }
218 .into());
219 }
220 }
221
222 Ok(())
223 }
224
225 fn config_name(&self) -> &'static str {
226 "SecurityConfig"
227 }
228}
229
230#[derive(Debug, Clone, Serialize, Deserialize)]
232pub struct ConfigBuilder<T> {
233 config: T,
234}
235
236impl<T: BaseConfig> ConfigBuilder<T> {
237 pub fn new(config: T) -> Self {
238 Self { config }
239 }
240
241 pub fn build(self) -> MCPResult<T> {
242 self.config.validate()?;
243 Ok(self.config)
244 }
245
246 pub fn validate(&self) -> MCPResult<()> {
247 self.config.validate()
248 }
249}
250
251#[macro_export]
253macro_rules! impl_config_defaults {
254 ($config_type:ty, $name:expr) => {
255 impl $crate::config::base::ConfigDefaults for $config_type {}
256
257 impl $crate::config::base::BaseConfig for $config_type {
258 fn validate(&self) -> $crate::MCPResult<()> {
259 Ok(())
261 }
262
263 fn config_name(&self) -> &'static str {
264 $name
265 }
266 }
267 };
268}
269
270#[cfg(test)]
271mod tests {
272 use super::*;
273
274 #[test]
275 fn test_timeout_config_defaults() {
276 let config = TimeoutConfig::default();
277 assert_eq!(config.connect_timeout, Duration::from_secs(10));
278 assert_eq!(config.request_timeout, Duration::from_secs(30));
279 assert_eq!(config.shutdown_timeout, Duration::from_secs(5));
280 }
281
282 #[test]
283 fn test_timeout_config_validation() {
284 let config = TimeoutConfig::default();
285 assert!(config.validate().is_ok());
286
287 let invalid_config = TimeoutConfig {
288 connect_timeout: Duration::from_millis(50), request_timeout: Duration::from_secs(30),
290 shutdown_timeout: Duration::from_secs(5),
291 };
292 assert!(invalid_config.validate().is_err());
293 }
294
295 #[test]
296 fn test_retry_config_defaults() {
297 let config = RetryConfig::default();
298 assert_eq!(config.max_retries, 3);
299 assert_eq!(config.initial_delay, Duration::from_millis(100));
300 assert_eq!(config.max_delay, Duration::from_secs(30));
301 assert_eq!(config.backoff_multiplier, 2.0);
302 assert!(config.enable_jitter);
303 }
304
305 #[test]
306 fn test_retry_config_validation() {
307 let config = RetryConfig::default();
308 assert!(config.validate().is_ok());
309
310 let invalid_config = RetryConfig {
311 max_retries: 15, ..Default::default()
313 };
314 assert!(invalid_config.validate().is_err());
315 }
316
317 #[test]
318 fn test_network_config_defaults() {
319 let config = NetworkConfig::default();
320 assert_eq!(config.host, "127.0.0.1");
321 assert_eq!(config.port, 8080);
322 assert!(config.enable_keepalive);
323 }
324
325 #[test]
326 fn test_security_config_defaults() {
327 let config = SecurityConfig::default();
328 assert!(!config.enable_tls);
329 assert!(config.allow_insecure);
330 assert_eq!(config.allowed_origins, vec!["*"]);
331 }
332
333 #[test]
334 fn test_config_builder() {
335 let config = TimeoutConfig::default();
336 let builder = ConfigBuilder::new(config);
337 let built_config = builder.build().unwrap();
338 assert_eq!(built_config.config_name(), "TimeoutConfig");
339 }
340}