spacegate_kernel/helper_layers/
route.rs

1use std::{convert::Infallible, ops::Index};
2
3use futures_util::future::BoxFuture;
4pub use hyper::http::request::Parts;
5use hyper::{Request, Response};
6
7use crate::{extension::Matched, SgBody};
8
9pub trait Router: Clone {
10    type Index: Clone;
11    fn route(&self, req: &mut Request<SgBody>) -> Option<Self::Index>;
12}
13
14#[derive(Debug, Clone)]
15pub struct RouterService<S, R, F>
16where
17    R: Router,
18{
19    services: S,
20    fallback: F,
21    router: R,
22}
23
24impl<S, R, F> RouterService<S, R, F>
25where
26    R: Router,
27    S: Index<R::Index>,
28{
29    pub fn new(services: S, router: R, fallback: F) -> Self {
30        Self { services, router, fallback }
31    }
32}
33
34impl<S, R, F> hyper::service::Service<Request<SgBody>> for RouterService<S, R, F>
35where
36    R: Router + Send + Sync + 'static,
37    R::Index: Send + Sync + 'static + Clone,
38    S: Index<R::Index>,
39    S::Output: hyper::service::Service<Request<SgBody>, Response = Response<SgBody>, Error = Infallible> + Send + 'static,
40    F: hyper::service::Service<Request<SgBody>, Response = Response<SgBody>, Error = Infallible> + Send + 'static,
41    <F as hyper::service::Service<hyper::Request<SgBody>>>::Future: std::marker::Send,
42    <S::Output as hyper::service::Service<hyper::Request<SgBody>>>::Future: std::marker::Send,
43{
44    type Error = Infallible;
45    type Response = Response<SgBody>;
46    type Future = BoxFuture<'static, Result<Self::Response, Self::Error>>;
47    // #[instrument("router", skip_all, fields(http.uri =? req.uri(), http.method =? req.method()))]
48    fn call(&self, mut req: Request<SgBody>) -> Self::Future {
49        let fut: Self::Future = if let Some(index) = self.router.route(&mut req) {
50            req.extensions_mut().insert(Matched {
51                index: index.clone(),
52                router: self.router.clone(),
53            });
54            let fut = self.services.index(index).call(req);
55            Box::pin(fut)
56        } else {
57            let fut = self.fallback.call(req);
58            Box::pin(fut)
59        };
60        fut
61    }
62}