use std::marker::PhantomData; use actix_codec::{AsyncRead, AsyncWrite}; use actix_service::{NewService, Service}; use futures::{future::ok, future::FutureResult, Async, Future, Poll}; use openssl::ssl::{HandshakeError, SslConnector}; use tokio_openssl::{ConnectAsync, SslConnectorExt, SslStream}; use crate::resolver::RequestHost; /// Openssl connector factory pub struct OpensslConnector { connector: SslConnector, _t: PhantomData<(R, T, E)>, } impl OpensslConnector { pub fn new(connector: SslConnector) -> Self { OpensslConnector { connector, _t: PhantomData, } } } impl OpensslConnector { pub fn service( connector: SslConnector, ) -> impl Service), Error = HandshakeError> { OpensslConnectorService { connector: connector, _t: PhantomData, } } } impl Clone for OpensslConnector { fn clone(&self) -> Self { Self { connector: self.connector.clone(), _t: PhantomData, } } } impl NewService for OpensslConnector { type Request = (R, T); type Response = (R, SslStream); type Error = HandshakeError; type Service = OpensslConnectorService; type InitError = E; type Future = FutureResult; fn new_service(&self) -> Self::Future { ok(OpensslConnectorService { connector: self.connector.clone(), _t: PhantomData, }) } } pub struct OpensslConnectorService { connector: SslConnector, _t: PhantomData<(R, T)>, } impl Service for OpensslConnectorService { type Request = (R, T); type Response = (R, SslStream); type Error = HandshakeError; type Future = ConnectAsyncExt; fn poll_ready(&mut self) -> Poll<(), Self::Error> { Ok(Async::Ready(())) } fn call(&mut self, (req, stream): (R, T)) -> Self::Future { ConnectAsyncExt { fut: SslConnectorExt::connect_async(&self.connector, req.host(), stream), req: Some(req), } } } pub struct ConnectAsyncExt { req: Option, fut: ConnectAsync, } impl Future for ConnectAsyncExt where R: RequestHost, T: AsyncRead + AsyncWrite, { type Item = (R, SslStream); type Error = HandshakeError; fn poll(&mut self) -> Poll { match self.fut.poll()? { Async::Ready(stream) => Ok(Async::Ready((self.req.take().unwrap(), stream))), Async::NotReady => Ok(Async::NotReady), } } }