1use crate::error::{Error, Result};
4use crate::request::Request;
5use crate::response::Response;
6use async_trait::async_trait;
7use std::sync::Arc;
8
9#[async_trait]
11pub trait Middleware: Send + Sync + 'static {
12 async fn handle(&self, req: Request, next: Next) -> Result<Response>;
13}
14
15#[derive(Clone)]
17pub struct Next {
18 middlewares: Arc<Vec<Arc<dyn Middleware>>>,
19 index: usize,
20}
21
22impl Next {
23 pub fn new(middlewares: Arc<Vec<Arc<dyn Middleware>>>) -> Self {
24 Self {
25 middlewares,
26 index: 0,
27 }
28 }
29
30 pub async fn run(mut self, req: Request) -> Result<Response> {
31 if self.index < self.middlewares.len() {
32 let middleware = self.middlewares[self.index].clone();
33 self.index += 1;
34 middleware.handle(req, self).await
35 } else {
36 Err(Error::not_found("Route not found"))
38 }
39 }
40}
41
42#[async_trait]
45impl<M: Middleware + ?Sized> Middleware for Arc<M> {
46 async fn handle(&self, req: Request, next: Next) -> Result<Response> {
47 (**self).handle(req, next).await
48 }
49}
50
51pub(crate) struct Layered {
53 middlewares: Vec<Arc<dyn Middleware>>,
54 inner: crate::handler::DynHandler,
55}
56
57impl Layered {
58 pub(crate) fn new(
59 middlewares: Vec<Arc<dyn Middleware>>,
60 inner: crate::handler::DynHandler,
61 ) -> Self {
62 Self { middlewares, inner }
63 }
64}
65
66#[async_trait]
67impl crate::handler::Handler for Layered {
68 async fn call(&self, req: Request) -> Result<Response> {
69 let inner = self.inner.clone();
70 let mut chain = self.middlewares.clone();
71 chain.push(Arc::new(move |req: Request, _next: Next| {
72 let inner = inner.clone();
73 async move { inner.call(req).await }
74 }));
75 Next::new(Arc::new(chain)).run(req).await
76 }
77}
78
79#[async_trait]
81impl<F, Fut> Middleware for F
82where
83 F: Fn(Request, Next) -> Fut + Send + Sync + 'static,
84 Fut: std::future::Future<Output = Result<Response>> + Send + 'static,
85{
86 async fn handle(&self, req: Request, next: Next) -> Result<Response> {
87 (self)(req, next).await
88 }
89}
90
91pub async fn logger(req: Request, next: Next) -> Result<Response> {
93 let method = req.method.clone();
94 let uri = req.uri.clone();
95 let start = std::time::Instant::now();
96
97 let response = next.run(req).await;
98
99 let duration = start.elapsed();
100 println!("{} {} - {:?}", method, uri, duration);
101
102 response
103}
104
105pub fn cors(
107 allowed_origins: Vec<String>,
108) -> impl Fn(
109 Request,
110 Next,
111) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<Response>> + Send>>
112 + Clone {
113 move |req: Request, next: Next| {
114 let origins = allowed_origins.clone();
115 Box::pin(async move {
116 if req.method == http::Method::OPTIONS {
118 let mut response = Response::new(http::StatusCode::NO_CONTENT);
119
120 if !origins.is_empty() {
121 let origin = if origins.contains(&"*".to_string()) {
122 "*".to_string()
123 } else {
124 origins[0].clone()
126 };
127 response = response.with_header("Access-Control-Allow-Origin", origin);
128 response = response.with_header(
129 "Access-Control-Allow-Methods",
130 "GET, POST, PUT, DELETE, PATCH, OPTIONS",
131 );
132 response = response.with_header(
133 "Access-Control-Allow-Headers",
134 "Content-Type, Authorization",
135 );
136 response = response.with_header("Access-Control-Max-Age", "86400");
137 }
138
139 return Ok(response);
140 }
141
142 let mut response = next.run(req).await?;
144
145 if !origins.is_empty() {
146 let origin = if origins.contains(&"*".to_string()) {
147 "*".to_string()
148 } else {
149 origins[0].clone()
150 };
151 response = response.with_header("Access-Control-Allow-Origin", origin);
152 response = response.with_header("Access-Control-Allow-Credentials", "true");
153 }
154
155 Ok(response)
156 })
157 }
158}