// Middleware composition operators
//
// Simple composition using Mars Handler pattern:
// - Handlers run sequentially
// - If a handler sends a response, subsequent handlers are skipped
// - Use ctx.is_response_sent() to check if halted
// ============================================================================
// Sequential Composition
// ============================================================================
///|
/// Compose array of middlewares into single middleware
/// Runs handlers sequentially, stops if response is sent
pub fn pipeline(middlewares : Array[Middleware]) -> Middleware {
let handlers : Array[@mars.Handler] = []
for mw in middlewares {
let Middleware(handler) = mw
handlers.push(handler)
}
Middleware(@mars.compose(handlers))
}
///|
/// Sequential composition: run m1, then m2 if m1 didn't send response
/// Usage: m1 |> then_(m2)
pub fn then_(m1 : Middleware, m2 : Middleware) -> Middleware {
pipeline([m1, m2])
}
///|
/// Method-style composition: then(m1, m2)
pub fn then(m1 : Middleware, m2 : Middleware) -> Middleware {
then_(m1, m2)
}
///|
/// Method-style composition on Middleware type
/// Usage: logger().Middleware::then(cors())
/// Note: Using explicit type to avoid needing mars import in consumer packages
pub fn Middleware::then(self : Middleware, other : Middleware) -> Middleware {
then_(self, other)
}
// ============================================================================
// Identity Middleware
// ============================================================================
///|
/// Identity middleware - passes through unchanged
pub fn identity() -> Middleware {
Middleware(@mars.Handler(async fn(_ctx) { () }))
}
// ============================================================================
// Run Middleware
// ============================================================================
///|
/// Execute middleware and check if it halted
/// Returns true if middleware sent a response (halted)
pub async fn run(middleware : Middleware, ctx : Ctx) -> Bool raise Error {
let Middleware(@mars.Handler(h)) = middleware
h(ctx)
ctx.is_response_sent()
}
///|
/// Execute middleware and convert unexpected errors to 500 response.
/// Returns true if middleware halted request handling.
pub async fn run_or_500(
middleware : Middleware,
ctx : Ctx,
message_prefix? : String = "Internal Server Error: ",
) -> Bool {
run(middleware, ctx) catch {
e => {
ctx.text(message_prefix + e.to_string(), status=500)
true
}
}
}