use crate::fcgi_context::FcgiContext;
use crate::pipe::Pipe;
use crate::status;
use std::collections::BTreeMap;
type RouteParams = BTreeMap<String, String>;
type RouterCallback = Box<dyn Fn(FcgiContext, RouteParams) -> FcgiContext + Send + Sync>;
#[derive(Default)]
pub struct Router {
map: BTreeMap<&'static str, matchit::Router<RouterCallback>>,
}
impl Router {
pub fn new() -> Router {
Self {
map: BTreeMap::new(),
}
}
pub fn register<C, P>(mut self, method: &'static str, path: P, callback: C) -> Self
where
P: Into<String>,
C: Fn(FcgiContext, RouteParams) -> FcgiContext,
C: 'static + Send + Sync,
{
let _ = self
.map
.entry(method)
.or_default()
.insert(path, Box::new(callback));
self
}
pub fn get<C, P>(self, path: P, callback: C) -> Self
where
P: Into<String>,
C: Fn(FcgiContext, RouteParams) -> FcgiContext,
C: 'static + Send + Sync,
{
self.register("GET", path, callback)
}
pub fn post<C, P>(self, path: P, callback: C) -> Self
where
P: Into<String>,
C: Fn(FcgiContext, RouteParams) -> FcgiContext,
C: 'static + Send + Sync,
{
self.register("POST", path, callback)
}
pub fn put<C, P>(self, path: P, callback: C) -> Self
where
P: Into<String>,
C: Fn(FcgiContext, RouteParams) -> FcgiContext,
C: 'static + Send + Sync,
{
self.register("PUT", path, callback)
}
pub fn delete<C, P>(self, path: P, callback: C) -> Self
where
P: Into<String>,
C: Fn(FcgiContext, RouteParams) -> FcgiContext,
C: 'static + Send + Sync,
{
self.register("DELETE", path, callback)
}
}
impl Pipe for Router {
fn run(&self, ctx: FcgiContext) -> FcgiContext {
let Some(router) = self.map.get(ctx.method()) else {
return ctx.halt().with_status(status::METHOD_NOT_ALLOWED);
};
let Ok(entry) = router.at(ctx.path()) else {
return ctx.halt().with_status(status::NOT_FOUND);
};
let mut params = BTreeMap::new();
for (key, value) in entry.params.iter() {
params.insert(key.to_string(), value.to_string());
}
(entry.value)(ctx, params)
}
}