2019-11-14 13:38:24 +01:00
|
|
|
use std::future::Future;
|
|
|
|
use std::pin::Pin;
|
2019-03-02 21:16:30 +01:00
|
|
|
use std::rc::Rc;
|
|
|
|
use std::sync::Arc;
|
2019-11-14 13:38:24 +01:00
|
|
|
use std::task::{Context, Poll};
|
2019-03-02 21:16:30 +01:00
|
|
|
|
2019-12-03 13:32:02 +01:00
|
|
|
use crate::transform_err::TransformMapInitErr;
|
2019-11-14 13:38:24 +01:00
|
|
|
use crate::{IntoServiceFactory, Service, ServiceFactory};
|
2019-02-03 19:42:27 +01:00
|
|
|
|
2019-12-11 05:29:34 +01:00
|
|
|
/// Apply transform to a service.
|
|
|
|
pub fn apply<T, S, U>(t: T, factory: U) -> ApplyTransform<T, S>
|
2019-11-20 19:35:44 +01:00
|
|
|
where
|
|
|
|
S: ServiceFactory,
|
|
|
|
T: Transform<S::Service, InitError = S::InitError>,
|
|
|
|
U: IntoServiceFactory<S>,
|
|
|
|
{
|
2019-12-11 05:29:34 +01:00
|
|
|
ApplyTransform::new(t, factory.into_factory())
|
2019-11-20 19:35:44 +01:00
|
|
|
}
|
|
|
|
|
2019-12-10 16:11:39 +01:00
|
|
|
/// The `Transform` trait defines the interface of a service factory that wraps inner service
|
|
|
|
/// during construction.
|
|
|
|
///
|
|
|
|
/// Transform(middleware) wraps inner service and runs during
|
|
|
|
/// inbound and/or outbound processing in the request/response lifecycle.
|
|
|
|
/// It may modify request and/or response.
|
|
|
|
///
|
|
|
|
/// For example, timeout transform:
|
|
|
|
///
|
|
|
|
/// ```rust,ignore
|
|
|
|
/// pub struct Timeout<S> {
|
|
|
|
/// service: S,
|
|
|
|
/// timeout: Duration,
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// impl<S> Service for Timeout<S>
|
|
|
|
/// where
|
|
|
|
/// S: Service,
|
|
|
|
/// {
|
|
|
|
/// type Request = S::Request;
|
|
|
|
/// type Response = S::Response;
|
|
|
|
/// type Error = TimeoutError<S::Error>;
|
|
|
|
/// type Future = TimeoutServiceResponse<S>;
|
|
|
|
///
|
|
|
|
/// fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
|
|
|
|
/// ready!(self.service.poll_ready(cx)).map_err(TimeoutError::Service)
|
|
|
|
/// }
|
|
|
|
///
|
|
|
|
/// fn call(&mut self, req: S::Request) -> Self::Future {
|
|
|
|
/// TimeoutServiceResponse {
|
|
|
|
/// fut: self.service.call(req),
|
|
|
|
/// sleep: Delay::new(clock::now() + self.timeout),
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// ```
|
|
|
|
///
|
|
|
|
/// Timeout service in above example is decoupled from underlying service implementation
|
|
|
|
/// and could be applied to any service.
|
|
|
|
///
|
2019-07-17 06:30:59 +02:00
|
|
|
/// The `Transform` trait defines the interface of a Service factory. `Transform`
|
|
|
|
/// is often implemented for middleware, defining how to construct a
|
|
|
|
/// middleware Service. A Service that is constructed by the factory takes
|
2019-04-04 17:40:28 +02:00
|
|
|
/// the Service that follows it during execution as a parameter, assuming
|
2019-07-17 06:30:59 +02:00
|
|
|
/// ownership of the next Service.
|
2019-12-10 16:11:39 +01:00
|
|
|
///
|
|
|
|
/// Factory for `Timeout` middleware from the above example could look like this:
|
|
|
|
///
|
|
|
|
/// ```rust,,ignore
|
|
|
|
/// pub struct TimeoutTransform {
|
|
|
|
/// timeout: Duration,
|
|
|
|
/// }
|
|
|
|
///
|
2020-11-20 23:45:57 +01:00
|
|
|
/// impl<S> Transform<S> for TimeoutTransform
|
2019-12-10 16:11:39 +01:00
|
|
|
/// where
|
|
|
|
/// S: Service,
|
|
|
|
/// {
|
|
|
|
/// type Request = S::Request;
|
|
|
|
/// type Response = S::Response;
|
|
|
|
/// type Error = TimeoutError<S::Error>;
|
|
|
|
/// type InitError = S::Error;
|
|
|
|
/// type Transform = Timeout<S>;
|
|
|
|
/// type Future = Ready<Result<Self::Transform, Self::InitError>>;
|
|
|
|
///
|
|
|
|
/// fn new_transform(&self, service: S) -> Self::Future {
|
|
|
|
/// ok(TimeoutService {
|
|
|
|
/// service,
|
|
|
|
/// timeout: self.timeout,
|
|
|
|
/// })
|
|
|
|
/// }
|
|
|
|
/// }
|
|
|
|
/// ```
|
2019-03-09 15:36:23 +01:00
|
|
|
pub trait Transform<S> {
|
|
|
|
/// Requests handled by the service.
|
|
|
|
type Request;
|
|
|
|
|
2019-02-03 19:42:27 +01:00
|
|
|
/// Responses given by the service.
|
|
|
|
type Response;
|
|
|
|
|
|
|
|
/// Errors produced by the service.
|
|
|
|
type Error;
|
|
|
|
|
|
|
|
/// The `TransformService` value created by this factory
|
2019-03-09 15:36:23 +01:00
|
|
|
type Transform: Service<
|
|
|
|
Request = Self::Request,
|
|
|
|
Response = Self::Response,
|
|
|
|
Error = Self::Error,
|
|
|
|
>;
|
2019-02-03 19:42:27 +01:00
|
|
|
|
2019-12-10 16:11:39 +01:00
|
|
|
/// Errors produced while building a transform service.
|
2019-02-03 19:42:27 +01:00
|
|
|
type InitError;
|
|
|
|
|
|
|
|
/// The future response value.
|
2019-11-14 13:38:24 +01:00
|
|
|
type Future: Future<Output = Result<Self::Transform, Self::InitError>>;
|
2019-02-03 19:42:27 +01:00
|
|
|
|
2019-12-10 16:11:39 +01:00
|
|
|
/// Creates and returns a new Transform component, asynchronously
|
2019-03-05 04:38:11 +01:00
|
|
|
fn new_transform(&self, service: S) -> Self::Future;
|
2019-12-03 13:32:02 +01:00
|
|
|
|
2020-09-19 16:12:41 +02:00
|
|
|
/// Map this transform's factory error to a different error,
|
2019-12-03 13:32:02 +01:00
|
|
|
/// returning a new transform service factory.
|
|
|
|
fn map_init_err<F, E>(self, f: F) -> TransformMapInitErr<Self, S, F, E>
|
|
|
|
where
|
|
|
|
Self: Sized,
|
|
|
|
F: Fn(Self::InitError) -> E + Clone,
|
|
|
|
{
|
|
|
|
TransformMapInitErr::new(self, f)
|
|
|
|
}
|
2019-02-03 19:42:27 +01:00
|
|
|
}
|
|
|
|
|
2019-03-09 15:36:23 +01:00
|
|
|
impl<T, S> Transform<S> for Rc<T>
|
2019-02-03 19:42:27 +01:00
|
|
|
where
|
2019-03-09 15:36:23 +01:00
|
|
|
T: Transform<S>,
|
2019-03-02 21:16:30 +01:00
|
|
|
{
|
2019-03-09 15:36:23 +01:00
|
|
|
type Request = T::Request;
|
2019-03-02 21:16:30 +01:00
|
|
|
type Response = T::Response;
|
|
|
|
type Error = T::Error;
|
|
|
|
type InitError = T::InitError;
|
2019-03-05 04:38:11 +01:00
|
|
|
type Transform = T::Transform;
|
2019-03-02 21:16:30 +01:00
|
|
|
type Future = T::Future;
|
|
|
|
|
2019-03-05 04:38:11 +01:00
|
|
|
fn new_transform(&self, service: S) -> T::Future {
|
|
|
|
self.as_ref().new_transform(service)
|
2019-03-02 21:16:30 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-09 15:36:23 +01:00
|
|
|
impl<T, S> Transform<S> for Arc<T>
|
2019-03-02 21:16:30 +01:00
|
|
|
where
|
2019-03-09 15:36:23 +01:00
|
|
|
T: Transform<S>,
|
2019-03-02 21:16:30 +01:00
|
|
|
{
|
2019-03-09 15:36:23 +01:00
|
|
|
type Request = T::Request;
|
2019-03-02 21:16:30 +01:00
|
|
|
type Response = T::Response;
|
|
|
|
type Error = T::Error;
|
|
|
|
type InitError = T::InitError;
|
2019-03-05 04:38:11 +01:00
|
|
|
type Transform = T::Transform;
|
2019-03-02 21:16:30 +01:00
|
|
|
type Future = T::Future;
|
|
|
|
|
2019-03-05 04:38:11 +01:00
|
|
|
fn new_transform(&self, service: S) -> T::Future {
|
|
|
|
self.as_ref().new_transform(service)
|
2019-03-02 21:16:30 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-12 20:53:08 +01:00
|
|
|
/// `Apply` transform to new service
|
2019-12-05 07:37:26 +01:00
|
|
|
pub struct ApplyTransform<T, S>(Rc<(T, S)>);
|
2019-03-05 06:24:47 +01:00
|
|
|
|
2019-05-12 15:03:50 +02:00
|
|
|
impl<T, S> ApplyTransform<T, S>
|
2019-03-05 06:24:47 +01:00
|
|
|
where
|
2019-11-14 13:38:24 +01:00
|
|
|
S: ServiceFactory,
|
2019-03-12 20:53:08 +01:00
|
|
|
T: Transform<S::Service, InitError = S::InitError>,
|
2019-03-05 06:24:47 +01:00
|
|
|
{
|
2019-03-12 20:53:08 +01:00
|
|
|
/// Create new `ApplyTransform` new service instance
|
2019-11-14 13:38:24 +01:00
|
|
|
fn new(t: T, service: S) -> Self {
|
2019-12-05 07:37:26 +01:00
|
|
|
Self(Rc::new((t, service)))
|
2019-03-05 06:24:47 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-05-12 15:03:50 +02:00
|
|
|
impl<T, S> Clone for ApplyTransform<T, S> {
|
2019-03-12 20:53:08 +01:00
|
|
|
fn clone(&self) -> Self {
|
2019-12-05 07:37:26 +01:00
|
|
|
ApplyTransform(self.0.clone())
|
2019-03-12 20:53:08 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-14 13:38:24 +01:00
|
|
|
impl<T, S> ServiceFactory for ApplyTransform<T, S>
|
2019-03-05 06:24:47 +01:00
|
|
|
where
|
2019-11-14 13:38:24 +01:00
|
|
|
S: ServiceFactory,
|
2019-03-12 20:53:08 +01:00
|
|
|
T: Transform<S::Service, InitError = S::InitError>,
|
2019-03-05 06:24:47 +01:00
|
|
|
{
|
2019-03-09 15:36:23 +01:00
|
|
|
type Request = T::Request;
|
2019-03-05 06:24:47 +01:00
|
|
|
type Response = T::Response;
|
|
|
|
type Error = T::Error;
|
|
|
|
|
2019-05-12 15:03:50 +02:00
|
|
|
type Config = S::Config;
|
2019-03-05 06:24:47 +01:00
|
|
|
type Service = T::Transform;
|
|
|
|
type InitError = T::InitError;
|
2019-05-12 15:03:50 +02:00
|
|
|
type Future = ApplyTransformFuture<T, S>;
|
2019-03-05 06:24:47 +01:00
|
|
|
|
2019-12-02 16:27:48 +01:00
|
|
|
fn new_service(&self, cfg: S::Config) -> Self::Future {
|
2019-03-05 06:24:47 +01:00
|
|
|
ApplyTransformFuture {
|
2019-12-05 07:37:26 +01:00
|
|
|
store: self.0.clone(),
|
|
|
|
state: ApplyTransformFutureState::A(self.0.as_ref().1.new_service(cfg)),
|
2019-03-05 06:24:47 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-05 07:37:26 +01:00
|
|
|
#[pin_project::pin_project]
|
|
|
|
pub struct ApplyTransformFuture<T, S>
|
|
|
|
where
|
|
|
|
S: ServiceFactory,
|
|
|
|
T: Transform<S::Service, InitError = S::InitError>,
|
|
|
|
{
|
|
|
|
store: Rc<(T, S)>,
|
|
|
|
#[pin]
|
|
|
|
state: ApplyTransformFutureState<T, S>,
|
|
|
|
}
|
|
|
|
|
2020-06-05 23:42:45 +02:00
|
|
|
#[pin_project::pin_project(project = ApplyTransformFutureStateProj)]
|
2019-12-05 07:37:26 +01:00
|
|
|
pub enum ApplyTransformFutureState<T, S>
|
|
|
|
where
|
|
|
|
S: ServiceFactory,
|
|
|
|
T: Transform<S::Service, InitError = S::InitError>,
|
|
|
|
{
|
|
|
|
A(#[pin] S::Future),
|
|
|
|
B(#[pin] T::Future),
|
2019-03-05 06:24:47 +01:00
|
|
|
}
|
|
|
|
|
2019-05-12 15:03:50 +02:00
|
|
|
impl<T, S> Future for ApplyTransformFuture<T, S>
|
2019-03-05 06:24:47 +01:00
|
|
|
where
|
2019-11-14 13:38:24 +01:00
|
|
|
S: ServiceFactory,
|
2019-03-12 20:53:08 +01:00
|
|
|
T: Transform<S::Service, InitError = S::InitError>,
|
2019-03-05 06:24:47 +01:00
|
|
|
{
|
2019-11-14 13:38:24 +01:00
|
|
|
type Output = Result<T::Transform, T::InitError>;
|
2019-03-05 06:24:47 +01:00
|
|
|
|
2019-11-19 09:51:40 +01:00
|
|
|
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
|
|
|
let mut this = self.as_mut().project();
|
2019-11-14 13:38:24 +01:00
|
|
|
|
2019-12-05 07:37:26 +01:00
|
|
|
match this.state.as_mut().project() {
|
2020-06-05 23:42:45 +02:00
|
|
|
ApplyTransformFutureStateProj::A(fut) => match fut.poll(cx)? {
|
2019-12-05 07:37:26 +01:00
|
|
|
Poll::Ready(srv) => {
|
|
|
|
let fut = this.store.0.new_transform(srv);
|
|
|
|
this.state.set(ApplyTransformFutureState::B(fut));
|
|
|
|
self.poll(cx)
|
|
|
|
}
|
|
|
|
Poll::Pending => Poll::Pending,
|
|
|
|
},
|
2020-06-05 23:42:45 +02:00
|
|
|
ApplyTransformFutureStateProj::B(fut) => fut.poll(cx),
|
2019-03-05 06:24:47 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|