use crate::{Outcome, internals::AppContext};
use feather_runtime::http::{Request, Response};
pub trait Middleware: Send + Sync {
fn handle(&self, request: &mut Request, response: &mut Response, ctx: &AppContext) -> Outcome;
}
#[derive(Debug)]
pub enum MiddlewareResult {
Next,
NextRoute,
End,
}
impl Middleware for [&Box<dyn Middleware>]
where
Self: Send + Sync,
{
fn handle(&self, request: &mut Request, response: &mut Response, ctx: &AppContext) -> Outcome {
for middleware in self {
let res = middleware.handle(request, response, ctx)?;
match res {
MiddlewareResult::Next => continue,
MiddlewareResult::NextRoute => return Ok(MiddlewareResult::NextRoute),
MiddlewareResult::End => return Ok(MiddlewareResult::End),
}
}
Ok(MiddlewareResult::Next)
}
}
impl<F> Middleware for F
where
F: Fn(&mut Request, &mut Response, &AppContext) -> Outcome + Send + Sync,
{
fn handle(&self, req: &mut Request, res: &mut Response, ctx: &AppContext) -> Outcome {
self(req, res, ctx)
}
}
pub fn _chainer<A, B>(a: A, b: B) -> impl Middleware
where
A: Middleware,
B: Middleware,
{
move |request: &mut Request, response: &mut Response, ctx: &AppContext| -> Outcome {
match a.handle(request, response, ctx) {
Ok(MiddlewareResult::Next) => b.handle(request, response, ctx),
Ok(MiddlewareResult::NextRoute) => Ok(MiddlewareResult::NextRoute),
Ok(MiddlewareResult::End) => Ok(MiddlewareResult::End),
Err(e) => Err(e),
}
}
}
#[macro_export]
macro_rules! chain {
($first:expr, $($rest:expr),+ $(,)?) => {{
let chained = $first;
$(let chained = $crate::middlewares::common::_chainer(chained, $rest);)+
chained
}};
}
pub use chain;