diff --git a/actix-service/src/lib.rs b/actix-service/src/lib.rs index fd09184c..f86bdac5 100644 --- a/actix-service/src/lib.rs +++ b/actix-service/src/lib.rs @@ -19,6 +19,7 @@ mod map; mod map_config; mod map_err; mod map_init_err; +mod map_request; mod pipeline; mod then; mod transform; @@ -28,6 +29,7 @@ pub use self::apply::{apply_fn, apply_fn_factory}; pub use self::apply_cfg::{apply_cfg, apply_cfg_factory}; pub use self::fn_service::{fn_factory, fn_factory_with_config, fn_service}; pub use self::map_config::{map_config, unit_config}; +pub use self::map_request::{MapRequest, MapRequestMiddleware}; pub use self::pipeline::{pipeline, pipeline_factory, Pipeline, PipelineFactory}; pub use self::transform::{apply, Transform}; diff --git a/actix-service/src/map_request.rs b/actix-service/src/map_request.rs new file mode 100644 index 00000000..13de392d --- /dev/null +++ b/actix-service/src/map_request.rs @@ -0,0 +1,62 @@ +use std::{cell::RefCell, future::Future, rc::Rc}; + +use futures_util::future::{self, FutureExt as _, LocalBoxFuture, TryFutureExt as _}; + +use super::{Service, Transform}; + +#[derive(Clone, Debug)] +pub struct MapRequest(pub F); + +pub struct MapRequestMiddleware { + service: Rc>, + f: F, +} + +impl Transform for MapRequest +where + S: Service + 'static, + F: FnMut(S::Request) -> R + Clone + 'static, + R: Future> + 'static, +{ + type Request = S::Request; + type Response = S::Response; + type Error = S::Error; + type Transform = MapRequestMiddleware; + type InitError = (); + type Future = future::Ready>; + + fn new_transform(&self, service: S) -> Self::Future { + future::ok(MapRequestMiddleware { + service: Rc::new(RefCell::new(service)), + f: self.0.clone(), + }) + } +} + +impl Service for MapRequestMiddleware +where + S: Service + 'static, + F: FnMut(S::Request) -> R + Clone + 'static, + R: Future> + 'static, +{ + type Request = S::Request; + type Response = S::Response; + type Error = S::Error; + type Future = LocalBoxFuture<'static, Result>; + + fn poll_ready( + &mut self, + ctx: &mut std::task::Context<'_>, + ) -> std::task::Poll> { + self.service.borrow_mut().poll_ready(ctx) + } + + fn call(&mut self, req: Self::Request) -> Self::Future { + let mut f = self.f.clone(); + let service = Rc::clone(&self.service); + + f(req) + .and_then(move |req| service.borrow_mut().call(req)) + .boxed_local() + } +}