aws_smithy_runtime/client/dns/
caching.rs1use std::{
7 io::{Error as IoError, ErrorKind as IoErrorKind},
8 net::IpAddr,
9 time::Duration,
10};
11
12use aws_smithy_runtime_api::client::dns::{DnsFuture, ResolveDns, ResolveDnsError};
13use hickory_resolver::{
14 config::{NameServerConfigGroup, ResolverConfig},
15 name_server::TokioConnectionProvider,
16 Resolver,
17};
18
19#[non_exhaustive]
23#[derive(Debug)]
24pub struct CachingDnsResolver {
25 resolver: Resolver<TokioConnectionProvider>,
26}
27
28impl Default for CachingDnsResolver {
29 fn default() -> Self {
32 Self {
33 resolver: Resolver::builder_tokio().expect("In tokio runtime").build(),
34 }
35 }
36}
37
38impl CachingDnsResolver {
39 pub fn builder() -> CachingDnsResolverBuilder {
41 CachingDnsResolverBuilder {
42 nameservers: None,
43 timeout: None,
44 attempts: None,
45 cache_size: None,
46 num_concurrent_reqs: None,
47 }
48 }
49
50 pub fn clear_cache(&self) {
52 self.resolver.clear_cache();
53 }
54}
55
56impl ResolveDns for CachingDnsResolver {
57 fn resolve_dns<'a>(&'a self, name: &'a str) -> DnsFuture<'a> {
58 DnsFuture::new(async move {
59 let result = self.resolver.lookup_ip(name).await;
60
61 match result {
62 Ok(ips) => Ok(ips.into_iter().collect()),
63 Err(failure) => Err(ResolveDnsError::new(IoError::new(
64 IoErrorKind::Other,
65 failure,
66 ))),
67 }
68 })
69 }
70}
71
72pub struct CachingDnsResolverBuilder {
73 nameservers: Option<Nameservers>,
74 timeout: Option<Duration>,
75 attempts: Option<usize>,
76 cache_size: Option<usize>,
77 num_concurrent_reqs: Option<usize>,
78}
79
80struct Nameservers {
81 ips: Vec<IpAddr>,
82 port: u16,
83}
84
85impl CachingDnsResolverBuilder {
86 pub fn nameservers(mut self, ips: &[IpAddr], port: u16) -> Self {
89 self.nameservers = Some(Nameservers {
90 ips: ips.to_vec(),
91 port,
92 });
93 self
94 }
95
96 pub fn timeout(mut self, timeout: Duration) -> Self {
98 self.timeout = Some(timeout);
99 self
100 }
101
102 pub fn attempts(mut self, attempts: usize) -> Self {
104 self.attempts = Some(attempts);
105 self
106 }
107
108 pub fn cache_size(mut self, cache_size: usize) -> Self {
110 self.cache_size = Some(cache_size);
111 self
112 }
113
114 pub fn num_concurrent_reqs(mut self, num_concurrent_reqs: usize) -> Self {
120 self.num_concurrent_reqs = Some(num_concurrent_reqs);
121 self
122 }
123
124 pub fn build(self) -> CachingDnsResolver {
125 let mut builder = if let Some(nameservers) = self.nameservers {
126 let nameserver_config =
127 NameServerConfigGroup::from_ips_clear(&nameservers.ips, nameservers.port, true);
128 let resolver_config = ResolverConfig::from_parts(None, vec![], nameserver_config);
129
130 Resolver::builder_with_config(resolver_config, TokioConnectionProvider::default())
131 } else {
132 Resolver::builder_tokio().expect("Successfully read system config")
133 };
134
135 let opts = builder.options_mut();
136
137 if let Some(timeout) = self.timeout {
138 opts.timeout = timeout;
139 }
140
141 if let Some(attempts) = self.attempts {
142 opts.attempts = attempts;
143 }
144
145 if let Some(cache_size) = self.cache_size {
146 opts.cache_size = cache_size;
147 }
148
149 if let Some(num_concurrent_reqs) = self.num_concurrent_reqs {
150 opts.num_concurrent_reqs = num_concurrent_reqs;
151 }
152
153 CachingDnsResolver {
154 resolver: builder.build(),
155 }
156 }
157}