1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
//! Middleware pipeline —Sequential execution model.
//!
//! Middlewares are called in registration order. Each middleware can
//! inspect or modify the request. The final handler (router) is called
//! after all middlewares have passed.
use rust_webx_core::error::Result;
use rust_webx_core::http::IHttpContext;
use rust_webx_core::middleware::IMiddleware;
use std::future::Future;
use std::pin::Pin;
use std::sync::Arc;
/// Boxed final handler function type.
pub type HandlerFn = Arc<
dyn for<'a> Fn(
&'a mut dyn IHttpContext,
) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'a>>
+ Send
+ Sync,
>;
pub struct MiddlewarePipeline {
middlewares: Vec<Arc<dyn IMiddleware>>,
}
impl MiddlewarePipeline {
pub fn new() -> Self {
Self {
middlewares: Vec::new(),
}
}
pub fn add_middleware(&mut self, middleware: Arc<dyn IMiddleware>) {
self.middlewares.push(middleware);
}
/// Execute middleware onion: invoke forward, final handler, after hooks reverse.
///
/// Supports short-circuit: if a middleware's `invoke` returns `ControlFlow::Break(())`,
/// remaining middleware and the final handler are skipped. `after` hooks on
/// already-executed middleware still run in reverse order.
pub async fn execute(
&self,
ctx: &mut dyn IHttpContext,
final_handler: HandlerFn,
) -> Result<()> {
use std::ops::ControlFlow;
let mut executed: Vec<Arc<dyn IMiddleware>> = Vec::new();
let mut short_circuited = false;
// Forward pass: invoke each middleware, track executed for after hooks
for middleware in &self.middlewares {
match middleware.invoke(ctx).await? {
ControlFlow::Continue(()) => executed.push(Arc::clone(middleware)),
ControlFlow::Break(()) => {
short_circuited = true;
break;
}
}
}
// Run the final handler (router) only if not short-circuited
if !short_circuited {
final_handler(ctx).await?;
}
// Reverse pass: after hooks on executed middleware only
for middleware in executed.into_iter().rev() {
middleware.after(ctx).await?;
}
Ok(())
}
}
impl Default for MiddlewarePipeline {
fn default() -> Self {
Self::new()
}
}