auto_discovery/
simple.rs

1//! Simplified API for common use cases
2//!
3//! This module provides simplified, zero-configuration APIs for the most common
4//! service discovery scenarios.
5
6use crate::{
7    config::DiscoveryConfig,
8    error::Result,
9    service::ServiceInfo,
10    types::{ServiceType, ProtocolType},
11    ServiceDiscovery,
12};
13use std::time::Duration;
14
15/// Simple service discovery with sensible defaults
16pub struct SimpleDiscovery {
17    inner: ServiceDiscovery,
18}
19
20impl SimpleDiscovery {
21    /// Create a new simple discovery instance with defaults
22    /// 
23    /// Automatically configures:
24    /// - mDNS protocol 
25    /// - Common service types (_http._tcp, _https._tcp, _ssh._tcp, _ftp._tcp)
26    /// - 5-second timeout
27    /// - Service verification enabled
28    /// 
29    /// # Example
30    /// ```rust
31    /// use auto_discovery::simple::SimpleDiscovery;
32    /// 
33    /// #[tokio::main]
34    /// async fn main() -> Result<(), Box<dyn std::error::Error>> {
35    ///     let discovery = SimpleDiscovery::new().await?;
36    ///     let services = discovery.discover_all().await?;
37    ///     println!("Found {} services", services.len());
38    ///     Ok(())
39    /// }
40    /// ```
41    pub async fn new() -> Result<Self> {
42        let config = DiscoveryConfig::new()
43            .with_service_type(ServiceType::new("_http._tcp")?)
44            .with_service_type(ServiceType::new("_https._tcp")?)
45            .with_service_type(ServiceType::new("_ssh._tcp")?)
46            .with_service_type(ServiceType::new("_ftp._tcp")?)
47            .with_protocol(ProtocolType::Mdns)
48            .with_timeout(Duration::from_secs(5))
49            .with_verify_services(true);
50
51        let inner = ServiceDiscovery::new(config).await?;
52        Ok(Self { inner })
53    }
54
55    /// Discover all configured services
56    pub async fn discover_all(&self) -> Result<Vec<ServiceInfo>> {
57        self.inner.discover_services(None).await
58    }
59
60    /// Discover only HTTP services
61    pub async fn discover_http(&self) -> Result<Vec<ServiceInfo>> {
62        self.inner.discover_services(Some(ProtocolType::Mdns)).await
63    }
64
65    /// Register a simple HTTP service
66    /// 
67    /// # Example
68    /// ```rust
69    /// # use auto_discovery::simple::SimpleDiscovery;
70    /// # #[tokio::main] 
71    /// # async fn main() -> Result<(), Box<dyn std::error::Error>> {
72    /// let discovery = SimpleDiscovery::new().await?;
73    /// discovery.register_http_service("My Web App", 8080).await?;
74    /// # Ok(())
75    /// # }
76    /// ```
77    pub async fn register_http_service(&self, name: &str, port: u16) -> Result<()> {
78        let service = ServiceInfo::new(name, "_http._tcp", port, None)?;
79        self.inner.register_service(service).await
80    }
81
82    /// Register a service with custom attributes
83    pub async fn register_service_with_attributes(
84        &self, 
85        name: &str, 
86        service_type: &str, 
87        port: u16,
88        attributes: Vec<(&str, &str)>
89    ) -> Result<()> {
90        let service = ServiceInfo::new(name, service_type, port, Some(attributes))?;
91        self.inner.register_service(service).await
92    }
93
94    /// Stop all services and cleanup
95    pub async fn shutdown(&self) -> Result<()> {
96        // Unregister all services
97        let services = self.inner.get_registered_services().await;
98        for service in services {
99            let _ = self.inner.unregister_service(&service).await;
100        }
101        Ok(())
102    }
103}
104
105/// Quick one-liner functions for common scenarios
106///
107/// Discover all HTTP services on the network
108/// 
109/// # Example
110/// ```rust
111/// use auto_discovery::simple::discover_http_services;
112/// 
113/// #[tokio::main]
114/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
115///     let services = discover_http_services().await?;
116///     for service in services {
117///         println!("Found: {} at {}:{}", service.name(), service.address, service.port);
118///     }
119///     Ok(())
120/// }
121/// ```
122pub async fn discover_http_services() -> Result<Vec<ServiceInfo>> {
123    let discovery = SimpleDiscovery::new().await?;
124    discovery.discover_http().await
125}
126
127/// Register an HTTP service and return a handle for cleanup
128/// 
129/// # Example
130/// ```rust
131/// use auto_discovery::simple::register_http_service;
132/// 
133/// #[tokio::main]
134/// async fn main() -> Result<(), Box<dyn std::error::Error>> {
135///     let handle = register_http_service("My API", 8080).await?;
136///     
137///     // Your server code here
138///     
139///     handle.unregister().await?;
140///     Ok(())
141/// }
142/// ```
143pub async fn register_http_service(name: &str, port: u16) -> Result<ServiceHandle> {
144    let discovery = SimpleDiscovery::new().await?;
145    let service = ServiceInfo::new(name, "_http._tcp", port, None)?;
146    discovery.inner.register_service(service.clone()).await?;
147    Ok(ServiceHandle { 
148        discovery: discovery.inner,
149        service,
150    })
151}
152
153/// Handle for managing a registered service
154pub struct ServiceHandle {
155    discovery: ServiceDiscovery,
156    service: ServiceInfo,
157}
158
159impl ServiceHandle {
160    /// Unregister the service
161    pub async fn unregister(self) -> Result<()> {
162        self.discovery.unregister_service(&self.service).await
163    }
164
165    /// Get service information
166    pub fn service(&self) -> &ServiceInfo {
167        &self.service
168    }
169}
170
171#[cfg(test)]
172mod tests {
173    use super::*;
174
175    #[tokio::test]
176    async fn test_simple_discovery() {
177        let discovery = SimpleDiscovery::new().await.unwrap();
178        
179        // Should not fail even if no services found
180        let services = discovery.discover_all().await.unwrap();
181        // Can't assert specific count since it depends on network
182        assert!(!services.is_empty() || services.is_empty()); // services can be empty in test environment
183    }
184
185    #[tokio::test]
186    async fn test_register_http_service() {
187        let discovery = SimpleDiscovery::new().await.unwrap();
188        let result = discovery.register_http_service("Test Service", 8080).await;
189        
190        // Registration might fail in test environment
191        match result {
192            Ok(_) => {
193                // Service registered successfully
194            }
195            Err(_) => {
196                // Expected in test environment without actual mDNS
197            }
198        }
199    }
200
201    #[tokio::test]
202    async fn test_one_liner_functions() {
203        // Test the one-liner function
204        let result = discover_http_services().await;
205        
206        // Should not panic even if discovery fails
207        match result {
208            Ok(_services) => {
209                // Success case
210            }
211            Err(_) => {
212                // Expected in test environment
213            }
214        }
215    }
216}