Skip to content

Commit

Permalink
add methods for resolving known hosts instead of discovering all hosts
Browse files Browse the repository at this point in the history
  • Loading branch information
icewind1991 committed Jan 28, 2020
1 parent 470b01f commit e14ae12
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 0 deletions.
18 changes: 18 additions & 0 deletions examples/resolve_hosts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
use mdns::Error;
use std::time::Duration;

const SERVICE_NAME: &'static str = "_http._tcp.local";
const HOSTS: [&'static str; 2] = ["server1._http._tcp.local", "server2._http._tcp.local"];

#[tokio::main]
async fn main() -> Result<(), Error> {
let responses = mdns::resolve::multiple(SERVICE_NAME, &HOSTS, Duration::from_secs(15)).await?;

for response in responses {
if let (Some(host), Some(ip)) = (response.hostname(), response.ip_addr()) {
println!("found host {} at {}", host, ip)
}
}

Ok(())
}
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ pub use self::errors::Error;
pub use self::response::{Record, RecordKind, Response};

pub mod discover;
pub mod resolve;

mod errors;
mod mdns;
Expand Down
89 changes: 89 additions & 0 deletions src/resolve.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
//! Utilities for resolving a devices on the LAN.
//!
//! Examples
//!
//! ```rust,no_run
//! use mdns::Error;
//! use std::time::Duration;
//!
//! const SERVICE_NAME: &'static str = "_googlecast._tcp.local";
//! const HOST: &'static str = "mycast._googlecast._tcp.local";
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Error> {
//! if let Some(response) = mdns::resolve::one(SERVICE_NAME, HOST, Duration::from_secs(15)).await? {
//! println!("{:?}", response);
//! }
//!
//! Ok(())
//! }
//! ```
use crate::{Error, Response};
use futures_util::pin_mut;
use futures_util::StreamExt;
use std::time::Duration;

/// Resolve a single device by hostname
pub async fn one<S>(
service_name: &str,
host_name: S,
timeout: Duration,
) -> Result<Option<Response>, Error>
where
S: AsRef<str>,
{
// by setting the query interval higher than the timeout we ensure we only make one query
let stream = crate::discover::all(service_name, timeout * 2)?.listen();
pin_mut!(stream);

let process = async {
while let Some(Ok(response)) = stream.next().await {
match response.hostname() {
Some(found_host) if found_host == host_name.as_ref() => return Some(response),
_ => {}
}
}

None
};

Ok(match tokio::time::timeout(timeout, process).await {
Ok(result) => result,
Err(_) => None,
})
}

/// Resolve multiple devices by hostname
pub async fn multiple<S>(
service_name: &str,
host_names: &[S],
timeout: Duration,
) -> Result<Vec<Response>, Error>
where
S: AsRef<str>,
{
// by setting the query interval higher than the timeout we ensure we only make one query
let stream = crate::discover::all(service_name, timeout * 2)?.listen();
pin_mut!(stream);

let mut found = Vec::new();

let process = async {
while let Some(Ok(response)) = stream.next().await {
match response.hostname() {
Some(found_host) if host_names.iter().any(|s| s.as_ref() == found_host) => {
found.push(response);

if found.len() == host_names.len() {
return;
}
}
_ => {}
}
}
};

let _ = tokio::time::timeout(timeout, process).await;
Ok(found)
}

0 comments on commit e14ae12

Please sign in to comment.