snapcast_client/
discovery.rs1use std::time::Duration;
4
5use anyhow::{Result, bail};
6
7#[derive(Debug, Clone)]
9pub struct Endpoint {
10 pub host: String,
12 pub port: u16,
14}
15
16pub async fn discover(timeout: Duration, service_type: &str) -> Result<Endpoint> {
18 let mdns = mdns_sd::ServiceDaemon::new()?;
19 let receiver = mdns.browse(service_type)?;
20
21 let deadline = tokio::time::Instant::now() + timeout;
22
23 loop {
24 let remaining = deadline.saturating_duration_since(tokio::time::Instant::now());
25 if remaining.is_zero() {
26 mdns.stop_browse(service_type).ok();
27 bail!("mDNS discovery timed out after {timeout:?}");
28 }
29
30 match tokio::time::timeout(remaining, async { receiver.recv_async().await }).await {
31 Ok(Ok(mdns_sd::ServiceEvent::ServiceResolved(info))) => {
32 let host = info
33 .get_addresses()
34 .iter()
35 .next()
36 .map(|a| a.to_string())
37 .unwrap_or_else(|| info.get_hostname().trim_end_matches('.').to_string());
38 let port = info.get_port();
39 tracing::info!(host = %host, port, "Discovered snapserver via mDNS");
40 mdns.stop_browse(service_type).ok();
41 return Ok(Endpoint { host, port });
42 }
43 Ok(Ok(_)) => continue, Ok(Err(e)) => {
45 mdns.stop_browse(service_type).ok();
46 bail!("mDNS receiver error: {e}");
47 }
48 Err(_) => {
49 mdns.stop_browse(service_type).ok();
50 bail!("mDNS discovery timed out after {timeout:?}");
51 }
52 }
53 }
54}