ferro_rs/middleware/registry.rs
1//! Middleware registry for global middleware
2//!
3//! Configure global middleware in `bootstrap.rs` using the `global_middleware!` macro,
4//! or use `Server::middleware()` for manual configuration.
5
6use super::{into_boxed, BoxedMiddleware, Middleware};
7use std::sync::{OnceLock, RwLock};
8
9/// Global middleware registry (populated via `global_middleware!` macro in bootstrap.rs)
10static GLOBAL_MIDDLEWARE: OnceLock<RwLock<Vec<BoxedMiddleware>>> = OnceLock::new();
11
12/// Global middleware names registry (for introspection)
13static GLOBAL_MIDDLEWARE_NAMES: OnceLock<RwLock<Vec<String>>> = OnceLock::new();
14
15/// Register a global middleware that runs on every request
16///
17/// Called by the `global_middleware!` macro. Middleware runs in registration order.
18///
19/// # Example
20///
21/// ```rust,ignore
22/// // In bootstrap.rs
23/// global_middleware!(LoggingMiddleware);
24/// global_middleware!(CorsMiddleware);
25/// ```
26pub fn register_global_middleware<M: Middleware + 'static>(middleware: M) {
27 // Track the middleware name for introspection
28 let type_name = std::any::type_name::<M>();
29 let short_name = type_name.rsplit("::").next().unwrap_or(type_name);
30 let names_registry = GLOBAL_MIDDLEWARE_NAMES.get_or_init(|| RwLock::new(Vec::new()));
31 if let Ok(mut names) = names_registry.write() {
32 names.push(short_name.to_string());
33 }
34
35 let registry = GLOBAL_MIDDLEWARE.get_or_init(|| RwLock::new(Vec::new()));
36 if let Ok(mut vec) = registry.write() {
37 vec.push(into_boxed(middleware));
38 }
39}
40
41/// Get global middleware names for introspection
42pub fn get_global_middleware_info() -> Vec<String> {
43 GLOBAL_MIDDLEWARE_NAMES
44 .get()
45 .and_then(|lock| lock.read().ok())
46 .map(|vec| vec.clone())
47 .unwrap_or_default()
48}
49
50/// Get all registered global middleware
51///
52/// Used internally by `Server::from_config()` to apply middleware.
53pub fn get_global_middleware() -> Vec<BoxedMiddleware> {
54 GLOBAL_MIDDLEWARE
55 .get()
56 .and_then(|lock| lock.read().ok())
57 .map(|vec| vec.clone())
58 .unwrap_or_default()
59}
60
61/// Registry for global middleware that runs on every request
62///
63/// # Example
64///
65/// ```rust,ignore
66/// Server::from_config(router)
67/// .middleware(LoggingMiddleware) // Global middleware
68/// .middleware(CorsMiddleware)
69/// .run()
70/// .await;
71/// ```
72pub struct MiddlewareRegistry {
73 /// Middleware that runs on every request (in order)
74 global: Vec<BoxedMiddleware>,
75}
76
77impl MiddlewareRegistry {
78 /// Create a new empty middleware registry
79 pub fn new() -> Self {
80 Self { global: Vec::new() }
81 }
82
83 /// Create a registry pre-populated with globally registered middleware
84 ///
85 /// This pulls middleware registered via `global_middleware!` in bootstrap.rs.
86 pub fn from_global() -> Self {
87 Self {
88 global: get_global_middleware(),
89 }
90 }
91
92 /// Append global middleware that runs on every request
93 ///
94 /// Global middleware runs in the order they are added, before any
95 /// route-specific middleware.
96 ///
97 /// # Example
98 ///
99 /// ```rust,ignore
100 /// m.append(LoggingMiddleware)
101 /// .append(CorsMiddleware)
102 /// ```
103 pub fn append<M: Middleware + 'static>(mut self, middleware: M) -> Self {
104 self.global.push(into_boxed(middleware));
105 self
106 }
107
108 /// Get the list of global middleware
109 pub fn global_middleware(&self) -> &[BoxedMiddleware] {
110 &self.global
111 }
112}
113
114impl Default for MiddlewareRegistry {
115 fn default() -> Self {
116 Self::new()
117 }
118}