1
0
mirror of https://github.com/fafhrd91/actix-net synced 2025-02-08 00:44:24 +01:00
Nikolay Kim 13049b80ca
Migrate actix-net to std::future (#64)
* Migrate actix-codec, actix-rt, and actix-threadpool to std::future

* update to latest tokio alpha and futures-rs

* Migrate actix-service to std::future,

This is a squash of ~8 commits, since it included a lot of experimentation. To see the commits,
look into the semtexzv/std-future-service-tmp branch.

* update futures-rs and tokio

* Migrate actix-threadpool to std::future (#59)

* Migrate actix-threadpool to std::future

* Cosmetic refactor

- turn log::error! into log::warn! as it doesn't throw any error
- add Clone and Copy impls for Cancelled making it cheap to operate with
- apply rustfmt

* Bump up crate version to 0.2.0 and pre-fill its changelog

* Disable patching 'actix-threadpool' crate in global workspace as unnecessary

* Revert patching and fix 'actix-rt'

* Migrate actix-rt to std::future (#47)

* remove Pin from Service::poll_ready(); simplify combinators api; make code compile

* disable tests

* update travis config

* refactor naming

* drop IntoFuture trait

* Migrate actix-server to std::future (#50)

Still not finished, this is more WIP, this is an aggregation of several commits, which
can be found in semtexzv/std-future-server-tmp branch

* update actix-server

* rename Factor to ServiceFactory

* start server worker in start mehtod

* update actix-utils

* remove IntoTransform trait

* Migrate actix-server::ssl::nativetls to std futures (#61)

* Refactor 'nativetls' module

* Migrate 'actix-server-config' to std futures

- remove "uds" feature
- disable features by default

* Switch NativeTlsAcceptor to use 'tokio-tls' crate

* Bikeshed features names and remove unnecessary dependencies for 'actix-server-config' crate

* update openssl impl

* migrate actix-connect to std::future

* migrate actix-ioframe to std::future

* update version to alpha.1

* fix boxed service

* migrate server rustls support

* migratte openssl and rustls connecttors

* store the thread's handle with arbiter (#62)

* update ssl connect tests

* restore service tests

* update readme
2019-11-14 18:38:24 +06:00

192 lines
5.0 KiB
Rust

use std::future::Future;
use std::marker::PhantomData;
use std::net::SocketAddr;
use std::pin::Pin;
use std::task::{Context, Poll};
use actix_service::{Service, ServiceFactory};
use futures::future::{ok, Either, Ready};
use pin_project::pin_project;
use trust_dns_resolver::lookup_ip::LookupIpFuture;
use trust_dns_resolver::{AsyncResolver, Background};
use crate::connect::{Address, Connect};
use crate::error::ConnectError;
use crate::get_default_resolver;
/// DNS Resolver Service factory
pub struct ResolverFactory<T> {
resolver: Option<AsyncResolver>,
_t: PhantomData<T>,
}
impl<T> ResolverFactory<T> {
/// Create new resolver instance with custom configuration and options.
pub fn new(resolver: AsyncResolver) -> Self {
ResolverFactory {
resolver: Some(resolver),
_t: PhantomData,
}
}
pub fn service(&self) -> Resolver<T> {
Resolver {
resolver: self.resolver.clone(),
_t: PhantomData,
}
}
}
impl<T> Default for ResolverFactory<T> {
fn default() -> Self {
ResolverFactory {
resolver: None,
_t: PhantomData,
}
}
}
impl<T> Clone for ResolverFactory<T> {
fn clone(&self) -> Self {
ResolverFactory {
resolver: self.resolver.clone(),
_t: PhantomData,
}
}
}
impl<T: Address> ServiceFactory for ResolverFactory<T> {
type Request = Connect<T>;
type Response = Connect<T>;
type Error = ConnectError;
type Config = ();
type Service = Resolver<T>;
type InitError = ();
type Future = Ready<Result<Self::Service, Self::InitError>>;
fn new_service(&self, _: &()) -> Self::Future {
ok(self.service())
}
}
/// DNS Resolver Service
pub struct Resolver<T> {
resolver: Option<AsyncResolver>,
_t: PhantomData<T>,
}
impl<T> Resolver<T> {
/// Create new resolver instance with custom configuration and options.
pub fn new(resolver: AsyncResolver) -> Self {
Resolver {
resolver: Some(resolver),
_t: PhantomData,
}
}
}
impl<T> Default for Resolver<T> {
fn default() -> Self {
Resolver {
resolver: None,
_t: PhantomData,
}
}
}
impl<T> Clone for Resolver<T> {
fn clone(&self) -> Self {
Resolver {
resolver: self.resolver.clone(),
_t: PhantomData,
}
}
}
impl<T: Address> Service for Resolver<T> {
type Request = Connect<T>;
type Response = Connect<T>;
type Error = ConnectError;
type Future = Either<ResolverFuture<T>, Ready<Result<Connect<T>, Self::Error>>>;
fn poll_ready(&mut self, _: &mut Context) -> Poll<Result<(), Self::Error>> {
Poll::Ready(Ok(()))
}
fn call(&mut self, mut req: Connect<T>) -> Self::Future {
if req.addr.is_some() {
Either::Right(ok(req))
} else if let Ok(ip) = req.host().parse() {
req.addr = Some(either::Either::Left(SocketAddr::new(ip, req.port())));
Either::Right(ok(req))
} else {
trace!("DNS resolver: resolving host {:?}", req.host());
if self.resolver.is_none() {
self.resolver = Some(get_default_resolver());
}
Either::Left(ResolverFuture::new(req, self.resolver.as_ref().unwrap()))
}
}
}
#[pin_project]
#[doc(hidden)]
/// Resolver future
pub struct ResolverFuture<T: Address> {
req: Option<Connect<T>>,
#[pin]
lookup: Background<LookupIpFuture>,
}
impl<T: Address> ResolverFuture<T> {
pub fn new(req: Connect<T>, resolver: &AsyncResolver) -> Self {
let lookup = if let Some(host) = req.host().splitn(2, ':').next() {
resolver.lookup_ip(host)
} else {
resolver.lookup_ip(req.host())
};
ResolverFuture {
lookup,
req: Some(req),
}
}
}
impl<T: Address> Future for ResolverFuture<T> {
type Output = Result<Connect<T>, ConnectError>;
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
let this = self.project();
match this.lookup.poll(cx) {
Poll::Pending => Poll::Pending,
Poll::Ready(Ok(ips)) => {
let req = this.req.take().unwrap();
let port = req.port();
let req = req.set_addrs(ips.iter().map(|ip| SocketAddr::new(ip, port)));
trace!(
"DNS resolver: host {:?} resolved to {:?}",
req.host(),
req.addrs()
);
if req.addr.is_none() {
Poll::Ready(Err(ConnectError::NoRecords))
} else {
Poll::Ready(Ok(req))
}
}
Poll::Ready(Err(e)) => {
trace!(
"DNS resolver: failed to resolve host {:?} err: {}",
this.req.as_ref().unwrap().host(),
e
);
Poll::Ready(Err(e.into()))
}
}
}
}