Skip to main content

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}