use std::future::Future;
use std::net::SocketAddr;
use std::pin::Pin;
use std::sync::Arc;
use crate::EngineError;
pub type DnsResolveFuture<'a> =
Pin<Box<dyn Future<Output = Result<Vec<SocketAddr>, EngineError>> + Send + 'a>>;
pub trait DnsResolver: Send + Sync + std::fmt::Debug {
fn resolve<'a>(&'a self, host: &'a str, port: u16) -> DnsResolveFuture<'a>;
}
#[derive(Debug, Clone)]
pub struct StaticDnsResolver {
addrs: Vec<SocketAddr>,
}
impl StaticDnsResolver {
#[must_use]
pub fn new(addrs: Vec<SocketAddr>) -> Self {
Self { addrs }
}
#[must_use]
pub fn single(addr: SocketAddr) -> Self {
Self { addrs: vec![addr] }
}
}
impl DnsResolver for StaticDnsResolver {
fn resolve<'a>(&'a self, _host: &'a str, _port: u16) -> DnsResolveFuture<'a> {
let addrs = self.addrs.clone();
Box::pin(async move { Ok(addrs) })
}
}
#[must_use]
pub fn arc_dns_resolver<R: DnsResolver + 'static>(resolver: R) -> Arc<dyn DnsResolver> {
Arc::new(resolver)
}
#[cfg(test)]
mod tests {
use std::net::{IpAddr, Ipv4Addr};
use super::*;
#[tokio::test(flavor = "current_thread")]
async fn static_resolver_returns_its_address() {
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 6650);
let r = StaticDnsResolver::single(addr);
let out = r.resolve("ignored", 6650).await.expect("resolve ok");
assert_eq!(out, vec![addr]);
}
#[tokio::test(flavor = "current_thread")]
async fn static_resolver_returns_all_addrs_in_order() {
let a = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 6650);
let b = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 2)), 6650);
let r = StaticDnsResolver::new(vec![a, b]);
let out = r.resolve("ignored", 6650).await.expect("resolve ok");
assert_eq!(out, vec![a, b]);
}
#[test]
fn arc_wrapper_smoke() {
let addr = SocketAddr::new(IpAddr::V4(Ipv4Addr::LOCALHOST), 6650);
let r = arc_dns_resolver(StaticDnsResolver::single(addr));
assert!(Arc::strong_count(&r) >= 1);
}
}