use std::marker::PhantomData; use std::rc::Rc; use actix_codec::{AsyncRead, AsyncWrite, Decoder, Encoder}; use actix_service::{IntoNewService, IntoService, NewService, Service}; use futures::{Async, Future, Poll}; use crate::connect::{Connect, ConnectResult}; use crate::dispatcher::FramedDispatcher; use crate::error::ServiceError; use crate::item::Item; type RequestItem = Item; type ResponseItem = Option<::Item>; /// Service builder - structure that follows the builder pattern /// for building instances for framed services. pub struct Builder(PhantomData<(St, Codec)>); impl Builder { pub fn new() -> Builder { Builder(PhantomData) } /// Construct framed handler service with specified connect service pub fn service(self, connect: F) -> ServiceBuilder where F: IntoService, Io: AsyncRead + AsyncWrite, C: Service, Response = ConnectResult>, Codec: Decoder + Encoder, { ServiceBuilder { connect: connect.into_service(), _t: PhantomData, } } /// Construct framed handler new service with specified connect service pub fn factory(self, connect: F) -> NewServiceBuilder where F: IntoNewService, Io: AsyncRead + AsyncWrite, C: NewService< Config = (), Request = Connect, Response = ConnectResult, >, C::Error: 'static, C::Future: 'static, Codec: Decoder + Encoder, { NewServiceBuilder { connect: connect.into_new_service(), _t: PhantomData, } } } pub struct ServiceBuilder { connect: C, _t: PhantomData<(St, Io, Codec)>, } impl ServiceBuilder where St: 'static, Io: AsyncRead + AsyncWrite, C: Service, Response = ConnectResult>, C::Error: 'static, Codec: Decoder + Encoder, ::Item: 'static, ::Error: std::fmt::Debug, { pub fn finish( self, service: F, ) -> impl Service> where F: IntoNewService, T: NewService< Config = St, Request = RequestItem, Response = ResponseItem, Error = C::Error, InitError = C::Error, > + 'static, { FramedServiceImpl { connect: self.connect, handler: Rc::new(service.into_new_service()), _t: PhantomData, } } } pub struct NewServiceBuilder { connect: C, _t: PhantomData<(St, Io, Codec)>, } impl NewServiceBuilder where St: 'static, Io: AsyncRead + AsyncWrite, C: NewService, Response = ConnectResult>, C::Error: 'static, C::Future: 'static, Codec: Decoder + Encoder, ::Item: 'static, ::Error: std::fmt::Debug, { pub fn finish( self, service: F, ) -> impl NewService< Config = (), Request = Io, Response = (), Error = ServiceError, > where F: IntoNewService, T: NewService< Config = St, Request = RequestItem, Response = ResponseItem, Error = C::Error, InitError = C::Error, > + 'static, { FramedService { connect: self.connect, handler: Rc::new(service.into_new_service()), _t: PhantomData, } } } pub(crate) struct FramedService { connect: C, handler: Rc, _t: PhantomData<(St, Io, Codec)>, } impl NewService for FramedService where St: 'static, Io: AsyncRead + AsyncWrite, C: NewService, Response = ConnectResult>, C::Error: 'static, C::Future: 'static, T: NewService< Config = St, Request = RequestItem, Response = ResponseItem, Error = C::Error, InitError = C::Error, > + 'static, Codec: Decoder + Encoder, ::Item: 'static, ::Error: std::fmt::Debug, { type Config = (); type Request = Io; type Response = (); type Error = ServiceError; type InitError = C::InitError; type Service = FramedServiceImpl; type Future = Box>; fn new_service(&self, _: &()) -> Self::Future { let handler = self.handler.clone(); // create connect service and then create service impl Box::new( self.connect .new_service(&()) .map(move |connect| FramedServiceImpl { connect, handler, _t: PhantomData, }), ) } } pub struct FramedServiceImpl { connect: C, handler: Rc, _t: PhantomData<(St, Io, Codec)>, } impl Service for FramedServiceImpl where // St: 'static, Io: AsyncRead + AsyncWrite, C: Service, Response = ConnectResult>, C::Error: 'static, T: NewService< Config = St, Request = RequestItem, Response = ResponseItem, Error = C::Error, InitError = C::Error, >, <::Service as Service>::Future: 'static, Codec: Decoder + Encoder, ::Item: 'static, ::Error: std::fmt::Debug, { type Request = Io; type Response = (); type Error = ServiceError; type Future = FramedServiceImplResponse; fn poll_ready(&mut self) -> Poll<(), Self::Error> { self.connect.poll_ready().map_err(|e| e.into()) } fn call(&mut self, req: Io) -> Self::Future { FramedServiceImplResponse { inner: FramedServiceImplResponseInner::Connect( self.connect.call(Connect::new(req)), self.handler.clone(), ), } } } pub struct FramedServiceImplResponse where C: Service, Response = ConnectResult>, C::Error: 'static, T: NewService< Config = St, Request = RequestItem, Response = ResponseItem, Error = C::Error, InitError = C::Error, >, <::Service as Service>::Future: 'static, Io: AsyncRead + AsyncWrite, Codec: Encoder + Decoder, ::Item: 'static, ::Error: std::fmt::Debug, { inner: FramedServiceImplResponseInner, } enum FramedServiceImplResponseInner where C: Service, Response = ConnectResult>, C::Error: 'static, T: NewService< Config = St, Request = RequestItem, Response = ResponseItem, Error = C::Error, InitError = C::Error, >, <::Service as Service>::Future: 'static, Io: AsyncRead + AsyncWrite, Codec: Encoder + Decoder, ::Item: 'static, ::Error: std::fmt::Debug, { Connect(C::Future, Rc), Handler(T::Future, Option>), Dispatcher(FramedDispatcher), } impl Future for FramedServiceImplResponse where C: Service, Response = ConnectResult>, C::Error: 'static, T: NewService< Config = St, Request = RequestItem, Response = ResponseItem, Error = C::Error, InitError = C::Error, >, <::Service as Service>::Future: 'static, Io: AsyncRead + AsyncWrite, Codec: Encoder + Decoder, ::Item: 'static, ::Error: std::fmt::Debug, { type Item = (); type Error = ServiceError; fn poll(&mut self) -> Poll { match self.inner { FramedServiceImplResponseInner::Connect(ref mut fut, ref handler) => { match fut.poll()? { Async::Ready(res) => { self.inner = FramedServiceImplResponseInner::Handler( handler.new_service(res.state.get_ref()), Some(res), ); self.poll() } Async::NotReady => Ok(Async::NotReady), } } FramedServiceImplResponseInner::Handler(ref mut fut, ref mut res) => { match fut.poll()? { Async::Ready(handler) => { let res = res.take().unwrap(); self.inner = FramedServiceImplResponseInner::Dispatcher(FramedDispatcher::new( res.framed, res.state, handler, res.rx, res.sink, )); self.poll() } Async::NotReady => Ok(Async::NotReady), } } FramedServiceImplResponseInner::Dispatcher(ref mut fut) => fut.poll(), } } }