1use crate::http::{Request, Response};
2use crate::middleware::{into_boxed, BoxedMiddleware, Middleware};
3use matchit::Router as MatchitRouter;
4use std::collections::HashMap;
5use std::future::Future;
6use std::pin::Pin;
7use std::sync::{Arc, OnceLock, RwLock};
8
9static ROUTE_REGISTRY: OnceLock<RwLock<HashMap<String, String>>> = OnceLock::new();
11
12pub fn register_route_name(name: &str, path: &str) {
14 let registry = ROUTE_REGISTRY.get_or_init(|| RwLock::new(HashMap::new()));
15 if let Ok(mut map) = registry.write() {
16 map.insert(name.to_string(), path.to_string());
17 }
18}
19
20pub fn route(name: &str, params: &[(&str, &str)]) -> Option<String> {
36 let registry = ROUTE_REGISTRY.get()?.read().ok()?;
37 let path_pattern = registry.get(name)?;
38
39 let mut url = path_pattern.clone();
40 for (key, value) in params {
41 url = url.replace(&format!("{{{}}}", key), value);
42 }
43 Some(url)
44}
45
46pub fn route_with_params(name: &str, params: &HashMap<String, String>) -> Option<String> {
48 let registry = ROUTE_REGISTRY.get()?.read().ok()?;
49 let path_pattern = registry.get(name)?;
50
51 let mut url = path_pattern.clone();
52 for (key, value) in params {
53 url = url.replace(&format!("{{{}}}", key), value);
54 }
55 Some(url)
56}
57
58#[derive(Clone, Copy)]
60enum Method {
61 Get,
62 Post,
63 Put,
64 Delete,
65}
66
67pub type BoxedHandler =
69 Box<dyn Fn(Request) -> Pin<Box<dyn Future<Output = Response> + Send>> + Send + Sync>;
70
71pub struct Router {
73 get_routes: MatchitRouter<Arc<BoxedHandler>>,
74 post_routes: MatchitRouter<Arc<BoxedHandler>>,
75 put_routes: MatchitRouter<Arc<BoxedHandler>>,
76 delete_routes: MatchitRouter<Arc<BoxedHandler>>,
77 route_middleware: HashMap<String, Vec<BoxedMiddleware>>,
79 fallback_handler: Option<Arc<BoxedHandler>>,
81 fallback_middleware: Vec<BoxedMiddleware>,
83}
84
85impl Router {
86 pub fn new() -> Self {
87 Self {
88 get_routes: MatchitRouter::new(),
89 post_routes: MatchitRouter::new(),
90 put_routes: MatchitRouter::new(),
91 delete_routes: MatchitRouter::new(),
92 route_middleware: HashMap::new(),
93 fallback_handler: None,
94 fallback_middleware: Vec::new(),
95 }
96 }
97
98 pub fn get_route_middleware(&self, path: &str) -> Vec<BoxedMiddleware> {
100 self.route_middleware.get(path).cloned().unwrap_or_default()
101 }
102
103 pub(crate) fn add_middleware(&mut self, path: &str, middleware: BoxedMiddleware) {
105 self.route_middleware
106 .entry(path.to_string())
107 .or_default()
108 .push(middleware);
109 }
110
111 pub(crate) fn set_fallback(&mut self, handler: Arc<BoxedHandler>) {
113 self.fallback_handler = Some(handler);
114 }
115
116 pub(crate) fn add_fallback_middleware(&mut self, middleware: BoxedMiddleware) {
118 self.fallback_middleware.push(middleware);
119 }
120
121 pub fn get_fallback(&self) -> Option<(Arc<BoxedHandler>, Vec<BoxedMiddleware>)> {
123 self.fallback_handler
124 .as_ref()
125 .map(|h| (h.clone(), self.fallback_middleware.clone()))
126 }
127
128 pub(crate) fn insert_get(&mut self, path: &str, handler: Arc<BoxedHandler>) {
130 self.get_routes.insert(path, handler).ok();
131 }
132
133 pub(crate) fn insert_post(&mut self, path: &str, handler: Arc<BoxedHandler>) {
135 self.post_routes.insert(path, handler).ok();
136 }
137
138 pub(crate) fn insert_put(&mut self, path: &str, handler: Arc<BoxedHandler>) {
140 self.put_routes.insert(path, handler).ok();
141 }
142
143 pub(crate) fn insert_delete(&mut self, path: &str, handler: Arc<BoxedHandler>) {
145 self.delete_routes.insert(path, handler).ok();
146 }
147
148 pub fn get<H, Fut>(mut self, path: &str, handler: H) -> RouteBuilder
150 where
151 H: Fn(Request) -> Fut + Send + Sync + 'static,
152 Fut: Future<Output = Response> + Send + 'static,
153 {
154 let handler: BoxedHandler = Box::new(move |req| Box::pin(handler(req)));
155 self.get_routes.insert(path, Arc::new(handler)).ok();
156 RouteBuilder {
157 router: self,
158 last_path: path.to_string(),
159 _last_method: Method::Get,
160 }
161 }
162
163 pub fn post<H, Fut>(mut self, path: &str, handler: H) -> RouteBuilder
165 where
166 H: Fn(Request) -> Fut + Send + Sync + 'static,
167 Fut: Future<Output = Response> + Send + 'static,
168 {
169 let handler: BoxedHandler = Box::new(move |req| Box::pin(handler(req)));
170 self.post_routes.insert(path, Arc::new(handler)).ok();
171 RouteBuilder {
172 router: self,
173 last_path: path.to_string(),
174 _last_method: Method::Post,
175 }
176 }
177
178 pub fn put<H, Fut>(mut self, path: &str, handler: H) -> RouteBuilder
180 where
181 H: Fn(Request) -> Fut + Send + Sync + 'static,
182 Fut: Future<Output = Response> + Send + 'static,
183 {
184 let handler: BoxedHandler = Box::new(move |req| Box::pin(handler(req)));
185 self.put_routes.insert(path, Arc::new(handler)).ok();
186 RouteBuilder {
187 router: self,
188 last_path: path.to_string(),
189 _last_method: Method::Put,
190 }
191 }
192
193 pub fn delete<H, Fut>(mut self, path: &str, handler: H) -> RouteBuilder
195 where
196 H: Fn(Request) -> Fut + Send + Sync + 'static,
197 Fut: Future<Output = Response> + Send + 'static,
198 {
199 let handler: BoxedHandler = Box::new(move |req| Box::pin(handler(req)));
200 self.delete_routes.insert(path, Arc::new(handler)).ok();
201 RouteBuilder {
202 router: self,
203 last_path: path.to_string(),
204 _last_method: Method::Delete,
205 }
206 }
207
208 pub fn match_route(
210 &self,
211 method: &hyper::Method,
212 path: &str,
213 ) -> Option<(Arc<BoxedHandler>, HashMap<String, String>)> {
214 let router = match *method {
215 hyper::Method::GET => &self.get_routes,
216 hyper::Method::POST => &self.post_routes,
217 hyper::Method::PUT => &self.put_routes,
218 hyper::Method::DELETE => &self.delete_routes,
219 _ => return None,
220 };
221
222 router.at(path).ok().map(|matched| {
223 let params: HashMap<String, String> = matched
224 .params
225 .iter()
226 .map(|(k, v)| (k.to_string(), v.to_string()))
227 .collect();
228 (matched.value.clone(), params)
229 })
230 }
231}
232
233impl Default for Router {
234 fn default() -> Self {
235 Self::new()
236 }
237}
238
239pub struct RouteBuilder {
241 pub(crate) router: Router,
242 last_path: String,
243 #[allow(dead_code)]
244 _last_method: Method,
245}
246
247impl RouteBuilder {
248 pub fn name(self, name: &str) -> Router {
250 register_route_name(name, &self.last_path);
251 self.router
252 }
253
254 pub fn middleware<M: Middleware + 'static>(mut self, middleware: M) -> RouteBuilder {
264 self.router
265 .add_middleware(&self.last_path, into_boxed(middleware));
266 self
267 }
268
269 pub fn middleware_boxed(mut self, middleware: BoxedMiddleware) -> RouteBuilder {
272 self.router
273 .route_middleware
274 .entry(self.last_path.clone())
275 .or_default()
276 .push(middleware);
277 self
278 }
279
280 pub fn get<H, Fut>(self, path: &str, handler: H) -> RouteBuilder
282 where
283 H: Fn(Request) -> Fut + Send + Sync + 'static,
284 Fut: Future<Output = Response> + Send + 'static,
285 {
286 self.router.get(path, handler)
287 }
288
289 pub fn post<H, Fut>(self, path: &str, handler: H) -> RouteBuilder
291 where
292 H: Fn(Request) -> Fut + Send + Sync + 'static,
293 Fut: Future<Output = Response> + Send + 'static,
294 {
295 self.router.post(path, handler)
296 }
297
298 pub fn put<H, Fut>(self, path: &str, handler: H) -> RouteBuilder
300 where
301 H: Fn(Request) -> Fut + Send + Sync + 'static,
302 Fut: Future<Output = Response> + Send + 'static,
303 {
304 self.router.put(path, handler)
305 }
306
307 pub fn delete<H, Fut>(self, path: &str, handler: H) -> RouteBuilder
309 where
310 H: Fn(Request) -> Fut + Send + Sync + 'static,
311 Fut: Future<Output = Response> + Send + 'static,
312 {
313 self.router.delete(path, handler)
314 }
315}
316
317impl From<RouteBuilder> for Router {
318 fn from(builder: RouteBuilder) -> Self {
319 builder.router
320 }
321}