Repository: actix/actix (language: rust)

Issue:
Remove resolver actor from actix
## Expected Behavior
actix as an actor framework should not be bind to a dns dependency.
I believe majority people don't use that feature or they would be fine to move that feature to user code base.

## Current Behavior
actix was blocked from update to tokio 1.0 because the said dep is still not ready.
At this point actix is unblocked but the point still stands.

## Possible Solution
Remove the feature.



Discussion / hints:
Would love to take a crack at it, if this issue isn't stale or superseded (@fakeshadow ?).
> 
> 
> Would love to take a crack at it, if this issue isn't stale or superseded (@fakeshadow ?).

An related PR was made to deprecate the feature. 

PR is welcome to actually remove it since there is no opposing response for doing so.
Okay. I'm going to attempt to create the changes with a related PR this weekend. Would it be desired to have the functionality still in a separate crate or is the whole feature already deprecated?
if anyone still needs it they can rip the code from the old versions
kay

Fix patch:
diff --git a/actix/CHANGES.md b/actix/CHANGES.md
index 9e43ae2da..059dfa4d2 100644
--- a/actix/CHANGES.md
+++ b/actix/CHANGES.md
@@ -1,7 +1,8 @@
 # CHANGES
 
 ## Unreleased - 2021-xx-xx
-
+### Removed
+- Removed `Resolver` actor [#451]
 
 ## 0.12.0 - 2021-06-06
 ### Added
@@ -20,7 +21,6 @@
 [#499]: https://github.com/actix/actix/pull/499
 [#501]: https://github.com/actix/actix/pull/501
 
-
 ## 0.11.1 - 2021-03-23
 ### Fixed
 * Panics caused by instant cancellation of a spawned future. [#484]
diff --git a/actix/Cargo.toml b/actix/Cargo.toml
index 5ea25d1f1..b86499745 100644
--- a/actix/Cargo.toml
+++ b/actix/Cargo.toml
@@ -25,9 +25,6 @@ default = ["macros"]
 # Re-exports derive macros from actix-derive and enables `#[actix::main]`.
 macros = ["actix_derive"]
 
-# DNS resolver
-resolver = ["trust-dns-proto", "trust-dns-resolver"]
-
 # Adds assertion to prevent processing too many messages on event loop
 mailbox_assert = []
 
@@ -50,10 +47,6 @@ smallvec = "1.6.1"
 tokio = { version = "1", features = ["io-util", "sync"] }
 tokio-util = { version = "0.6", features = ["codec"] }
 
-# dns resolver
-trust-dns-proto = { version = "0.20.0" , optional = true, default-features = false, features = ["tokio-runtime"] }
-trust-dns-resolver = { version = "0.20.0" , optional = true, default-features = false, features = ["tokio-runtime", "system-config"] }
-
 [dev-dependencies]
 doc-comment = "0.3"
 futures-util = { version = "0.3.7", default-features = false, features = ["alloc"] }
diff --git a/actix/src/actors/mod.rs b/actix/src/actors/mod.rs
index 374fd1db6..ccdb8b783 100644
--- a/actix/src/actors/mod.rs
+++ b/actix/src/actors/mod.rs
@@ -1,10 +1,3 @@
 //! Helper actors
 
 pub mod mocker;
-
-#[cfg(feature = "resolver")]
-#[deprecated(
-    since = "0.11.0",
-    note = "Resolver actor is deprecated and will be removed in a future release."
-)]
-pub mod resolver;
diff --git a/actix/src/actors/resolver.rs b/actix/src/actors/resolver.rs
deleted file mode 100644
index 1deb37287..000000000
--- a/actix/src/actors/resolver.rs
+++ /dev/null
@@ -1,433 +0,0 @@
-//! DNS resolver and connector utility actor
-//!
-//! # Examples
-//! ```
-//! # #![allow(deprecated)]
-//! use actix::actors::resolver;
-//! use actix::prelude::*;
-//!
-//! #[actix::main]
-//! async fn main() {
-//!     actix::spawn(async {
-//!         let resolver = resolver::Resolver::from_registry();
-//!         let addrs = resolver
-//!             .send(resolver::Resolve::host("localhost"))
-//!             .await
-//!             .unwrap();
-//!
-//!         println!("RESULT: {:?}", addrs);
-//!     });
-//!
-//!     let resolver = resolver::Resolver::from_registry();
-//!     let addrs = resolver
-//!         .send(resolver::Connect::host_and_port("localhost", 5000))
-//!         .await
-//!         .unwrap();
-//!     println!("RESULT: {:?}", addrs);
-//! }
-//! ```
-
-use std::collections::VecDeque;
-use std::fmt;
-use std::future::Future;
-use std::io;
-use std::net::SocketAddr;
-use std::pin::Pin;
-use std::task::{self, Poll};
-use std::time::Duration;
-
-use futures_util::future::Either;
-use pin_project_lite::pin_project;
-use tokio::net::TcpStream;
-use trust_dns_resolver::config::{ResolverConfig, ResolverOpts};
-use trust_dns_resolver::TokioAsyncResolver as AsyncResolver;
-use trust_dns_resolver::{error::ResolveError, lookup_ip::LookupIp};
-
-use crate::clock::Sleep;
-use crate::fut::ActorFuture;
-use crate::prelude::*;
-
-#[deprecated(since = "0.7.0", note = "please use `Resolver` instead")]
-pub type Connector = Resolver;
-
-#[deprecated(since = "0.7.0", note = "please use `ResolverError` instead")]
-pub type ConnectorError = ResolverError;
-
-#[derive(Eq, PartialEq, Debug)]
-pub struct Resolve {
-    pub name: String,
-    pub port: Option<u16>,
-}
-
-impl Resolve {
-    pub fn host<T: AsRef<str>>(host: T) -> Resolve {
-        Resolve {
-            name: host.as_ref().to_owned(),
-            port: None,
-        }
-    }
-
-    pub fn host_and_port<T: AsRef<str>>(host: T, port: u16) -> Resolve {
-        Resolve {
-            name: host.as_ref().to_owned(),
-            port: Some(port),
-        }
-    }
-}
-
-impl Message for Resolve {
-    type Result = Result<VecDeque<SocketAddr>, ResolverError>;
-}
-
-#[derive(Eq, PartialEq, Debug)]
-pub struct Connect {
-    pub name: String,
-    pub port: Option<u16>,
-    pub timeout: Duration,
-}
-
-impl Connect {
-    pub fn host<T: AsRef<str>>(host: T) -> Connect {
-        Connect {
-            name: host.as_ref().to_owned(),
-            port: None,
-            timeout: Duration::from_secs(1),
-        }
-    }
-
-    pub fn host_and_port<T: AsRef<str>>(host: T, port: u16) -> Connect {
-        Connect {
-            name: host.as_ref().to_owned(),
-            port: Some(port),
-            timeout: Duration::from_secs(1),
-        }
-    }
-
-    /// Set connect timeout
-    ///
-    /// By default timeout is set to a 1 second.
-    pub fn timeout(mut self, timeout: Duration) -> Connect {
-        self.timeout = timeout;
-        self
-    }
-}
-
-impl Message for Connect {
-    type Result = Result<TcpStream, ResolverError>;
-}
-
-#[derive(Eq, PartialEq, Debug)]
-pub struct ConnectAddr(pub SocketAddr);
-
-impl Message for ConnectAddr {
-    type Result = Result<TcpStream, ResolverError>;
-}
-
-#[derive(Debug)]
-pub enum ResolverError {
-    /// Failed to resolve the hostname
-    Resolver(String),
-
-    /// Address is invalid
-    InvalidInput(&'static str),
-
-    /// Connecting took too long
-    Timeout,
-
-    /// Connection io error
-    IoError(io::Error),
-}
-
-impl fmt::Display for ResolverError {
-    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self {
-            ResolverError::Resolver(s) => write!(fmt, "Failed resolving hostname: {}", s),
-            ResolverError::InvalidInput(s) => write!(fmt, "Invalid input: {}", s),
-            ResolverError::Timeout => write!(fmt, "Timeout out while establishing connection"),
-            ResolverError::IoError(e) => write!(fmt, "{}", e),
-        }
-    }
-}
-
-#[deprecated(
-    since = "0.11.0",
-    note = "Resolver actor is deprecated and will be removed in a future release."
-)]
-pub struct Resolver {
-    resolver: Option<AsyncResolver>,
-    cfg: Option<(ResolverConfig, ResolverOpts)>,
-    err: Option<String>,
-}
-
-impl Resolver {
-    pub fn new(config: ResolverConfig, options: ResolverOpts) -> Resolver {
-        Resolver {
-            resolver: None,
-            cfg: Some((config, options)),
-            err: None,
-        }
-    }
-}
-
-impl Actor for Resolver {
-    type Context = Context<Self>;
-    fn started(&mut self, ctx: &mut Self::Context) {
-        let cfg = self.cfg.take();
-        ctx.wait(async move { cfg }.into_actor(self).map(|cfg, this, _| {
-            let resolver = match cfg {
-                Some((conf, opt)) => AsyncResolver::tokio(conf, opt),
-                None => match AsyncResolver::tokio_from_system_conf() {
-                    Ok(resolver) => Ok(resolver),
-                    Err(err) => {
-                        log::warn!("Can not create system dns resolver: {}", err);
-                        AsyncResolver::tokio(ResolverConfig::default(), ResolverOpts::default())
-                    }
-                },
-            };
-            this.resolver = Some(resolver.unwrap())
-        }));
-    }
-}
-
-impl Supervised for Resolver {}
-
-impl SystemService for Resolver {}
-
-impl Default for Resolver {
-    fn default() -> Resolver {
-        Resolver {
-            resolver: None,
-            cfg: None,
-            err: None,
-        }
-    }
-}
-
-impl Handler<Resolve> for Resolver {
-    type Result = ResponseActFuture<Self, Result<VecDeque<SocketAddr>, ResolverError>>;
-
-    fn handle(&mut self, msg: Resolve, _: &mut Self::Context) -> Self::Result {
-        if let Some(ref err) = self.err {
-            Box::pin(ResolveFut::err(err.clone()))
-        } else {
-            Box::pin(ResolveFut::new(
-                msg.name,
-                msg.port.unwrap_or(0),
-                self.resolver.as_ref().unwrap(),
-            ))
-        }
-    }
-}
-
-impl Handler<Connect> for Resolver {
-    type Result = ResponseActFuture<Self, Result<TcpStream, ResolverError>>;
-
-    fn handle(&mut self, msg: Connect, _: &mut Self::Context) -> Self::Result {
-        let timeout = msg.timeout;
-        Box::pin(
-            ResolveFut::new(
-                msg.name,
-                msg.port.unwrap_or(0),
-                self.resolver.as_ref().unwrap(),
-            )
-            .then(move |addrs, act, _| match addrs {
-                Ok(a) => Either::Left(TcpConnector::with_timeout(a, timeout)),
-                Err(e) => Either::Right(async move { Err(e) }.into_actor(act)),
-            }),
-        )
-    }
-}
-
-impl Handler<ConnectAddr> for Resolver {
-    type Result = ResponseActFuture<Self, Result<TcpStream, ResolverError>>;
-
-    fn handle(&mut self, msg: ConnectAddr, _: &mut Self::Context) -> Self::Result {
-        let mut v = VecDeque::new();
-        v.push_back(msg.0);
-        Box::pin(TcpConnector::new(v))
-    }
-}
-
-type LookupIpFuture = Pin<Box<dyn Future<Output = Result<LookupIp, ResolveError>>>>;
-
-/// A resolver future.
-struct ResolveFut {
-    lookup: Option<LookupIpFuture>,
-    port: u16,
-    addrs: Option<VecDeque<SocketAddr>>,
-    error: Option<ResolverError>,
-    error2: Option<String>,
-}
-
-impl ResolveFut {
-    pub fn new<S: AsRef<str>>(addr: S, port: u16, resolver: &AsyncResolver) -> ResolveFut {
-        // try to parse as a regular SocketAddr first
-        if let Ok(addr) = addr.as_ref().parse() {
-            let mut addrs = VecDeque::new();
-            addrs.push_back(addr);
-
-            ResolveFut {
-                port,
-                lookup: None,
-                addrs: Some(addrs),
-                error: None,
-                error2: None,
-            }
-        } else {
-            // we need to do dns resolution
-            match ResolveFut::parse(addr.as_ref(), port) {
-                Ok((host, port)) => ResolveFut {
-                    port,
-                    lookup: {
-                        // Clone data so it can be moved to async block
-                        let resolver_clone = resolver.clone();
-                        let host = host.to_string();
-                        Some(Box::pin(async move {
-                            let resolver = resolver_clone;
-                            resolver.lookup_ip(host).await
-                        }))
-                    },
-                    addrs: None,
-                    error: None,
-                    error2: None,
-                },
-                Err(err) => ResolveFut {
-                    port,
-                    lookup: None,
-                    addrs: None,
-                    error: Some(err),
-                    error2: None,
-                },
-            }
-        }
-    }
-
-    pub fn err(err: String) -> ResolveFut {
-        ResolveFut {
-            port: 0,
-            lookup: None,
-            addrs: None,
-            error: None,
-            error2: Some(err),
-        }
-    }
-
-    fn parse(addr: &str, port: u16) -> Result<(&str, u16), ResolverError> {
-        macro_rules! try_opt {
-            ($e:expr, $msg:expr) => {
-                match $e {
-                    Some(r) => r,
-                    None => return Err(ResolverError::InvalidInput($msg)),
-                }
-            };
-        }
-
-        // split the string by ':' and convert the second part to u16
-        let mut parts_iter = addr.splitn(2, ':');
-        let host = try_opt!(parts_iter.next(), "invalid socket address");
-        let port_str = parts_iter.next().unwrap_or("");
-        let port: u16 = port_str.parse().unwrap_or(port);
-
-        Ok((host, port))
-    }
-}
-
-impl ActorFuture<Resolver> for ResolveFut {
-    type Output = Result<VecDeque<SocketAddr>, ResolverError>;
-
-    fn poll(
-        mut self: Pin<&mut Self>,
-        _: &mut Resolver,
-        _: &mut Context<Resolver>,
-        task: &mut task::Context<'_>,
-    ) -> Poll<Self::Output> {
-        if let Some(err) = self.error.take() {
-            Poll::Ready(Err(err))
-        } else if let Some(err) = self.error2.take() {
-            Poll::Ready(Err(ResolverError::Resolver(err)))
-        } else if let Some(addrs) = self.addrs.take() {
-            Poll::Ready(Ok(addrs))
-        } else {
-            match Pin::new(self.lookup.as_mut().unwrap()).poll(task) {
-                Poll::Pending => Poll::Pending,
-                Poll::Ready(Ok(ips)) => {
-                    let addrs: VecDeque<_> = ips
-                        .iter()
-                        .map(|ip| SocketAddr::new(ip, self.port))
-                        .collect();
-                    if addrs.is_empty() {
-                        Poll::Ready(Err(ResolverError::Resolver(
-                            "Expect at least one A dns record".to_owned(),
-                        )))
-                    } else {
-                        Poll::Ready(Ok(addrs))
-                    }
-                }
-                Poll::Ready(Err(err)) => {
-                    Poll::Ready(Err(ResolverError::Resolver(format!("{}", err))))
-                }
-            }
-        }
-    }
-}
-
-pin_project! {
-    /// A TCP stream connector.
-    #[allow(clippy::type_complexity)]
-    pub struct TcpConnector {
-        addrs: VecDeque<SocketAddr>,
-        #[pin]
-        timeout: Sleep,
-        stream: Option<Pin<Box<dyn Future<Output = Result<TcpStream, io::Error>>>>>,
-    }
-}
-
-impl TcpConnector {
-    pub fn new(addrs: VecDeque<SocketAddr>) -> TcpConnector {
-        TcpConnector::with_timeout(addrs, Duration::from_secs(1))
-    }
-
-    pub fn with_timeout(addrs: VecDeque<SocketAddr>, timeout: Duration) -> TcpConnector {
-        TcpConnector {
-            addrs,
-            stream: None,
-            timeout: actix_rt::time::sleep(timeout),
-        }
-    }
-}
-
-impl ActorFuture<Resolver> for TcpConnector {
-    type Output = Result<TcpStream, ResolverError>;
-
-    fn poll(
-        self: Pin<&mut Self>,
-        _: &mut Resolver,
-        _: &mut Context<Resolver>,
-        cx: &mut task::Context<'_>,
-    ) -> Poll<Self::Output> {
-        let this = self.project();
-
-        // timeout
-        if this.timeout.poll(cx).is_ready() {
-            return Poll::Ready(Err(ResolverError::Timeout));
-        }
-
-        // connect
-        loop {
-            if let Some(ref mut fut) = this.stream {
-                match Pin::new(fut).poll(cx) {
-                    Poll::Ready(Ok(sock)) => return Poll::Ready(Ok(sock)),
-                    Poll::Pending => return Poll::Pending,
-                    Poll::Ready(Err(err)) => {
-                        if this.addrs.is_empty() {
-                            return Poll::Ready(Err(ResolverError::IoError(err)));
-                        }
-                    }
-                }
-            }
-            // try to connect
-            let addr = this.addrs.pop_front().unwrap();
-            *this.stream = Some(Box::pin(TcpStream::connect(addr)));
-        }
-    }
-}


Test patch:
diff --git a/actix/tests/test_actors.rs b/actix/tests/test_actors.rs
deleted file mode 100644
index da9d8956d..000000000
--- a/actix/tests/test_actors.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-#![allow(deprecated)]
-#![cfg(feature = "resolver")]
-
-use actix::actors::resolver;
-use actix::prelude::*;
-
-#[actix::test]
-async fn test_resolver() {
-    actix_rt::spawn(async {
-        let resolver = resolver::Resolver::from_registry();
-        let _ = resolver
-            .send(resolver::Resolve::host("localhost"))
-            .await
-            .unwrap();
-    });
-
-    let resolver = resolver::Resolver::from_registry();
-    let _ = resolver
-        .send(resolver::Connect::host("localhost:5000"))
-        .await
-        .unwrap();
-}