foxtive_ntex/http/middlewares/
executor.rs1use 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 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 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 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 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}