//! This example shows how to create a resolver that uses the tokio multithreaded runtime. This is how //! you might integrate the resolver into a more complex application. fn main() { tracing_subscriber::fmt::init(); run(); } fn run() { use tokio::runtime::Runtime; // Set up the standard tokio runtime (multithreaded by default). let runtime = Runtime::new().expect("Failed to create runtime"); let resolver = { // To make this independent, if targeting macOS, BSD, Linux, or Windows, we can use the system's configuration: #[cfg(any(unix, windows))] { use hickory_resolver::{TokioResolver, net::runtime::TokioRuntimeProvider}; // use the system resolver configuration TokioResolver::builder(TokioRuntimeProvider::default()) .expect("failed to create resolver") .build() .unwrap() } // For other operating systems, we can use one of the preconfigured definitions #[cfg(not(any(unix, windows)))] { // Directly reference the config types use hickory_resolver::{ Resolver, config::{GOOGLE, ResolverConfig, ResolverOpts}, }; // Get a new resolver with the google nameservers as the upstream recursive resolvers Resolver::tokio(ResolverConfig::udp_and_tcp(), ResolverOpts::default()) } }; // Create some futures representing name lookups. let names = &["www.google.com", "www.reddit.com", "www.wikipedia.org"]; let mut futures = names .iter() .map(|name| (name, resolver.lookup_ip(*name))) .collect::>(); // Go through the list of resolution operations and wait for them to complete. for (name, lookup) in futures.drain(..) { let ips = runtime .block_on(lookup) .expect("Failed completing lookup future") .iter() .collect::>(); println!("{name} resolved to {ips:?}"); } // Drop the resolver, which means that the runtime will become idle. drop(futures); drop(resolver); } #[test] fn test_multithreaded_runtime() { test_support::subscribe(); run() }