1use crate::http::{Request, Response};
2use crate::middleware::{into_boxed, BoxedMiddleware, Middleware};
3use matchit::Router as MatchitRouter;
4use serde::Serialize;
5use std::collections::HashMap;
6use std::future::Future;
7use std::pin::Pin;
8use std::sync::{Arc, OnceLock, RwLock};
9
10static ROUTE_REGISTRY: OnceLock<RwLock<HashMap<String, String>>> = OnceLock::new();
12
13static REGISTERED_ROUTES: OnceLock<RwLock<Vec<RouteInfo>>> = OnceLock::new();
15
16#[derive(Debug, Clone, Default, Serialize)]
18pub struct RouteInfo {
19 pub method: String,
21 pub path: String,
23 pub name: Option<String>,
25 pub middleware: Vec<String>,
27 pub mcp_tool_name: Option<String>,
29 pub mcp_description: Option<String>,
31 pub mcp_hint: Option<String>,
33 pub mcp_hidden: bool,
35}
36
37fn insert_route<V>(router: &mut MatchitRouter<V>, method: &str, path: &str, value: V) {
53 if let Err(err) = router.insert(path, value) {
54 tracing::error!(
55 method = %method,
56 path = %path,
57 error = %err,
58 "route registration conflict: matchit rejected this route; \
59 it will NOT be reachable. A conflicting pattern is already \
60 registered at the same tree position."
61 );
62 }
63}
64
65fn register_route(method: &str, path: &str) {
67 let registry = REGISTERED_ROUTES.get_or_init(|| RwLock::new(Vec::new()));
68 if let Ok(mut routes) = registry.write() {
69 routes.push(RouteInfo {
70 method: method.to_string(),
71 path: path.to_string(),
72 name: None,
73 middleware: Vec::new(),
74 mcp_tool_name: None,
75 mcp_description: None,
76 mcp_hint: None,
77 mcp_hidden: false,
78 });
79 }
80}
81
82fn update_route_name(path: &str, name: &str) {
84 let registry = REGISTERED_ROUTES.get_or_init(|| RwLock::new(Vec::new()));
85 if let Ok(mut routes) = registry.write() {
86 if let Some(route) = routes.iter_mut().rev().find(|r| r.path == path) {
88 route.name = Some(name.to_string());
89 }
90 }
91}
92
93fn update_route_middleware(path: &str, middleware_name: &str) {
95 let registry = REGISTERED_ROUTES.get_or_init(|| RwLock::new(Vec::new()));
96 if let Ok(mut routes) = registry.write() {
97 if let Some(route) = routes.iter_mut().rev().find(|r| r.path == path) {
99 route.middleware.push(middleware_name.to_string());
100 }
101 }
102}
103
104pub(crate) fn update_route_mcp(
106 path: &str,
107 tool_name: Option<String>,
108 description: Option<String>,
109 hint: Option<String>,
110 hidden: bool,
111) {
112 let registry = REGISTERED_ROUTES.get_or_init(|| RwLock::new(Vec::new()));
113 if let Ok(mut routes) = registry.write() {
114 if let Some(route) = routes.iter_mut().rev().find(|r| r.path == path) {
115 route.mcp_tool_name = tool_name;
116 route.mcp_description = description;
117 route.mcp_hint = hint;
118 route.mcp_hidden = hidden;
119 }
120 }
121}
122
123pub fn get_registered_routes() -> Vec<RouteInfo> {
125 REGISTERED_ROUTES
126 .get()
127 .and_then(|r| r.read().ok())
128 .map(|routes| routes.clone())
129 .unwrap_or_default()
130}
131
132pub fn register_route_name(name: &str, path: &str) {
134 let registry = ROUTE_REGISTRY.get_or_init(|| RwLock::new(HashMap::new()));
135 if let Ok(mut map) = registry.write() {
136 map.insert(name.to_string(), path.to_string());
137 }
138 update_route_name(path, name);
140}
141
142pub fn route(name: &str, params: &[(&str, &str)]) -> Option<String> {
158 let registry = ROUTE_REGISTRY.get()?.read().ok()?;
159 let path_pattern = registry.get(name)?;
160
161 let mut url = path_pattern.clone();
162 for (key, value) in params {
163 url = url.replace(&format!("{{{key}}}"), value);
164 }
165 Some(url)
166}
167
168pub fn route_with_params(name: &str, params: &HashMap<String, String>) -> Option<String> {
170 let registry = ROUTE_REGISTRY.get()?.read().ok()?;
171 let path_pattern = registry.get(name)?;
172
173 let mut url = path_pattern.clone();
174 for (key, value) in params {
175 url = url.replace(&format!("{{{key}}}"), value);
176 }
177 Some(url)
178}
179
180#[derive(Clone, Copy)]
182enum Method {
183 Get,
184 Post,
185 Put,
186 Patch,
187 Delete,
188}
189
190pub type BoxedHandler =
192 Box<dyn Fn(Request) -> Pin<Box<dyn Future<Output = Response> + Send>> + Send + Sync>;
193
194type RouteValue = (Arc<BoxedHandler>, String);
196
197pub struct Router {
199 get_routes: MatchitRouter<RouteValue>,
200 post_routes: MatchitRouter<RouteValue>,
201 put_routes: MatchitRouter<RouteValue>,
202 patch_routes: MatchitRouter<RouteValue>,
203 delete_routes: MatchitRouter<RouteValue>,
204 route_middleware: HashMap<String, Vec<BoxedMiddleware>>,
206 fallback_handler: Option<Arc<BoxedHandler>>,
208 fallback_middleware: Vec<BoxedMiddleware>,
210}
211
212impl Router {
213 pub fn new() -> Self {
215 Self {
216 get_routes: MatchitRouter::new(),
217 post_routes: MatchitRouter::new(),
218 put_routes: MatchitRouter::new(),
219 patch_routes: MatchitRouter::new(),
220 delete_routes: MatchitRouter::new(),
221 route_middleware: HashMap::new(),
222 fallback_handler: None,
223 fallback_middleware: Vec::new(),
224 }
225 }
226
227 pub fn get_route_middleware(&self, path: &str) -> Vec<BoxedMiddleware> {
229 self.route_middleware.get(path).cloned().unwrap_or_default()
230 }
231
232 pub(crate) fn add_middleware(&mut self, path: &str, middleware: BoxedMiddleware) {
234 self.route_middleware
235 .entry(path.to_string())
236 .or_default()
237 .push(middleware);
238 }
239
240 pub(crate) fn set_fallback(&mut self, handler: Arc<BoxedHandler>) {
242 self.fallback_handler = Some(handler);
243 }
244
245 pub(crate) fn add_fallback_middleware(&mut self, middleware: BoxedMiddleware) {
247 self.fallback_middleware.push(middleware);
248 }
249
250 pub fn get_fallback(&self) -> Option<(Arc<BoxedHandler>, Vec<BoxedMiddleware>)> {
252 self.fallback_handler
253 .as_ref()
254 .map(|h| (h.clone(), self.fallback_middleware.clone()))
255 }
256
257 pub(crate) fn insert_get(&mut self, path: &str, handler: Arc<BoxedHandler>) {
259 insert_route(
260 &mut self.get_routes,
261 "GET",
262 path,
263 (handler, path.to_string()),
264 );
265 register_route("GET", path);
266 }
267
268 pub(crate) fn insert_post(&mut self, path: &str, handler: Arc<BoxedHandler>) {
270 insert_route(
271 &mut self.post_routes,
272 "POST",
273 path,
274 (handler, path.to_string()),
275 );
276 register_route("POST", path);
277 }
278
279 pub(crate) fn insert_put(&mut self, path: &str, handler: Arc<BoxedHandler>) {
281 insert_route(
282 &mut self.put_routes,
283 "PUT",
284 path,
285 (handler, path.to_string()),
286 );
287 register_route("PUT", path);
288 }
289
290 pub(crate) fn insert_patch(&mut self, path: &str, handler: Arc<BoxedHandler>) {
292 insert_route(
293 &mut self.patch_routes,
294 "PATCH",
295 path,
296 (handler, path.to_string()),
297 );
298 register_route("PATCH", path);
299 }
300
301 pub(crate) fn insert_delete(&mut self, path: &str, handler: Arc<BoxedHandler>) {
303 insert_route(
304 &mut self.delete_routes,
305 "DELETE",
306 path,
307 (handler, path.to_string()),
308 );
309 register_route("DELETE", path);
310 }
311
312 pub(crate) fn insert_get_alias(
319 &mut self,
320 alias_path: &str,
321 handler: Arc<BoxedHandler>,
322 canonical_path: &str,
323 ) {
324 self.get_routes
325 .insert(alias_path, (handler, canonical_path.to_string()))
326 .ok();
327 }
328
329 pub(crate) fn insert_post_alias(
332 &mut self,
333 alias_path: &str,
334 handler: Arc<BoxedHandler>,
335 canonical_path: &str,
336 ) {
337 self.post_routes
338 .insert(alias_path, (handler, canonical_path.to_string()))
339 .ok();
340 }
341
342 pub(crate) fn insert_put_alias(
345 &mut self,
346 alias_path: &str,
347 handler: Arc<BoxedHandler>,
348 canonical_path: &str,
349 ) {
350 self.put_routes
351 .insert(alias_path, (handler, canonical_path.to_string()))
352 .ok();
353 }
354
355 pub(crate) fn insert_patch_alias(
358 &mut self,
359 alias_path: &str,
360 handler: Arc<BoxedHandler>,
361 canonical_path: &str,
362 ) {
363 self.patch_routes
364 .insert(alias_path, (handler, canonical_path.to_string()))
365 .ok();
366 }
367
368 pub(crate) fn insert_delete_alias(
371 &mut self,
372 alias_path: &str,
373 handler: Arc<BoxedHandler>,
374 canonical_path: &str,
375 ) {
376 self.delete_routes
377 .insert(alias_path, (handler, canonical_path.to_string()))
378 .ok();
379 }
380
381 pub fn get<H, Fut>(mut self, path: &str, handler: H) -> RouteBuilder
383 where
384 H: Fn(Request) -> Fut + Send + Sync + 'static,
385 Fut: Future<Output = Response> + Send + 'static,
386 {
387 let handler: BoxedHandler = Box::new(move |req| Box::pin(handler(req)));
388 insert_route(
389 &mut self.get_routes,
390 "GET",
391 path,
392 (Arc::new(handler), path.to_string()),
393 );
394 register_route("GET", path);
395 RouteBuilder {
396 router: self,
397 last_path: path.to_string(),
398 _last_method: Method::Get,
399 }
400 }
401
402 pub fn post<H, Fut>(mut self, path: &str, handler: H) -> RouteBuilder
404 where
405 H: Fn(Request) -> Fut + Send + Sync + 'static,
406 Fut: Future<Output = Response> + Send + 'static,
407 {
408 let handler: BoxedHandler = Box::new(move |req| Box::pin(handler(req)));
409 insert_route(
410 &mut self.post_routes,
411 "POST",
412 path,
413 (Arc::new(handler), path.to_string()),
414 );
415 register_route("POST", path);
416 RouteBuilder {
417 router: self,
418 last_path: path.to_string(),
419 _last_method: Method::Post,
420 }
421 }
422
423 pub fn put<H, Fut>(mut self, path: &str, handler: H) -> RouteBuilder
425 where
426 H: Fn(Request) -> Fut + Send + Sync + 'static,
427 Fut: Future<Output = Response> + Send + 'static,
428 {
429 let handler: BoxedHandler = Box::new(move |req| Box::pin(handler(req)));
430 insert_route(
431 &mut self.put_routes,
432 "PUT",
433 path,
434 (Arc::new(handler), path.to_string()),
435 );
436 register_route("PUT", path);
437 RouteBuilder {
438 router: self,
439 last_path: path.to_string(),
440 _last_method: Method::Put,
441 }
442 }
443
444 pub fn patch<H, Fut>(mut self, path: &str, handler: H) -> RouteBuilder
446 where
447 H: Fn(Request) -> Fut + Send + Sync + 'static,
448 Fut: Future<Output = Response> + Send + 'static,
449 {
450 let handler: BoxedHandler = Box::new(move |req| Box::pin(handler(req)));
451 insert_route(
452 &mut self.patch_routes,
453 "PATCH",
454 path,
455 (Arc::new(handler), path.to_string()),
456 );
457 register_route("PATCH", path);
458 RouteBuilder {
459 router: self,
460 last_path: path.to_string(),
461 _last_method: Method::Patch,
462 }
463 }
464
465 pub fn delete<H, Fut>(mut self, path: &str, handler: H) -> RouteBuilder
467 where
468 H: Fn(Request) -> Fut + Send + Sync + 'static,
469 Fut: Future<Output = Response> + Send + 'static,
470 {
471 let handler: BoxedHandler = Box::new(move |req| Box::pin(handler(req)));
472 insert_route(
473 &mut self.delete_routes,
474 "DELETE",
475 path,
476 (Arc::new(handler), path.to_string()),
477 );
478 register_route("DELETE", path);
479 RouteBuilder {
480 router: self,
481 last_path: path.to_string(),
482 _last_method: Method::Delete,
483 }
484 }
485
486 pub fn match_route(
497 &self,
498 method: &hyper::Method,
499 path: &str,
500 ) -> Option<(Arc<BoxedHandler>, HashMap<String, String>, String)> {
501 let router = match *method {
502 hyper::Method::GET => &self.get_routes,
503 hyper::Method::POST => &self.post_routes,
504 hyper::Method::PUT => &self.put_routes,
505 hyper::Method::PATCH => &self.patch_routes,
506 hyper::Method::DELETE => &self.delete_routes,
507 hyper::Method::OPTIONS => return self.match_preflight(path),
508 _ => return None,
509 };
510
511 router.at(path).ok().map(|matched| {
512 let params: HashMap<String, String> = matched
513 .params
514 .iter()
515 .map(|(k, v)| (k.to_string(), v.to_string()))
516 .collect();
517 let (handler, pattern) = matched.value.clone();
518 (handler, params, pattern)
519 })
520 }
521
522 fn match_preflight(
531 &self,
532 path: &str,
533 ) -> Option<(Arc<BoxedHandler>, HashMap<String, String>, String)> {
534 let tables = [
535 &self.get_routes,
536 &self.post_routes,
537 &self.put_routes,
538 &self.patch_routes,
539 &self.delete_routes,
540 ];
541 for table in tables {
542 if let Ok(matched) = table.at(path) {
543 let params: HashMap<String, String> = matched
544 .params
545 .iter()
546 .map(|(k, v)| (k.to_string(), v.to_string()))
547 .collect();
548 let (_, pattern) = matched.value.clone();
549 let handler: BoxedHandler = Box::new(|_req| {
550 Box::pin(async move { Ok(crate::http::HttpResponse::new().status(204)) })
551 });
552 return Some((Arc::new(handler), params, pattern));
553 }
554 }
555 None
556 }
557}
558
559impl Default for Router {
560 fn default() -> Self {
561 Self::new()
562 }
563}
564
565pub struct RouteBuilder {
567 pub(crate) router: Router,
568 last_path: String,
569 #[allow(dead_code)]
570 _last_method: Method,
571}
572
573impl RouteBuilder {
574 pub fn name(self, name: &str) -> Router {
576 register_route_name(name, &self.last_path);
577 self.router
578 }
579
580 pub fn middleware<M: Middleware + 'static>(mut self, middleware: M) -> RouteBuilder {
590 let type_name = std::any::type_name::<M>();
592 let short_name = type_name.rsplit("::").next().unwrap_or(type_name);
593 update_route_middleware(&self.last_path, short_name);
594
595 self.router
596 .add_middleware(&self.last_path, into_boxed(middleware));
597 self
598 }
599
600 pub fn middleware_boxed(mut self, middleware: BoxedMiddleware) -> RouteBuilder {
603 update_route_middleware(&self.last_path, "BoxedMiddleware");
605
606 self.router
607 .route_middleware
608 .entry(self.last_path.clone())
609 .or_default()
610 .push(middleware);
611 self
612 }
613
614 pub fn get<H, Fut>(self, path: &str, handler: H) -> RouteBuilder
616 where
617 H: Fn(Request) -> Fut + Send + Sync + 'static,
618 Fut: Future<Output = Response> + Send + 'static,
619 {
620 self.router.get(path, handler)
621 }
622
623 pub fn post<H, Fut>(self, path: &str, handler: H) -> RouteBuilder
625 where
626 H: Fn(Request) -> Fut + Send + Sync + 'static,
627 Fut: Future<Output = Response> + Send + 'static,
628 {
629 self.router.post(path, handler)
630 }
631
632 pub fn put<H, Fut>(self, path: &str, handler: H) -> RouteBuilder
634 where
635 H: Fn(Request) -> Fut + Send + Sync + 'static,
636 Fut: Future<Output = Response> + Send + 'static,
637 {
638 self.router.put(path, handler)
639 }
640
641 pub fn patch<H, Fut>(self, path: &str, handler: H) -> RouteBuilder
643 where
644 H: Fn(Request) -> Fut + Send + Sync + 'static,
645 Fut: Future<Output = Response> + Send + 'static,
646 {
647 self.router.patch(path, handler)
648 }
649
650 pub fn delete<H, Fut>(self, path: &str, handler: H) -> RouteBuilder
652 where
653 H: Fn(Request) -> Fut + Send + Sync + 'static,
654 Fut: Future<Output = Response> + Send + 'static,
655 {
656 self.router.delete(path, handler)
657 }
658}
659
660impl From<RouteBuilder> for Router {
661 fn from(builder: RouteBuilder) -> Self {
662 builder.router
663 }
664}