hyper_system_resolver/
system.rs1use std::{io, net::SocketAddr, vec};
4
5use dns_lookup::AddrInfoHints;
6use hyper::client::connect::dns::Name;
7use tokio::task::JoinHandle;
8
9use crate::background;
10
11#[derive(Debug, Builder, Default, Clone)]
17pub struct System {
18 pub addr_info_hints: Option<AddrInfoHints>,
25
26 pub service: Option<String>,
35}
36
37impl background::Resolve for System {
38 type Iter = vec::IntoIter<SocketAddr>;
39
40 fn resolve(&mut self, name: Name) -> JoinHandle<io::Result<Self::Iter>> {
41 let addr_info_hints = self.addr_info_hints;
42 let service = self.service.clone();
43 tokio::task::spawn_blocking(move || {
44 debug!("resolving host={:?} service={:?}", name, service);
45
46 let iter = dns_lookup::getaddrinfo(Some(name.as_str()), service.as_deref(), addr_info_hints)?;
47 let list = iter
48 .map(|result| result.map(|addr_info| addr_info.sockaddr))
49 .collect::<Result<Vec<_>, _>>()?;
50 Ok(list.into_iter())
51 })
52 }
53}
54
55pub type Resolver = background::Resolver<System>;
57
58impl System {
59 pub fn resolver(self) -> Resolver {
61 Resolver::new(self)
62 }
63}
64
65impl From<System> for Resolver {
66 fn from(system: System) -> Self {
67 system.resolver()
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use std::{
74 net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6},
75 str::FromStr,
76 };
77
78 use tower_service::Service;
79
80 use super::*;
81
82 #[tokio::test]
83 async fn test_resolve_ipv4() {
84 let mut resolver = background::Resolver::new(System {
85 addr_info_hints: Some(
86 AddrInfoHints {
87 address: dns_lookup::AddrFamily::Inet.into(),
88 ..Default::default()
89 }
90 ),
91 service: None,
92 });
93
94 let addrs: Vec<_> = resolver
95 .call(Name::from_str("localhost").unwrap())
96 .await
97 .unwrap()
98 .collect();
99
100 let localhost = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(127, 0, 0, 1), 0));
101
102 assert!(!addrs.is_empty());
103 for addr in addrs {
104 assert_eq!(addr, localhost);
105 }
106 }
107
108 #[tokio::test]
109 async fn test_resolve_ipv6() {
110 let mut resolver = background::Resolver::new(System {
111 addr_info_hints: Some(AddrInfoHints {
112 address: dns_lookup::AddrFamily::Inet6.into(),
113 ..Default::default()
114 }),
115 service: None,
116 });
117
118 let addrs: Vec<_> = resolver
119 .call(Name::from_str("localhost").unwrap())
120 .await
121 .unwrap()
122 .collect();
123
124 let localhost = SocketAddr::V6(SocketAddrV6::new(
125 Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1),
126 0,
127 0,
128 0,
129 ));
130
131 assert!(!addrs.is_empty());
132 for addr in addrs {
133 assert_eq!(addr, localhost);
134 }
135 }
136}