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
42pub(crate) struct Layered {
44 middlewares: Vec<Arc<dyn Middleware>>,
45 inner: crate::handler::DynHandler,
46}
47
48impl Layered {
49 pub(crate) fn new(
50 middlewares: Vec<Arc<dyn Middleware>>,
51 inner: crate::handler::DynHandler,
52 ) -> Self {
53 Self { middlewares, inner }
54 }
55}
56
57#[async_trait]
58impl crate::handler::Handler for Layered {
59 async fn call(&self, req: Request) -> Result<Response> {
60 let inner = self.inner.clone();
61 let mut chain = self.middlewares.clone();
62 chain.push(Arc::new(move |req: Request, _next: Next| {
63 let inner = inner.clone();
64 async move { inner.call(req).await }
65 }));
66 Next::new(Arc::new(chain)).run(req).await
67 }
68}
69
70#[async_trait]
72impl<F, Fut> Middleware for F
73where
74 F: Fn(Request, Next) -> Fut + Send + Sync + 'static,
75 Fut: std::future::Future<Output = Result<Response>> + Send + 'static,
76{
77 async fn handle(&self, req: Request, next: Next) -> Result<Response> {
78 (self)(req, next).await
79 }
80}
81
82pub async fn logger(req: Request, next: Next) -> Result<Response> {
84 let method = req.method.clone();
85 let uri = req.uri.clone();
86 let start = std::time::Instant::now();
87
88 let response = next.run(req).await;
89
90 let duration = start.elapsed();
91 println!("{} {} - {:?}", method, uri, duration);
92
93 response
94}
95
96pub fn cors(
98 allowed_origins: Vec<String>,
99) -> impl Fn(
100 Request,
101 Next,
102) -> std::pin::Pin<Box<dyn std::future::Future<Output = Result<Response>> + Send>>
103 + Clone {
104 move |req: Request, next: Next| {
105 let origins = allowed_origins.clone();
106 Box::pin(async move {
107 if req.method == http::Method::OPTIONS {
109 let mut response = Response::new(http::StatusCode::NO_CONTENT);
110
111 if !origins.is_empty() {
112 let origin = if origins.contains(&"*".to_string()) {
113 "*".to_string()
114 } else {
115 origins[0].clone()
117 };
118 response = response.with_header("Access-Control-Allow-Origin", origin);
119 response = response.with_header(
120 "Access-Control-Allow-Methods",
121 "GET, POST, PUT, DELETE, PATCH, OPTIONS",
122 );
123 response = response.with_header(
124 "Access-Control-Allow-Headers",
125 "Content-Type, Authorization",
126 );
127 response = response.with_header("Access-Control-Max-Age", "86400");
128 }
129
130 return Ok(response);
131 }
132
133 let mut response = next.run(req).await?;
135
136 if !origins.is_empty() {
137 let origin = if origins.contains(&"*".to_string()) {
138 "*".to_string()
139 } else {
140 origins[0].clone()
141 };
142 response = response.with_header("Access-Control-Allow-Origin", origin);
143 response = response.with_header("Access-Control-Allow-Credentials", "true");
144 }
145
146 Ok(response)
147 })
148 }
149}