Skip to main content

foxtive_ntex/http/middlewares/
executor.rs

1use crate::http::middlewares::{Middleware, MiddlewareFlow};
2use crate::http::response::anyhow::ResponseError;
3use ntex::service::{Middleware as ServiceMiddleware, Service, ServiceCtx};
4use ntex::web;
5use ntex::web::{Error, WebRequest, WebResponse};
6use std::rc::Rc;
7use tracing::{debug, error, info};
8
9#[derive(Clone)]
10pub struct MiddlewareChain {
11    middlewares: Rc<Vec<Middleware>>,
12}
13
14impl MiddlewareChain {
15    pub fn new(middlewares: Vec<Middleware>) -> Self {
16        MiddlewareChain {
17            middlewares: Rc::new(middlewares),
18        }
19    }
20
21    /// Convenience method for single middleware
22    pub fn single(middleware: Middleware) -> Self {
23        Self::new(vec![middleware])
24    }
25}
26
27impl<S, Cfg> ServiceMiddleware<S, Cfg> for MiddlewareChain {
28    type Service = MiddlewareChainInternal<S>;
29
30    fn create(&self, service: S, _cfg: Cfg) -> Self::Service {
31        MiddlewareChainInternal {
32            service,
33            middlewares: self.middlewares.clone(),
34        }
35    }
36}
37
38pub struct MiddlewareChainInternal<S> {
39    service: S,
40    middlewares: Rc<Vec<Middleware>>,
41}
42
43impl<S, Err> Service<web::WebRequest<Err>> for MiddlewareChainInternal<S>
44where
45    S: Service<web::WebRequest<Err>, Response = web::WebResponse, Error = web::Error>,
46    Err: web::ErrorRenderer,
47{
48    type Response = web::WebResponse;
49    type Error = web::Error;
50
51    ntex::forward_ready!(service);
52
53    async fn call(
54        &self,
55        request: web::WebRequest<Err>,
56        ctx: ServiceCtx<'_, Self>,
57    ) -> Result<Self::Response, Self::Error> {
58        let (mut req, payload) = request.into_parts();
59        info!("{} {}", req.method(), req.path());
60
61        // Execute all "Before" middlewares in order
62        for middleware in self.middlewares.iter() {
63            if let Middleware::Before(mid) = middleware {
64                let flow = mid
65                    .handle(req)
66                    .await
67                    .map_err(|err| Error::from(ResponseError::new(err)))?;
68
69                match flow {
70                    MiddlewareFlow::Continue(modified_req) => {
71                        req = modified_req;
72                    }
73                    MiddlewareFlow::Respond(request, response) => {
74                        return Ok(WebResponse::new(response, request));
75                    }
76                }
77            }
78        }
79
80        // Call the actual handler
81        let request = WebRequest::from_parts(req, payload).unwrap();
82        debug!("calling http controller -> method...");
83        let mut response = ctx.call(&self.service, request).await?;
84
85        // Execute all "After" middlewares in order
86        for middleware in self.middlewares.iter() {
87            if let Middleware::After(mid) = middleware {
88                match mid.handle(response).await {
89                    Ok(modified_resp) => {
90                        response = modified_resp;
91                    }
92                    Err(err) => {
93                        error!("[middleware-chain-error][after] {err:?}");
94                        return Err(Error::from(ResponseError::new(err)));
95                    }
96                }
97            }
98        }
99
100        Ok(response)
101    }
102}