auto_discovery/protocols/
mod.rs

1//! Protocol implementations for service discovery
2
3use crate::{
4    config::DiscoveryConfig,
5    error::{DiscoveryError, Result},
6    registry::ServiceRegistry,
7    service::ServiceInfo,
8    types::{ProtocolType, ServiceType},
9};
10use async_trait::async_trait;
11use std::{collections::HashMap, sync::Arc, time::Duration};
12use tracing::warn;
13
14pub mod mdns;
15pub mod upnp;
16pub mod dns_sd;
17
18// #[cfg(feature = "simple-mdns")]
19// pub mod simple_mdns; // Disabled due to API incompatibilities
20
21/// Trait for service discovery protocols
22#[async_trait]
23pub trait DiscoveryProtocol: Send + Sync {
24    /// Get the protocol type
25    fn protocol_type(&self) -> ProtocolType;
26
27    /// Discover services of the specified types with timeout
28    async fn discover_services(
29        &self,
30        service_types: Vec<ServiceType>,
31        timeout: Option<Duration>,
32    ) -> Result<Vec<ServiceInfo>>;
33
34    /// Register a service for advertisement
35    async fn register_service(&self, service: ServiceInfo) -> Result<()>;
36
37    /// Unregister a service
38    async fn unregister_service(&self, service: &ServiceInfo) -> Result<()>;
39
40    /// Verify if a service is alive and healthy
41    async fn verify_service(&self, service: &ServiceInfo) -> Result<bool>;
42
43    /// Check if the protocol is available
44    async fn is_available(&self) -> bool;
45
46    /// Set the service registry for this protocol
47    fn set_registry(&mut self, registry: Arc<ServiceRegistry>);
48}
49
50/// Manager for all discovery protocols
51#[derive(Clone)]
52pub struct ProtocolManager {
53    #[allow(dead_code)]
54    config: DiscoveryConfig,
55    protocols: HashMap<ProtocolType, Arc<dyn DiscoveryProtocol + Send + Sync>>,
56}
57
58impl ProtocolManager {
59    /// Create a new protocol manager
60    pub async fn new(config: DiscoveryConfig) -> Result<Self> {
61        let mut protocols: HashMap<ProtocolType, Arc<dyn DiscoveryProtocol + Send + Sync>> = HashMap::new();
62
63        // Initialize protocols based on config
64        if config.has_protocol(ProtocolType::Mdns) {
65            #[cfg(all(feature = "simple-mdns", not(feature = "mdns")))]
66            {
67                if let Ok(mdns) = simple_mdns::SimpleMdnsProtocol::new(&config).await {
68                    protocols.insert(ProtocolType::Mdns, Arc::new(mdns) as Arc<dyn DiscoveryProtocol + Send + Sync>);
69                }
70            }
71            #[cfg(not(feature = "simple-mdns"))]
72            {
73                if let Ok(mdns) = mdns::MdnsProtocol::new(&config).await {
74                    protocols.insert(ProtocolType::Mdns, Arc::new(mdns) as Arc<dyn DiscoveryProtocol + Send + Sync>);
75                }
76            }
77        }
78
79        if config.has_protocol(ProtocolType::Upnp) {
80            if let Ok(ssdp) = upnp::SsdpProtocol::new(config.clone()) {
81                protocols.insert(ProtocolType::Upnp, Arc::new(ssdp) as Arc<dyn DiscoveryProtocol + Send + Sync>);
82            }
83        }
84
85        if config.has_protocol(ProtocolType::DnsSd) {
86            if let Ok(dns_sd) = dns_sd::DnsSdProtocol::new(&config).await {
87                protocols.insert(ProtocolType::DnsSd, Arc::new(dns_sd) as Arc<dyn DiscoveryProtocol + Send + Sync>);
88            }
89        }
90
91        // simple-mdns implementation is disabled due to API incompatibilities
92        // #[cfg(feature = "simple-mdns")]
93        // {
94        //     if config.has_protocol(ProtocolType::Mdns) {
95        //         if let Ok(simple_mdns) = simple_mdns::SimpleMdnsProtocol::new(&config).await {
96        //             protocols.insert(
97        //                 ProtocolType::Mdns,
98        //                 Arc::new(simple_mdns) as Arc<dyn DiscoveryProtocol + Send + Sync>,
99        //             );
100        //         }
101        //     }
102        // }
103
104        Ok(Self { config, protocols })
105    }
106
107    /// Get enabled protocol types
108    pub fn protocol_types(&self) -> Vec<ProtocolType> {
109        self.protocols.keys().copied().collect()
110    }
111
112    /// Discover services with all enabled protocols
113    pub async fn discover_services(
114        &self,
115        service_types: Vec<ServiceType>,
116        timeout: Option<Duration>,
117    ) -> Result<Vec<ServiceInfo>> {
118        let mut all_services = Vec::new();
119
120        for protocol in self.protocols.values() {
121            match protocol.discover_services(service_types.clone(), timeout).await {
122                Ok(services) => all_services.extend(services),
123                Err(e) => warn!(
124                    "Error discovering services with protocol {:?}: {}",
125                    protocol.protocol_type(),
126                    e
127                ),
128            }
129        }
130
131        Ok(all_services)
132    }
133
134    /// Discover services with a specific protocol
135    pub async fn discover_services_with_protocol(
136        &self,
137        protocol_type: ProtocolType,
138        service_types: Vec<ServiceType>,
139        timeout: Option<Duration>,
140    ) -> Result<Vec<ServiceInfo>> {
141        if let Some(protocol) = self.protocols.get(&protocol_type) {
142            return protocol.discover_services(service_types, timeout).await;
143        }
144        Err(DiscoveryError::protocol(format!("Protocol {protocol_type:?} not available")))
145    }
146
147    /// Register a service with the appropriate protocol
148    pub async fn register_service(&self, service: ServiceInfo) -> Result<()> {
149        let protocol_type = service.protocol_type();
150        if let Some(protocol) = self.protocols.get(&protocol_type) {
151            return protocol.register_service(service).await;
152        }
153        
154        Err(DiscoveryError::protocol(format!(
155            "Protocol {protocol_type:?} not available"
156        )))
157    }
158
159    /// Unregister a service
160    pub async fn unregister_service(&self, service: &ServiceInfo) -> Result<()> {
161        let protocol_type = service.protocol_type();
162        if let Some(protocol) = self.protocols.get(&protocol_type) {
163            return protocol.unregister_service(service).await;
164        }
165        Err(DiscoveryError::protocol(format!(
166            "Protocol {protocol_type:?} not available"
167        )))
168    }
169
170    /// Verify a service is still available
171    pub async fn verify_service(&self, service: &ServiceInfo) -> Result<bool> {
172        let protocol_type = service.protocol_type();
173        if let Some(protocol) = self.protocols.get(&protocol_type) {
174            return protocol.verify_service(service).await;
175        }
176        Err(DiscoveryError::protocol(format!(
177            "Protocol {protocol_type:?} not available"
178        )))
179    }
180
181    /// Get a reference to the protocols map
182    pub fn protocols(&self) -> &HashMap<ProtocolType, Arc<dyn DiscoveryProtocol + Send + Sync>> {
183        &self.protocols
184    }
185
186    /// Perform a health check on all protocols
187    pub async fn health_check(&self) -> HashMap<ProtocolType, bool> {
188        let mut statuses = HashMap::new();
189        for (protocol_type, protocol) in &self.protocols {
190            statuses.insert(*protocol_type, protocol.is_available().await);
191        }
192        statuses
193    }
194}
195
196#[cfg(test)]
197mod tests {
198    use super::*;
199    use crate::config::DiscoveryConfig;
200
201    #[tokio::test]
202    async fn test_protocol_manager_creation() {
203        let config = DiscoveryConfig::new();
204        let manager = ProtocolManager::new(config).await;
205
206        // This might fail in test environment without proper network setup
207        match manager {
208            Ok(manager) => {
209                assert!(!manager.protocols.is_empty());
210            }
211            Err(_) => {
212                // Expected in some test environments
213            }
214        }
215    }
216
217    #[tokio::test]
218    async fn test_protocol_availability() {
219        let config = DiscoveryConfig::new().with_protocol(ProtocolType::Mdns);
220        if let Ok(manager) = ProtocolManager::new(config).await {
221            let protocols = manager.protocol_types();
222            assert!(!protocols.is_empty());
223        }
224    }
225
226    #[tokio::test]
227    async fn test_service_registration() {
228        let config = DiscoveryConfig::new().with_protocol(ProtocolType::Mdns);
229        let manager = ProtocolManager::new(config).await.unwrap();
230
231        let service = ServiceInfo::new(
232            "test_service",
233            "_http._tcp.local.",
234            8080,
235            Some(vec![("version", "1.0")])
236        )
237        .unwrap()
238        .with_protocol_type(ProtocolType::Mdns);
239
240        assert!(manager.register_service(service).await.is_ok());
241    }
242}