1
0
Fork 0
mirror of https://github.com/actix/actix-web.git synced 2024-06-02 13:29:24 +00:00
actix-web/actix-http/src/client/connector.rs

587 lines
19 KiB
Rust
Raw Normal View History

2019-03-13 21:41:40 +00:00
use std::fmt;
use std::future::Future;
2019-03-13 21:41:40 +00:00
use std::marker::PhantomData;
use std::pin::Pin;
use std::task::{Context, Poll};
2018-11-12 07:12:54 +00:00
use std::time::Duration;
2018-12-11 02:08:33 +00:00
use actix_codec::{AsyncRead, AsyncWrite};
2019-04-05 17:50:11 +00:00
use actix_connect::{
default_connector, Connect as TcpConnect, Connection as TcpConnection,
};
use actix_service::{apply_fn, Service};
2018-12-11 02:08:33 +00:00
use actix_utils::timeout::{TimeoutError, TimeoutService};
2019-11-18 12:42:27 +00:00
use futures::future::Ready;
2019-03-14 18:52:52 +00:00
use http::Uri;
use tokio_net::tcp::TcpStream;
2018-11-12 07:12:54 +00:00
2019-01-29 18:34:27 +00:00
use super::connection::Connection;
2019-03-13 21:41:40 +00:00
use super::error::ConnectError;
2019-01-29 04:41:09 +00:00
use super::pool::{ConnectionPool, Protocol};
use super::Connect;
2018-11-12 07:12:54 +00:00
#[cfg(feature = "ssl")]
use openssl::ssl::SslConnector as OpensslConnector;
2018-11-12 07:12:54 +00:00
#[cfg(feature = "rust-tls")]
use rustls::ClientConfig;
#[cfg(feature = "rust-tls")]
use std::sync::Arc;
#[cfg(any(feature = "ssl", feature = "rust-tls"))]
enum SslConnector {
#[cfg(feature = "ssl")]
Openssl(OpensslConnector),
#[cfg(feature = "rust-tls")]
Rustls(Arc<ClientConfig>),
}
#[cfg(not(any(feature = "ssl", feature = "rust-tls")))]
2018-11-12 07:12:54 +00:00
type SslConnector = ();
/// Manages http client network connectivity
/// The `Connector` type uses a builder-like combinator pattern for service
/// construction that finishes by calling the `.finish()` method.
///
2019-04-05 23:46:44 +00:00
/// ```rust,ignore
/// use std::time::Duration;
/// use actix_http::client::Connector;
///
/// let connector = Connector::new()
2019-04-05 23:46:44 +00:00
/// .timeout(Duration::from_secs(5))
/// .finish();
/// ```
2019-03-13 21:41:40 +00:00
pub struct Connector<T, U> {
connector: T,
2018-11-12 07:12:54 +00:00
timeout: Duration,
conn_lifetime: Duration,
conn_keep_alive: Duration,
disconnect_timeout: Duration,
limit: usize,
#[allow(dead_code)]
2019-03-13 21:41:40 +00:00
ssl: SslConnector,
_t: PhantomData<U>,
2018-11-12 07:12:54 +00:00
}
trait Io: AsyncRead + AsyncWrite {}
impl<T: AsyncRead + AsyncWrite> Io for T {}
2019-03-13 21:41:40 +00:00
impl Connector<(), ()> {
#[allow(clippy::new_ret_no_self)]
2019-03-13 21:41:40 +00:00
pub fn new() -> Connector<
impl Service<
2019-03-14 18:52:52 +00:00
Request = TcpConnect<Uri>,
Response = TcpConnection<Uri, TcpStream>,
2019-03-13 21:41:40 +00:00
Error = actix_connect::ConnectError,
> + Clone,
TcpStream,
> {
let ssl = {
2018-11-12 07:12:54 +00:00
#[cfg(feature = "ssl")]
{
2019-04-15 04:00:16 +00:00
use openssl::ssl::SslMethod;
2019-02-06 19:44:15 +00:00
let mut ssl = OpensslConnector::builder(SslMethod::tls()).unwrap();
2019-01-29 04:41:09 +00:00
let _ = ssl
.set_alpn_protos(b"\x02h2\x08http/1.1")
.map_err(|e| error!("Can not set alpn protocol: {:?}", e));
SslConnector::Openssl(ssl.build())
}
#[cfg(all(not(feature = "ssl"), feature = "rust-tls"))]
{
let protos = vec![b"h2".to_vec(), b"http/1.1".to_vec()];
let mut config = ClientConfig::new();
config.set_protocols(&protos);
config
.root_store
.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
SslConnector::Rustls(Arc::new(config))
2018-11-12 07:12:54 +00:00
}
#[cfg(not(any(feature = "ssl", feature = "rust-tls")))]
2019-01-29 18:14:00 +00:00
{}
2018-11-12 07:12:54 +00:00
};
Connector {
2019-03-13 21:41:40 +00:00
ssl,
connector: default_connector(),
2018-11-12 07:12:54 +00:00
timeout: Duration::from_secs(1),
conn_lifetime: Duration::from_secs(75),
conn_keep_alive: Duration::from_secs(15),
disconnect_timeout: Duration::from_millis(3000),
limit: 100,
2019-03-13 21:41:40 +00:00
_t: PhantomData,
2018-11-12 07:12:54 +00:00
}
}
}
2019-03-13 21:41:40 +00:00
impl<T, U> Connector<T, U> {
/// Use custom connector.
pub fn connector<T1, U1>(self, connector: T1) -> Connector<T1, U1>
where
2019-11-18 12:42:27 +00:00
U1: AsyncRead + AsyncWrite + Unpin + fmt::Debug,
2019-03-13 21:41:40 +00:00
T1: Service<
2019-03-14 18:52:52 +00:00
Request = TcpConnect<Uri>,
Response = TcpConnection<Uri, U1>,
2019-03-13 21:41:40 +00:00
Error = actix_connect::ConnectError,
> + Clone,
2019-11-18 12:42:27 +00:00
T1::Future: Unpin,
2019-03-13 21:41:40 +00:00
{
Connector {
connector,
timeout: self.timeout,
conn_lifetime: self.conn_lifetime,
conn_keep_alive: self.conn_keep_alive,
disconnect_timeout: self.disconnect_timeout,
limit: self.limit,
ssl: self.ssl,
_t: PhantomData,
}
2018-11-12 07:12:54 +00:00
}
2019-03-13 21:41:40 +00:00
}
2018-11-12 07:12:54 +00:00
2019-03-13 21:41:40 +00:00
impl<T, U> Connector<T, U>
where
2019-11-18 12:42:27 +00:00
U: AsyncRead + AsyncWrite + Unpin + fmt::Debug + 'static,
2019-03-13 21:41:40 +00:00
T: Service<
2019-03-14 18:52:52 +00:00
Request = TcpConnect<Uri>,
Response = TcpConnection<Uri, U>,
2019-03-13 21:41:40 +00:00
Error = actix_connect::ConnectError,
2019-11-18 12:42:27 +00:00
> + 'static,
2019-03-13 21:41:40 +00:00
{
2018-11-12 07:12:54 +00:00
/// Connection timeout, i.e. max time to connect to remote host including dns name resolution.
/// Set to 1 second by default.
pub fn timeout(mut self, timeout: Duration) -> Self {
self.timeout = timeout;
self
}
#[cfg(feature = "ssl")]
/// Use custom `SslConnector` instance.
pub fn ssl(mut self, connector: OpensslConnector) -> Self {
self.ssl = SslConnector::Openssl(connector);
self
}
#[cfg(feature = "rust-tls")]
pub fn rustls(mut self, connector: Arc<ClientConfig>) -> Self {
self.ssl = SslConnector::Rustls(connector);
2018-11-12 07:12:54 +00:00
self
}
/// Set total number of simultaneous connections per type of scheme.
///
/// If limit is 0, the connector has no limit.
/// The default limit size is 100.
pub fn limit(mut self, limit: usize) -> Self {
self.limit = limit;
self
}
/// Set keep-alive period for opened connection.
///
/// Keep-alive period is the period between connection usage. If
/// the delay between repeated usages of the same connection
/// exceeds this period, the connection is closed.
/// Default keep-alive period is 15 seconds.
pub fn conn_keep_alive(mut self, dur: Duration) -> Self {
self.conn_keep_alive = dur;
self
}
/// Set max lifetime period for connection.
///
/// Connection lifetime is max lifetime of any opened connection
/// until it is closed regardless of keep-alive period.
/// Default lifetime period is 75 seconds.
pub fn conn_lifetime(mut self, dur: Duration) -> Self {
self.conn_lifetime = dur;
self
}
/// Set server connection disconnect timeout in milliseconds.
///
/// Defines a timeout for disconnect connection. If a disconnect procedure does not complete
/// within this time, the socket get dropped. This timeout affects only secure connections.
///
/// To disable timeout set value to 0.
///
/// By default disconnect timeout is set to 3000 milliseconds.
pub fn disconnect_timeout(mut self, dur: Duration) -> Self {
self.disconnect_timeout = dur;
self
}
2019-04-05 18:36:26 +00:00
/// Finish configuration process and create connector service.
/// The Connector builder always concludes by calling `finish()` last in
/// its combinator chain.
pub fn finish(
2018-11-12 07:12:54 +00:00
self,
) -> impl Service<Request = Connect, Response = impl Connection, Error = ConnectError>
+ Clone {
#[cfg(not(any(feature = "ssl", feature = "rust-tls")))]
2018-11-12 07:12:54 +00:00
{
2019-03-05 03:51:09 +00:00
let connector = TimeoutService::new(
self.timeout,
2019-11-18 12:42:27 +00:00
apply_fn(UnpinWrapper(self.connector), |msg: Connect, srv| {
srv.call(TcpConnect::new(msg.uri).set_addr(msg.addr))
})
.map_err(ConnectError::from)
.map(|stream| (stream.into_parts().0, Protocol::Http1)),
2018-12-06 22:32:52 +00:00
)
.map_err(|e| match e {
2018-11-12 07:12:54 +00:00
TimeoutError::Service(e) => e,
2019-03-13 21:41:40 +00:00
TimeoutError::Timeout => ConnectError::Timeout,
2018-11-12 07:12:54 +00:00
});
connect_impl::InnerConnector {
tcp_pool: ConnectionPool::new(
connector,
self.conn_lifetime,
self.conn_keep_alive,
None,
self.limit,
),
}
}
#[cfg(any(feature = "ssl", feature = "rust-tls"))]
2018-11-12 07:12:54 +00:00
{
2019-02-06 19:44:15 +00:00
const H2: &[u8] = b"h2";
#[cfg(feature = "ssl")]
2019-03-13 21:41:40 +00:00
use actix_connect::ssl::OpensslConnector;
#[cfg(feature = "rust-tls")]
use actix_connect::ssl::RustlsConnector;
use actix_service::boxed::service;
#[cfg(feature = "rust-tls")]
use rustls::Session;
2019-02-06 19:44:15 +00:00
2019-03-05 03:51:09 +00:00
let ssl_service = TimeoutService::new(
self.timeout,
apply_fn(self.connector.clone(), |msg: Connect, srv| {
srv.call(TcpConnect::new(msg.uri).set_addr(msg.addr))
})
.map_err(ConnectError::from)
.and_then(match self.ssl {
#[cfg(feature = "ssl")]
SslConnector::Openssl(ssl) => service(
OpensslConnector::service(ssl)
.map_err(ConnectError::from)
.map(|stream| {
let sock = stream.into_parts().0;
let h2 = sock
.get_ref()
.ssl()
.selected_alpn_protocol()
.map(|protos| protos.windows(2).any(|w| w == H2))
.unwrap_or(false);
if h2 {
(Box::new(sock) as Box<dyn Io>, Protocol::Http2)
} else {
(Box::new(sock) as Box<dyn Io>, Protocol::Http1)
}
}),
),
#[cfg(feature = "rust-tls")]
SslConnector::Rustls(ssl) => service(
RustlsConnector::service(ssl)
.map_err(ConnectError::from)
.map(|stream| {
let sock = stream.into_parts().0;
let h2 = sock
.get_ref()
.1
.get_alpn_protocol()
.map(|protos| protos.windows(2).any(|w| w == H2))
.unwrap_or(false);
if h2 {
(Box::new(sock) as Box<dyn Io>, Protocol::Http2)
} else {
(Box::new(sock) as Box<dyn Io>, Protocol::Http1)
}
}),
),
}),
2018-12-06 22:32:52 +00:00
)
.map_err(|e| match e {
2018-11-12 07:12:54 +00:00
TimeoutError::Service(e) => e,
2019-03-13 21:41:40 +00:00
TimeoutError::Timeout => ConnectError::Timeout,
2018-11-12 07:12:54 +00:00
});
2019-03-05 03:51:09 +00:00
let tcp_service = TimeoutService::new(
self.timeout,
apply_fn(self.connector.clone(), |msg: Connect, srv| {
srv.call(TcpConnect::new(msg.uri).set_addr(msg.addr))
})
.map_err(ConnectError::from)
.map(|stream| (stream.into_parts().0, Protocol::Http1)),
2018-12-06 22:32:52 +00:00
)
.map_err(|e| match e {
2018-11-12 07:12:54 +00:00
TimeoutError::Service(e) => e,
2019-03-13 21:41:40 +00:00
TimeoutError::Timeout => ConnectError::Timeout,
2018-11-12 07:12:54 +00:00
});
connect_impl::InnerConnector {
tcp_pool: ConnectionPool::new(
tcp_service,
self.conn_lifetime,
self.conn_keep_alive,
None,
self.limit,
),
ssl_pool: ConnectionPool::new(
ssl_service,
self.conn_lifetime,
self.conn_keep_alive,
Some(self.disconnect_timeout),
self.limit,
),
}
}
}
}
2019-11-18 12:42:27 +00:00
#[derive(Clone)]
struct UnpinWrapper<T>(T);
impl<T: Service> Unpin for UnpinWrapper<T> {}
impl<T: Service> Service for UnpinWrapper<T> {
type Request = T::Request;
type Response = T::Response;
type Error = T::Error;
type Future = UnpinWrapperFut<T>;
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), T::Error>> {
self.0.poll_ready(cx)
}
fn call(&mut self, req: T::Request) -> Self::Future {
UnpinWrapperFut {
fut: self.0.call(req),
}
}
}
struct UnpinWrapperFut<T: Service> {
fut: T::Future,
}
impl<T: Service> Unpin for UnpinWrapperFut<T> {}
impl<T: Service> Future for UnpinWrapperFut<T> {
type Output = Result<T::Response, T::Error>;
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
unsafe { Pin::new_unchecked(&mut self.get_mut().fut) }.poll(cx)
}
}
#[cfg(not(any(feature = "ssl", feature = "rust-tls")))]
2018-11-12 07:12:54 +00:00
mod connect_impl {
2019-11-18 12:42:27 +00:00
use std::task::{Context, Poll};
use futures::future::{err, Either, Ready};
use futures::ready;
2019-01-29 04:41:09 +00:00
2018-11-12 07:12:54 +00:00
use super::*;
2019-01-29 04:41:09 +00:00
use crate::client::connection::IoConnection;
2018-11-12 07:12:54 +00:00
pub(crate) struct InnerConnector<T, Io>
where
Io: AsyncRead + AsyncWrite + 'static,
T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError>
2019-11-18 12:42:27 +00:00
+ Unpin
+ 'static,
2018-11-12 07:12:54 +00:00
{
pub(crate) tcp_pool: ConnectionPool<T, Io>,
}
impl<T, Io> Clone for InnerConnector<T, Io>
where
Io: AsyncRead + AsyncWrite + 'static,
T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError>
2019-11-18 12:42:27 +00:00
+ Unpin
+ 'static,
2018-11-12 07:12:54 +00:00
{
fn clone(&self) -> Self {
InnerConnector {
tcp_pool: self.tcp_pool.clone(),
}
}
}
impl<T, Io> Service for InnerConnector<T, Io>
2018-11-12 07:12:54 +00:00
where
2019-11-18 12:42:27 +00:00
Io: AsyncRead + AsyncWrite + Unpin + 'static,
T: Service<Request = Connect, Response = (Io, Protocol), Error = ConnectError>
2019-11-18 12:42:27 +00:00
+ Unpin
+ 'static,
2019-11-18 12:42:27 +00:00
T::Future: Unpin,
2018-11-12 07:12:54 +00:00
{
type Request = Connect;
2018-11-15 19:10:23 +00:00
type Response = IoConnection<Io>;
2019-03-14 20:06:29 +00:00
type Error = ConnectError;
2018-11-12 07:12:54 +00:00
type Future = Either<
<ConnectionPool<T, Io> as Service>::Future,
2019-11-18 12:42:27 +00:00
Ready<Result<IoConnection<Io>, ConnectError>>,
2018-11-12 07:12:54 +00:00
>;
2019-11-18 12:42:27 +00:00
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
self.tcp_pool.poll_ready(cx)
2018-11-12 07:12:54 +00:00
}
2019-04-20 01:10:53 +00:00
fn call(&mut self, req: Connect) -> Self::Future {
match req.uri.scheme_str() {
2019-03-14 18:52:52 +00:00
Some("https") | Some("wss") => {
2019-11-18 12:42:27 +00:00
Either::Right(err(ConnectError::SslIsNotSupported))
2019-03-14 18:52:52 +00:00
}
2019-11-18 12:42:27 +00:00
_ => Either::Left(self.tcp_pool.call(req)),
2018-11-12 07:12:54 +00:00
}
}
}
}
#[cfg(any(feature = "ssl", feature = "rust-tls"))]
2018-11-12 07:12:54 +00:00
mod connect_impl {
use std::marker::PhantomData;
2019-11-18 12:42:27 +00:00
use futures::future::Either;
use futures::ready;
2018-11-12 07:12:54 +00:00
use super::*;
2019-01-29 04:41:09 +00:00
use crate::client::connection::EitherConnection;
2018-11-12 07:12:54 +00:00
pub(crate) struct InnerConnector<T1, T2, Io1, Io2>
where
2019-11-18 12:42:27 +00:00
Io1: AsyncRead + AsyncWrite + Unpin + 'static,
Io2: AsyncRead + AsyncWrite + Unpin + 'static,
T1: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError>,
T2: Service<Request = Connect, Response = (Io2, Protocol), Error = ConnectError>,
2019-11-18 12:42:27 +00:00
T1::Future: Unpin,
T2::Future: Unpin,
2018-11-12 07:12:54 +00:00
{
pub(crate) tcp_pool: ConnectionPool<T1, Io1>,
pub(crate) ssl_pool: ConnectionPool<T2, Io2>,
}
impl<T1, T2, Io1, Io2> Clone for InnerConnector<T1, T2, Io1, Io2>
where
2019-11-18 12:42:27 +00:00
Io1: AsyncRead + AsyncWrite + Unpin + 'static,
Io2: AsyncRead + AsyncWrite + Unpin + 'static,
T1: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError>
2019-11-18 12:42:27 +00:00
+ Unpin
+ 'static,
T2: Service<Request = Connect, Response = (Io2, Protocol), Error = ConnectError>
2019-11-18 12:42:27 +00:00
+ Unpin
+ 'static,
2019-11-18 12:42:27 +00:00
T1::Future: Unpin,
T2::Future: Unpin,
2018-11-12 07:12:54 +00:00
{
fn clone(&self) -> Self {
InnerConnector {
tcp_pool: self.tcp_pool.clone(),
ssl_pool: self.ssl_pool.clone(),
}
}
}
impl<T1, T2, Io1, Io2> Service for InnerConnector<T1, T2, Io1, Io2>
2018-11-12 07:12:54 +00:00
where
2019-11-18 12:42:27 +00:00
Io1: AsyncRead + AsyncWrite + Unpin + 'static,
Io2: AsyncRead + AsyncWrite + Unpin + 'static,
T1: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError>
2019-11-18 12:42:27 +00:00
+ Unpin
+ 'static,
T2: Service<Request = Connect, Response = (Io2, Protocol), Error = ConnectError>
2019-11-18 12:42:27 +00:00
+ Unpin
+ 'static,
2019-11-18 12:42:27 +00:00
T1::Future: Unpin,
T2::Future: Unpin,
2018-11-12 07:12:54 +00:00
{
type Request = Connect;
2019-01-29 04:41:09 +00:00
type Response = EitherConnection<Io1, Io2>;
2019-03-13 21:41:40 +00:00
type Error = ConnectError;
2018-11-12 07:12:54 +00:00
type Future = Either<
2019-11-18 12:42:27 +00:00
InnerConnectorResponseA<T1, Io1, Io2>,
InnerConnectorResponseB<T2, Io1, Io2>,
2018-11-12 07:12:54 +00:00
>;
2019-11-18 12:42:27 +00:00
fn poll_ready(&mut self, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
self.tcp_pool.poll_ready(cx)
2018-11-12 07:12:54 +00:00
}
fn call(&mut self, req: Connect) -> Self::Future {
match req.uri.scheme_str() {
2019-11-18 12:42:27 +00:00
Some("https") | Some("wss") => Either::B(InnerConnectorResponseB {
fut: self.ssl_pool.call(req),
_t: PhantomData,
}),
_ => Either::A(InnerConnectorResponseA {
2018-11-15 19:10:23 +00:00
fut: self.tcp_pool.call(req),
2018-11-12 07:12:54 +00:00
_t: PhantomData,
2019-11-18 12:42:27 +00:00
}),
2018-11-12 07:12:54 +00:00
}
}
}
pub(crate) struct InnerConnectorResponseA<T, Io1, Io2>
where
2019-11-18 12:42:27 +00:00
Io1: AsyncRead + AsyncWrite + Unpin + 'static,
T: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError>
2019-11-18 12:42:27 +00:00
+ Unpin
+ 'static,
2019-11-18 12:42:27 +00:00
T::Future: Unpin,
2018-11-12 07:12:54 +00:00
{
fut: <ConnectionPool<T, Io1> as Service>::Future,
2018-11-12 07:12:54 +00:00
_t: PhantomData<Io2>,
}
impl<T, Io1, Io2> Future for InnerConnectorResponseA<T, Io1, Io2>
where
T: Service<Request = Connect, Response = (Io1, Protocol), Error = ConnectError>
2019-11-18 12:42:27 +00:00
+ Unpin
+ 'static,
2019-11-18 12:42:27 +00:00
T::Future: Unpin,
Io1: AsyncRead + AsyncWrite + Unpin + 'static,
Io2: AsyncRead + AsyncWrite + Unpin + 'static,
2018-11-12 07:12:54 +00:00
{
2019-11-18 12:42:27 +00:00
type Output = Result<EitherConnection<Io1, Io2>, ConnectError>;
2018-11-12 07:12:54 +00:00
2019-11-18 12:42:27 +00:00
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
Poll::Ready(
ready!(Pin::new(&mut self.get_mut().fut).poll(cx))
.map(|res| EitherConnection::A(res)),
)
2018-11-12 07:12:54 +00:00
}
}
pub(crate) struct InnerConnectorResponseB<T, Io1, Io2>
where
2019-11-18 12:42:27 +00:00
Io2: AsyncRead + AsyncWrite + Unpin + 'static,
T: Service<Request = Connect, Response = (Io2, Protocol), Error = ConnectError>
2019-11-18 12:42:27 +00:00
+ Unpin
+ 'static,
2019-11-18 12:42:27 +00:00
T::Future: Unpin,
2018-11-12 07:12:54 +00:00
{
fut: <ConnectionPool<T, Io2> as Service>::Future,
2018-11-12 07:12:54 +00:00
_t: PhantomData<Io1>,
}
impl<T, Io1, Io2> Future for InnerConnectorResponseB<T, Io1, Io2>
where
T: Service<Request = Connect, Response = (Io2, Protocol), Error = ConnectError>
2019-11-18 12:42:27 +00:00
+ Unpin
+ 'static,
2019-11-18 12:42:27 +00:00
T::Future: Unpin,
Io1: AsyncRead + AsyncWrite + Unpin + 'static,
Io2: AsyncRead + AsyncWrite + Unpin + 'static,
2018-11-12 07:12:54 +00:00
{
2019-11-18 12:42:27 +00:00
type Output = Result<EitherConnection<Io1, Io2>, ConnectError>;
2018-11-12 07:12:54 +00:00
2019-11-18 12:42:27 +00:00
fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
Poll::Ready(
ready!(Pin::new(&mut self.get_mut().fut).poll(cx))
.map(|res| EitherConnection::B(res)),
)
2018-11-12 07:12:54 +00:00
}
}
}