1use crate::types::{ProtocolType, ServiceType, DiscoveryFilter};
4use crate::error::Result;
5use serde::{Deserialize, Serialize};
6use std::{collections::HashSet, time::Duration};
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
10pub struct DiscoveryConfig {
11 service_types: Vec<ServiceType>,
13 timeout: Option<Duration>,
15 verify_services: bool,
17 interfaces: Option<HashSet<String>>,
19 max_services: usize,
21 max_retries: u32,
23 cache_duration: Duration,
25 rate_limit: Option<Duration>,
27 metrics_enabled: bool,
29 enabled_protocols: HashSet<ProtocolType>,
31 allow_cross_protocol: bool,
33 enable_ipv4: bool,
35 enable_ipv6: bool,
37 filter: Option<DiscoveryFilter>,
39}
40
41impl Default for DiscoveryConfig {
42 fn default() -> Self {
43 Self {
44 service_types: Vec::new(),
45 timeout: Some(Duration::from_secs(30)),
46 verify_services: false,
47 interfaces: None,
48 max_services: 1000,
49 max_retries: 3,
50 cache_duration: Duration::from_secs(300),
51 rate_limit: Some(Duration::from_secs(1)),
52 metrics_enabled: false,
53 enabled_protocols: [ProtocolType::Mdns].into_iter().collect(),
54 allow_cross_protocol: false,
55 enable_ipv4: true,
56 enable_ipv6: false,
57 filter: None,
58 }
59 }
60}
61
62impl DiscoveryConfig {
63 pub fn new() -> Self {
65 Self::default()
66 }
67
68 pub fn with_timeout(mut self, timeout: Duration) -> Self {
70 self.timeout = Some(timeout);
71 self
72 }
73
74 pub fn timeout(&self) -> Option<Duration> {
76 self.timeout
77 }
78
79 pub fn with_service_type(mut self, service_type: ServiceType) -> Self {
81 self.service_types.push(service_type);
82 self
83 }
84
85 pub fn service_types(&self) -> &[ServiceType] {
87 &self.service_types
88 }
89
90 pub fn with_verify_services(mut self, verify: bool) -> Self {
92 self.verify_services = verify;
93 self
94 }
95
96 pub fn verify_services(&self) -> bool {
98 self.verify_services
99 }
100
101 pub fn with_interfaces(mut self, interfaces: HashSet<String>) -> Self {
103 self.interfaces = Some(interfaces);
104 self
105 }
106
107 pub fn interfaces(&self) -> Option<&HashSet<String>> {
109 self.interfaces.as_ref()
110 }
111
112 pub fn with_max_services(mut self, max: usize) -> Self {
114 self.max_services = max;
115 self
116 }
117
118 pub fn max_services(&self) -> usize {
120 self.max_services
121 }
122
123 pub fn with_max_retries(mut self, retries: u32) -> Self {
125 self.max_retries = retries;
126 self
127 }
128
129 pub fn max_retries(&self) -> u32 {
131 self.max_retries
132 }
133
134 pub fn with_ipv4(mut self, enable: bool) -> Self {
136 self.enable_ipv4 = enable;
137 self
138 }
139
140 pub fn enable_ipv4(&self) -> bool {
142 self.enable_ipv4
143 }
144
145 pub fn with_ipv6(mut self, enable: bool) -> Self {
147 self.enable_ipv6 = enable;
148 self
149 }
150
151 pub fn enable_ipv6(&self) -> bool {
153 self.enable_ipv6
154 }
155
156 pub fn with_protocol(mut self, protocol: ProtocolType) -> Self {
158 self.enabled_protocols.insert(protocol);
159 self
160 }
161
162 pub fn is_protocol_enabled(&self, protocol: ProtocolType) -> bool {
164 self.enabled_protocols.contains(&protocol)
165 }
166
167 pub fn enable_protocol(&mut self, protocol: ProtocolType) {
169 self.enabled_protocols.insert(protocol);
170 }
171
172 pub fn disable_protocol(&mut self, protocol: ProtocolType) {
174 self.enabled_protocols.remove(&protocol);
175 }
176
177 pub fn with_protocols(mut self, protocols: HashSet<ProtocolType>) -> Self {
179 self.enabled_protocols = protocols;
180 self
181 }
182
183 pub fn protocols(&self) -> &HashSet<ProtocolType> {
185 &self.enabled_protocols
186 }
187
188 pub fn with_cross_protocol(mut self, enable: bool) -> Self {
190 self.allow_cross_protocol = enable;
191 self
192 }
193
194 pub fn allow_cross_protocol(&self) -> bool {
196 self.allow_cross_protocol
197 }
198
199 pub fn with_metrics(mut self, enable: bool) -> Self {
201 self.metrics_enabled = enable;
202 self
203 }
204
205 pub fn metrics_enabled(&self) -> bool {
207 self.metrics_enabled
208 }
209
210 pub fn with_rate_limit(mut self, limit: Duration) -> Self {
212 self.rate_limit = Some(limit);
213 self
214 }
215
216 pub fn rate_limit(&self) -> Option<Duration> {
218 self.rate_limit
219 }
220
221 pub fn with_cache_duration(mut self, duration: Duration) -> Self {
223 self.cache_duration = duration;
224 self
225 }
226
227 pub fn cache_duration(&self) -> Duration {
229 self.cache_duration
230 }
231
232 pub fn protocol_timeout(&self) -> Duration {
234 self.timeout.unwrap_or(Duration::from_secs(30))
235 }
236
237 pub fn has_protocol(&self, protocol: ProtocolType) -> bool {
239 self.enabled_protocols.contains(&protocol)
240 }
241
242 pub fn filter(&self) -> Option<&DiscoveryFilter> {
244 self.filter.as_ref()
245 }
246
247 pub fn with_filter(mut self, filter: DiscoveryFilter) -> Self {
249 self.filter = Some(filter);
250 self
251 }
252
253 pub fn validate(&self) -> Result<()> {
255 if self.timeout.is_some_and(|t| t.as_secs() == 0) {
256 return Err(crate::error::DiscoveryError::configuration(
257 "Timeout must be greater than 0",
258 ));
259 }
260
261 if !self.enable_ipv4 && !self.enable_ipv6 {
262 return Err(crate::error::DiscoveryError::configuration(
263 "Either IPv4 or IPv6 must be enabled",
264 ));
265 }
266
267 if self.enabled_protocols.is_empty() {
268 return Err(crate::error::DiscoveryError::configuration(
269 "At least one protocol must be enabled",
270 ));
271 }
272
273 Ok(())
274 }
275}
276
277#[derive(Debug, Clone, Serialize, Deserialize)]
279pub struct RegistrationConfig {
280 pub ttl: Duration,
282 pub auto_refresh: bool,
284 pub refresh_interval: Duration,
286 pub interfaces: Vec<String>,
288 pub protocols: HashSet<ProtocolType>,
290 pub enable_ipv6: bool,
292 pub enable_ipv4: bool,
294 pub priority: u16,
296 pub weight: u16,
298}
299
300impl Default for RegistrationConfig {
301 fn default() -> Self {
302 let mut protocols = HashSet::new();
303 protocols.insert(ProtocolType::Mdns);
304
305 Self {
306 ttl: Duration::from_secs(120),
307 auto_refresh: true,
308 refresh_interval: Duration::from_secs(60),
309 interfaces: Vec::new(),
310 protocols,
311 enable_ipv6: true,
312 enable_ipv4: true,
313 priority: 0,
314 weight: 0,
315 }
316 }
317}
318
319impl RegistrationConfig {
320 pub fn new() -> Self {
322 Self::default()
323 }
324
325 pub fn ttl(mut self, ttl: Duration) -> Self {
327 self.ttl = ttl;
328 self
329 }
330
331 pub fn auto_refresh(mut self, auto_refresh: bool) -> Self {
333 self.auto_refresh = auto_refresh;
334 self
335 }
336
337 pub fn refresh_interval(mut self, interval: Duration) -> Self {
339 self.refresh_interval = interval;
340 self
341 }
342
343 pub fn interfaces<I, S>(mut self, interfaces: I) -> Self
345 where
346 I: IntoIterator<Item = S>,
347 S: Into<String>,
348 {
349 self.interfaces = interfaces.into_iter().map(|s| s.into()).collect();
350 self
351 }
352
353 pub fn protocols<I>(mut self, protocols: I) -> Self
355 where
356 I: IntoIterator<Item = ProtocolType>,
357 {
358 self.protocols = protocols.into_iter().collect();
359 self
360 }
361
362 pub fn priority(mut self, priority: u16) -> Self {
364 self.priority = priority;
365 self
366 }
367
368 pub fn weight(mut self, weight: u16) -> Self {
370 self.weight = weight;
371 self
372 }
373
374 pub fn validate(&self) -> crate::Result<()> {
376 if self.ttl.is_zero() {
377 return Err(crate::error::DiscoveryError::configuration(
378 "TTL cannot be zero",
379 ));
380 }
381
382 if self.auto_refresh && self.refresh_interval.is_zero() {
383 return Err(crate::error::DiscoveryError::configuration(
384 "Refresh interval cannot be zero when auto-refresh is enabled",
385 ));
386 }
387
388 if self.auto_refresh && self.refresh_interval >= self.ttl {
389 return Err(crate::error::DiscoveryError::configuration(
390 "Refresh interval must be less than TTL",
391 ));
392 }
393
394 if self.protocols.is_empty() {
395 return Err(crate::error::DiscoveryError::configuration(
396 "At least one protocol must be enabled",
397 ));
398 }
399
400 if !self.enable_ipv4 && !self.enable_ipv6 {
401 return Err(crate::error::DiscoveryError::configuration(
402 "At least one IP version must be enabled",
403 ));
404 }
405
406 Ok(())
407 }
408}
409
410#[cfg(test)]
411mod tests {
412 use super::*;
413 use std::time::Duration;
414
415 #[test]
416 fn test_config_defaults() {
417 let config = DiscoveryConfig::new();
418 assert_eq!(config.service_types().len(), 0);
419 assert!(config.timeout().is_some());
420 assert!(!config.verify_services());
421 assert!(config.is_protocol_enabled(ProtocolType::Mdns));
422 }
423
424 #[test]
425 fn test_config_builder() -> Result<()> {
426 let config = DiscoveryConfig::new()
427 .with_service_type(ServiceType::new("_http._tcp")?);
428 assert_eq!(config.service_types().len(), 1);
429 Ok(())
430 }
431
432 #[test]
433 fn test_config_validation() -> Result<()> {
434 let config = DiscoveryConfig::new()
435 .with_service_type(ServiceType::new("_http._tcp")?)
436 .with_timeout(Duration::from_secs(10))
437 .with_verify_services(true);
438
439 assert!(config.validate().is_ok());
440
441 let invalid_config = DiscoveryConfig::new()
443 .with_timeout(Duration::ZERO);
444 assert!(invalid_config.validate().is_err());
445
446 let invalid_config = DiscoveryConfig::new()
448 .with_ipv4(false)
449 .with_ipv6(false);
450 assert!(invalid_config.validate().is_err());
451
452 Ok(())
453 }
454}