use std::io; use std::marker::PhantomData; use std::sync::Arc; use actix_service::{NewService, Service}; use futures::{future::ok, future::FutureResult, Async, Future, Poll}; use rustls::{ServerConfig, ServerSession}; use tokio_io::{AsyncRead, AsyncWrite}; use tokio_rustls::{Accept, TlsAcceptor, TlsStream}; use super::MAX_CONN_COUNTER; use crate::counter::{Counter, CounterGuard}; /// Support `SSL` connections via rustls package /// /// `rust-tls` feature enables `RustlsAcceptor` type pub struct RustlsAcceptor { config: Arc, io: PhantomData, } impl RustlsAcceptor { /// Create `RustlsAcceptor` new service pub fn new(config: ServerConfig) -> Self { RustlsAcceptor { config: Arc::new(config), io: PhantomData, } } } impl Clone for RustlsAcceptor { fn clone(&self) -> Self { Self { config: self.config.clone(), io: PhantomData, } } } impl NewService for RustlsAcceptor { type Response = TlsStream; type Error = io::Error; type Service = RustlsAcceptorService; type InitError = (); type Future = FutureResult; fn new_service(&self) -> Self::Future { MAX_CONN_COUNTER.with(|conns| { ok(RustlsAcceptorService { acceptor: self.config.clone().into(), conns: conns.clone(), io: PhantomData, }) }) } } pub struct RustlsAcceptorService { acceptor: TlsAcceptor, io: PhantomData, conns: Counter, } impl Service for RustlsAcceptorService { type Response = TlsStream; type Error = io::Error; type Future = RustlsAcceptorServiceFut; fn poll_ready(&mut self) -> Poll<(), Self::Error> { if self.conns.available() { Ok(Async::Ready(())) } else { Ok(Async::NotReady) } } fn call(&mut self, req: T) -> Self::Future { RustlsAcceptorServiceFut { _guard: self.conns.get(), fut: self.acceptor.accept(req), } } } pub struct RustlsAcceptorServiceFut where T: AsyncRead + AsyncWrite, { fut: Accept, _guard: CounterGuard, } impl Future for RustlsAcceptorServiceFut { type Item = TlsStream; type Error = io::Error; fn poll(&mut self) -> Poll { self.fut.poll() } }