#[cfg(test)] mod resolver_test; use crate::error::*; use std::collections::HashMap; use std::future::Future; use std::net::IpAddr; use std::pin::Pin; use std::str::FromStr; use std::sync::Arc; use tokio::sync::Mutex; #[derive(Default)] pub(crate) struct Resolver { parent: Option>>, hosts: HashMap, } impl Resolver { pub(crate) fn new() -> Self { let mut r = Resolver { parent: None, hosts: HashMap::new(), }; if let Err(err) = r.add_host("localhost".to_owned(), "127.0.0.1".to_owned()) { log::warn!("failed to add localhost to Resolver: {}", err); } r } pub(crate) fn set_parent(&mut self, p: Arc>) { self.parent = Some(p); } pub(crate) fn add_host(&mut self, name: String, ip_addr: String) -> Result<()> { if name.is_empty() { return Err(Error::ErrHostnameEmpty); } let ip = IpAddr::from_str(&ip_addr)?; self.hosts.insert(name, ip); Ok(()) } pub(crate) fn lookup( &self, host_name: String, ) -> Pin> + Send + 'static>> { if let Some(ip) = self.hosts.get(&host_name) { let ip2 = *ip; return Box::pin(async move { Some(ip2) }); } // mutex must be unlocked before calling into parent Resolver if let Some(parent) = &self.parent { let parent2 = Arc::clone(parent); Box::pin(async move { let p = parent2.lock().await; p.lookup(host_name).await }) } else { Box::pin(async move { None }) } } }