saluki_io/net/dns/
hyper.rs1use std::{
2 future::Future,
3 net::{IpAddr, SocketAddr},
4 pin::Pin,
5 sync::Arc,
6 task::{Context, Poll},
7};
8
9use hickory_resolver::{net::NetError, TokioResolver};
10use hyper_util::client::legacy::connect::{dns::Name, HttpConnector};
11use saluki_error::{ErrorContext as _, GenericError};
12use tower::Service;
13
14pub type HickoryHttpConnector = HttpConnector<HickoryResolver>;
16
17#[derive(Clone)]
19pub struct HickoryResolver {
20 resolver: Arc<TokioResolver>,
21}
22
23impl HickoryResolver {
24 pub fn from_system_conf() -> Result<Self, GenericError> {
34 let resolver = TokioResolver::builder_tokio()
35 .error_context("Failed to load the system resolver configuration.")?
36 .build()
37 .error_context("Failed to build the resolver.")?;
38
39 Ok(Self {
40 resolver: Arc::new(resolver),
41 })
42 }
43
44 pub fn into_http_connector(self) -> HickoryHttpConnector {
46 HickoryHttpConnector::new_with_resolver(self)
47 }
48}
49
50impl Service<Name> for HickoryResolver {
51 type Response = SocketAddrs;
52 type Error = NetError;
53
54 type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>> + Send>>;
55
56 fn poll_ready(&mut self, _cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
57 Poll::Ready(Ok(()))
58 }
59
60 fn call(&mut self, name: Name) -> Self::Future {
61 let resolver = self.resolver.clone();
62
63 Box::pin(async move {
64 let response = resolver.lookup_ip(name.as_str()).await?;
65 Ok(response.iter().collect())
66 })
67 }
68}
69
70pub struct SocketAddrs(Vec<IpAddr>);
71
72impl Iterator for SocketAddrs {
73 type Item = SocketAddr;
74
75 fn next(&mut self) -> Option<Self::Item> {
76 self.0.pop().map(|ip| SocketAddr::new(ip, 0))
77 }
78}
79
80impl FromIterator<IpAddr> for SocketAddrs {
81 fn from_iter<I: IntoIterator<Item = IpAddr>>(iter: I) -> Self {
82 Self(iter.into_iter().collect())
83 }
84}