actix_connector/
resolver.rs

1use std::collections::VecDeque;
2use std::marker::PhantomData;
3use std::net::IpAddr;
4
5use actix_service::Service;
6use futures::{Async, Future, Poll};
7use trust_dns_resolver::config::{ResolverConfig, ResolverOpts};
8pub use trust_dns_resolver::error::ResolveError;
9use trust_dns_resolver::lookup_ip::LookupIpFuture;
10use trust_dns_resolver::system_conf::read_system_conf;
11use trust_dns_resolver::{AsyncResolver, Background};
12
13/// Host name of the request
14pub trait RequestHost {
15    fn host(&self) -> &str;
16}
17
18impl RequestHost for String {
19    fn host(&self) -> &str {
20        self.as_ref()
21    }
22}
23
24pub struct Resolver<T = String> {
25    resolver: AsyncResolver,
26    req: PhantomData<T>,
27}
28
29impl<T: RequestHost> Default for Resolver<T> {
30    fn default() -> Self {
31        let (cfg, opts) = if let Ok((cfg, opts)) = read_system_conf() {
32            (cfg, opts)
33        } else {
34            (ResolverConfig::default(), ResolverOpts::default())
35        };
36
37        Resolver::new(cfg, opts)
38    }
39}
40
41impl<T: RequestHost> Resolver<T> {
42    /// Create new resolver instance with custom configuration and options.
43    pub fn new(cfg: ResolverConfig, opts: ResolverOpts) -> Self {
44        let (resolver, bg) = AsyncResolver::new(cfg, opts);
45        tokio_current_thread::spawn(bg);
46        Resolver {
47            resolver,
48            req: PhantomData,
49        }
50    }
51
52    /// Change type of resolver request.
53    pub fn into_request<T2: RequestHost>(&self) -> Resolver<T2> {
54        Resolver {
55            resolver: self.resolver.clone(),
56            req: PhantomData,
57        }
58    }
59}
60
61impl<T> Clone for Resolver<T> {
62    fn clone(&self) -> Self {
63        Resolver {
64            resolver: self.resolver.clone(),
65            req: PhantomData,
66        }
67    }
68}
69
70impl<T: RequestHost> Service for Resolver<T> {
71    type Request = T;
72    type Response = (T, VecDeque<IpAddr>);
73    type Error = ResolveError;
74    type Future = ResolverFuture<T>;
75
76    fn poll_ready(&mut self) -> Poll<(), Self::Error> {
77        Ok(Async::Ready(()))
78    }
79
80    fn call(&mut self, req: T) -> Self::Future {
81        if let Ok(ip) = req.host().parse() {
82            let mut addrs = VecDeque::new();
83            addrs.push_back(ip);
84            ResolverFuture::new(req, &self.resolver, Some(addrs))
85        } else {
86            ResolverFuture::new(req, &self.resolver, None)
87        }
88    }
89}
90
91#[doc(hidden)]
92/// Resolver future
93pub struct ResolverFuture<T> {
94    req: Option<T>,
95    lookup: Option<Background<LookupIpFuture>>,
96    addrs: Option<VecDeque<IpAddr>>,
97}
98
99impl<T: RequestHost> ResolverFuture<T> {
100    pub fn new(addr: T, resolver: &AsyncResolver, addrs: Option<VecDeque<IpAddr>>) -> Self {
101        // we need to do dns resolution
102        let lookup = Some(resolver.lookup_ip(addr.host()));
103        ResolverFuture {
104            lookup,
105            addrs,
106            req: Some(addr),
107        }
108    }
109}
110
111impl<T: RequestHost> Future for ResolverFuture<T> {
112    type Item = (T, VecDeque<IpAddr>);
113    type Error = ResolveError;
114
115    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
116        if let Some(addrs) = self.addrs.take() {
117            Ok(Async::Ready((self.req.take().unwrap(), addrs)))
118        } else {
119            match self.lookup.as_mut().unwrap().poll() {
120                Ok(Async::NotReady) => Ok(Async::NotReady),
121                Ok(Async::Ready(ips)) => Ok(Async::Ready((
122                    self.req.take().unwrap(),
123                    ips.iter().collect(),
124                ))),
125                Err(err) => Err(err),
126            }
127        }
128    }
129}