use std::sync::Arc;
use http::{Method, Request, Response};
use hyper::body::Incoming;
use crate::{BoxBody, BoxFuture, Error, HandlerFn, Router, error::RequestContext};
pub trait RegisterRoute {
fn register_route(self, router: &mut Router);
}
pub struct Next {
pub(crate) chain:
Box<dyn FnOnce(Request<Incoming>) -> BoxFuture<'static, Response<BoxBody>> + Send>,
}
impl Next {
pub async fn run(self, req: Request<Incoming>) -> Response<BoxBody> {
(self.chain)(req).await
}
}
#[allow(clippy::type_complexity)]
pub struct InternalMiddlewareLayer {
pub(crate) run:
Arc<dyn Fn(Request<Incoming>, Next) -> BoxFuture<'static, Response<BoxBody>> + Send + Sync>,
}
pub fn from_fn<F, Fut>(f: F) -> InternalMiddlewareLayer
where
F: Fn(Request<Incoming>, Next) -> Fut + Clone + Send + Sync + 'static,
Fut: Future<Output = Result<Response<BoxBody>, Error>> + Send + 'static,
{
InternalMiddlewareLayer {
run: Arc::new(move |req, next| {
let f = f.clone();
let context_frame = RequestContext::from_request(&req);
Box::pin(async move {
match f(req, next).await {
Ok(res) => res,
Err(err) => err.into_response_with_context(&context_frame),
}
})
}),
}
}
#[allow(dead_code)]
pub struct Module {
name: String,
pub(crate) endpoints: Vec<(Method, String, HandlerFn)>,
pub(crate) middleware: Vec<InternalMiddlewareLayer>,
}
impl Module {
pub fn new(name: &str) -> Self {
Self {
name: name.to_string(),
endpoints: Vec::new(),
middleware: Vec::new(),
}
}
pub fn add_endpoint(mut self, method: Method, path: &str, handler: HandlerFn) -> Self {
self.endpoints.push((method, path.to_string(), handler));
self
}
pub fn wrap(mut self, layer: InternalMiddlewareLayer) -> Self {
self.middleware.push(layer);
self
}
}