1use crate::topology::TopologyConfig;
4use crate::transport::TransportManagerConfig;
5use std::path::PathBuf;
6use std::time::Duration;
7
8#[derive(Debug, Clone)]
10pub struct IrohConfig {
11 pub bind_addr: Option<std::net::SocketAddr>,
14 pub relay_urls: Vec<String>,
17 pub secret_key: Option<[u8; 32]>,
21 pub bind_timeout: Duration,
23 pub shutdown_timeout: Duration,
25 pub download_timeout: Duration,
27}
28
29impl Default for IrohConfig {
30 fn default() -> Self {
31 Self {
32 bind_addr: None,
33 relay_urls: Vec::new(),
34 secret_key: None,
35 bind_timeout: Duration::from_secs(10),
36 shutdown_timeout: Duration::from_secs(5),
37 download_timeout: Duration::from_secs(30),
38 }
39 }
40}
41
42#[derive(Debug, Clone, Default)]
47pub struct MeshConfig {
48 pub node_id: Option<String>,
50 pub storage_path: Option<PathBuf>,
52 pub topology: TopologyConfig,
54 pub discovery: MeshDiscoveryConfig,
56 pub security: SecurityConfig,
58 pub transport_manager: Option<TransportManagerConfig>,
60 pub iroh: IrohConfig,
62 pub compaction: CompactionConfig,
64}
65
66#[derive(Debug, Clone)]
72pub struct CompactionConfig {
73 pub enabled: bool,
75 pub interval: Duration,
78 pub size_threshold_bytes: usize,
80 pub collections: Vec<String>,
85}
86
87const MIN_COMPACTION_INTERVAL: Duration = Duration::from_secs(10);
89
90impl CompactionConfig {
91 pub fn effective_interval(&self) -> Duration {
93 self.interval.max(MIN_COMPACTION_INTERVAL)
94 }
95}
96
97impl Default for CompactionConfig {
98 fn default() -> Self {
99 Self {
100 enabled: false,
101 interval: Duration::from_secs(300),
102 size_threshold_bytes: 64 * 1024,
103 collections: Vec::new(),
104 }
105 }
106}
107
108#[derive(Debug, Clone)]
110pub struct MeshDiscoveryConfig {
111 pub mdns_enabled: bool,
113 pub service_name: String,
115 pub interval: Duration,
117}
118
119impl Default for MeshDiscoveryConfig {
120 fn default() -> Self {
121 Self {
122 mdns_enabled: true,
123 service_name: "peat-mesh".to_string(),
124 interval: Duration::from_secs(30),
125 }
126 }
127}
128
129#[derive(Debug, Clone)]
131pub struct SecurityConfig {
132 pub encryption_enabled: bool,
134 pub require_peer_verification: bool,
136}
137
138impl Default for SecurityConfig {
139 fn default() -> Self {
140 Self {
141 encryption_enabled: true,
142 require_peer_verification: false,
143 }
144 }
145}
146
147#[cfg(test)]
148mod tests {
149 use super::*;
150
151 #[test]
154 fn test_mesh_config_default_node_id_is_none() {
155 let cfg = MeshConfig::default();
156 assert!(cfg.node_id.is_none());
157 }
158
159 #[test]
160 fn test_mesh_config_default_storage_path_is_none() {
161 let cfg = MeshConfig::default();
162 assert!(cfg.storage_path.is_none());
163 }
164
165 #[test]
166 fn test_mesh_config_default_topology() {
167 let cfg = MeshConfig::default();
168 assert_eq!(
170 cfg.topology.reevaluation_interval,
171 Some(Duration::from_secs(30))
172 );
173 }
174
175 #[test]
176 fn test_mesh_config_default_discovery() {
177 let cfg = MeshConfig::default();
178 assert!(cfg.discovery.mdns_enabled);
179 assert_eq!(cfg.discovery.service_name, "peat-mesh");
180 }
181
182 #[test]
183 fn test_mesh_config_default_security() {
184 let cfg = MeshConfig::default();
185 assert!(cfg.security.encryption_enabled);
186 assert!(!cfg.security.require_peer_verification);
187 }
188
189 #[test]
190 fn test_mesh_config_custom_values() {
191 let cfg = MeshConfig {
192 node_id: Some("custom-node".to_string()),
193 storage_path: Some(PathBuf::from("/tmp/mesh")),
194 discovery: MeshDiscoveryConfig {
195 mdns_enabled: false,
196 service_name: "my-mesh".to_string(),
197 interval: Duration::from_secs(10),
198 },
199 security: SecurityConfig {
200 encryption_enabled: false,
201 require_peer_verification: true,
202 },
203 ..Default::default()
204 };
205 assert_eq!(cfg.node_id.as_deref(), Some("custom-node"));
206 assert_eq!(
207 cfg.storage_path.as_deref(),
208 Some(std::path::Path::new("/tmp/mesh"))
209 );
210 assert!(!cfg.discovery.mdns_enabled);
211 assert_eq!(cfg.discovery.service_name, "my-mesh");
212 assert_eq!(cfg.discovery.interval, Duration::from_secs(10));
213 assert!(!cfg.security.encryption_enabled);
214 assert!(cfg.security.require_peer_verification);
215 }
216
217 #[test]
218 fn test_mesh_config_clone() {
219 let cfg = MeshConfig {
220 node_id: Some("cloned".to_string()),
221 ..Default::default()
222 };
223 let cloned = cfg.clone();
224 assert_eq!(cloned.node_id, cfg.node_id);
225 }
226
227 #[test]
228 fn test_mesh_config_debug() {
229 let cfg = MeshConfig::default();
230 let debug = format!("{:?}", cfg);
231 assert!(debug.contains("MeshConfig"));
232 }
233
234 #[test]
237 fn test_discovery_config_default_mdns_enabled() {
238 let cfg = MeshDiscoveryConfig::default();
239 assert!(cfg.mdns_enabled);
240 }
241
242 #[test]
243 fn test_discovery_config_default_service_name() {
244 let cfg = MeshDiscoveryConfig::default();
245 assert_eq!(cfg.service_name, "peat-mesh");
246 }
247
248 #[test]
249 fn test_discovery_config_default_interval() {
250 let cfg = MeshDiscoveryConfig::default();
251 assert_eq!(cfg.interval, Duration::from_secs(30));
252 }
253
254 #[test]
255 fn test_discovery_config_custom() {
256 let cfg = MeshDiscoveryConfig {
257 mdns_enabled: false,
258 service_name: "custom".to_string(),
259 interval: Duration::from_secs(5),
260 };
261 assert!(!cfg.mdns_enabled);
262 assert_eq!(cfg.service_name, "custom");
263 assert_eq!(cfg.interval, Duration::from_secs(5));
264 }
265
266 #[test]
267 fn test_discovery_config_clone() {
268 let cfg = MeshDiscoveryConfig::default();
269 let cloned = cfg.clone();
270 assert_eq!(cloned.service_name, cfg.service_name);
271 }
272
273 #[test]
274 fn test_discovery_config_debug() {
275 let cfg = MeshDiscoveryConfig::default();
276 let debug = format!("{:?}", cfg);
277 assert!(debug.contains("MeshDiscoveryConfig"));
278 }
279
280 #[test]
283 fn test_iroh_config_default() {
284 let cfg = IrohConfig::default();
285 assert!(cfg.bind_addr.is_none());
286 assert!(cfg.relay_urls.is_empty());
287 assert_eq!(cfg.bind_timeout, Duration::from_secs(10));
288 assert_eq!(cfg.shutdown_timeout, Duration::from_secs(5));
289 assert_eq!(cfg.download_timeout, Duration::from_secs(30));
290 }
291
292 #[test]
293 fn test_iroh_config_custom_bind_addr() {
294 let cfg = IrohConfig {
295 bind_addr: Some("0.0.0.0:4433".parse().unwrap()),
296 relay_urls: vec!["https://relay.example.com".to_string()],
297 ..Default::default()
298 };
299 assert_eq!(cfg.bind_addr.unwrap().port(), 4433);
300 assert_eq!(cfg.relay_urls.len(), 1);
301 }
302
303 #[test]
304 fn test_iroh_config_secret_key() {
305 let key = [42u8; 32];
306 let cfg = IrohConfig {
307 secret_key: Some(key),
308 ..Default::default()
309 };
310 assert_eq!(cfg.secret_key.unwrap(), [42u8; 32]);
311 }
312
313 #[test]
314 fn test_mesh_config_default_iroh() {
315 let cfg = MeshConfig::default();
316 assert!(cfg.iroh.bind_addr.is_none());
317 assert!(cfg.iroh.relay_urls.is_empty());
318 }
319
320 #[test]
323 fn test_security_config_default_encryption_enabled() {
324 let cfg = SecurityConfig::default();
325 assert!(cfg.encryption_enabled);
326 }
327
328 #[test]
329 fn test_security_config_default_peer_verification_disabled() {
330 let cfg = SecurityConfig::default();
331 assert!(!cfg.require_peer_verification);
332 }
333
334 #[test]
335 fn test_security_config_custom() {
336 let cfg = SecurityConfig {
337 encryption_enabled: false,
338 require_peer_verification: true,
339 };
340 assert!(!cfg.encryption_enabled);
341 assert!(cfg.require_peer_verification);
342 }
343
344 #[test]
345 fn test_security_config_clone() {
346 let cfg = SecurityConfig {
347 encryption_enabled: true,
348 require_peer_verification: true,
349 };
350 let cloned = cfg.clone();
351 assert_eq!(cloned.encryption_enabled, cfg.encryption_enabled);
352 assert_eq!(
353 cloned.require_peer_verification,
354 cfg.require_peer_verification
355 );
356 }
357
358 #[test]
359 fn test_security_config_debug() {
360 let cfg = SecurityConfig::default();
361 let debug = format!("{:?}", cfg);
362 assert!(debug.contains("SecurityConfig"));
363 }
364
365 #[test]
368 fn test_compaction_config_default_disabled() {
369 let cfg = CompactionConfig::default();
370 assert!(!cfg.enabled);
371 }
372
373 #[test]
374 fn test_compaction_config_default_interval() {
375 let cfg = CompactionConfig::default();
376 assert_eq!(cfg.interval, Duration::from_secs(300));
377 }
378
379 #[test]
380 fn test_compaction_config_default_threshold() {
381 let cfg = CompactionConfig::default();
382 assert_eq!(cfg.size_threshold_bytes, 64 * 1024);
383 }
384
385 #[test]
386 fn test_compaction_config_custom() {
387 let cfg = CompactionConfig {
388 enabled: true,
389 interval: Duration::from_secs(60),
390 size_threshold_bytes: 1024,
391 collections: vec!["beacons".to_string()],
392 };
393 assert!(cfg.enabled);
394 assert_eq!(cfg.interval, Duration::from_secs(60));
395 assert_eq!(cfg.size_threshold_bytes, 1024);
396 assert_eq!(cfg.collections.len(), 1);
397 }
398
399 #[test]
400 fn test_compaction_config_clone() {
401 let cfg = CompactionConfig {
402 enabled: false,
403 ..Default::default()
404 };
405 let cloned = cfg.clone();
406 assert_eq!(cloned.enabled, cfg.enabled);
407 assert_eq!(cloned.interval, cfg.interval);
408 }
409
410 #[test]
411 fn test_compaction_config_debug() {
412 let cfg = CompactionConfig::default();
413 let debug = format!("{:?}", cfg);
414 assert!(debug.contains("CompactionConfig"));
415 }
416
417 #[test]
418 fn test_mesh_config_default_compaction() {
419 let cfg = MeshConfig::default();
420 assert!(!cfg.compaction.enabled);
421 assert_eq!(cfg.compaction.interval, Duration::from_secs(300));
422 assert!(cfg.compaction.collections.is_empty());
423 }
424
425 #[test]
426 fn test_compaction_config_zero_interval_clamped() {
427 let cfg = CompactionConfig {
428 interval: Duration::from_secs(0),
429 ..Default::default()
430 };
431 assert_eq!(cfg.effective_interval(), Duration::from_secs(10));
432 }
433
434 #[test]
435 fn test_compaction_config_tiny_interval_clamped() {
436 let cfg = CompactionConfig {
437 interval: Duration::from_secs(3),
438 ..Default::default()
439 };
440 assert_eq!(cfg.effective_interval(), Duration::from_secs(10));
441 }
442
443 #[test]
444 fn test_compaction_config_large_interval_unchanged() {
445 let cfg = CompactionConfig {
446 interval: Duration::from_secs(600),
447 ..Default::default()
448 };
449 assert_eq!(cfg.effective_interval(), Duration::from_secs(600));
450 }
451
452 #[test]
453 fn test_compaction_config_exactly_min_interval() {
454 let cfg = CompactionConfig {
455 interval: Duration::from_secs(10),
456 ..Default::default()
457 };
458 assert_eq!(cfg.effective_interval(), Duration::from_secs(10));
459 }
460
461 #[test]
462 fn test_compaction_config_with_collections() {
463 let cfg = CompactionConfig {
464 enabled: true,
465 collections: vec!["beacons".to_string(), "platforms".to_string()],
466 ..Default::default()
467 };
468 assert!(cfg.enabled);
469 assert_eq!(cfg.collections.len(), 2);
470 assert_eq!(cfg.collections[0], "beacons");
471 }
472}