mdns/
resolve.rs

1//! Utilities for resolving a devices on the LAN.
2//!
3//! Examples
4//!
5//! ```rust,no_run
6//! use mdns::Error;
7//! use std::time::Duration;
8//!
9//! const SERVICE_NAME: &'static str = "_googlecast._tcp.local";
10//! const HOST: &'static str = "mycast._googlecast._tcp.local";
11//!
12//! #[async_std::main]
13//! async fn main() -> Result<(), Error> {
14//!     if let Some(response) = mdns::resolve::one(SERVICE_NAME, HOST, Duration::from_secs(15)).await? {
15//!         println!("{:?}", response);
16//!     }
17//!
18//!     Ok(())
19//! }
20//! ```
21
22use crate::{Error, Response};
23use futures_util::{StreamExt, pin_mut, TryFutureExt};
24use std::time::Duration;
25
26/// Resolve a single device by hostname
27pub async fn one<S>(
28    service_name: &str,
29    host_name: S,
30    timeout: Duration,
31) -> Result<Option<Response>, Error>
32where
33    S: AsRef<str>,
34{
35    // by setting the query interval higher than the timeout we ensure we only make one query
36    let stream = crate::discover::all(service_name, timeout * 2)?.listen();
37    pin_mut!(stream);
38
39    let process = async {
40        while let Some(Ok(response)) = stream.next().await {
41            match response.hostname() {
42                Some(found_host) if found_host == host_name.as_ref() => return Some(response),
43                _ => {}
44            }
45        }
46
47        None
48    };
49
50    async_std::future::timeout(timeout, process).map_err(|e| e.into()).await
51}
52
53/// Resolve multiple devices by hostname
54pub async fn multiple<S>(
55    service_name: &str,
56    host_names: &[S],
57    timeout: Duration,
58) -> Result<Vec<Response>, Error>
59where
60    S: AsRef<str>,
61{
62    // by setting the query interval higher than the timeout we ensure we only make one query
63    let stream = crate::discover::all(service_name, timeout * 2)?.listen();
64    pin_mut!(stream);
65
66    let mut found = Vec::new();
67
68    let process = async {
69        while let Some(Ok(response)) = stream.next().await {
70            match response.hostname() {
71                Some(found_host) if host_names.iter().any(|s| s.as_ref() == found_host) => {
72                    found.push(response);
73
74                    if found.len() == host_names.len() {
75                        return;
76                    }
77                }
78                _ => {}
79            }
80        }
81    };
82
83    match async_std::future::timeout(timeout, process).await {
84        Ok(()) => Ok(found),
85        Err(e) => Err(e.into())
86    }
87}