use std::{pin::Pin, sync::Arc}; use async_trait::async_trait; use http::request::Parts; use hyper::{Request, StatusCode, body::Incoming, service::Service}; use tokio::net::TcpStream; use crate::server::{GeneralResponse, TcpIntercept, custom_resp, default_response}; // The routes itself #[async_trait] pub trait Route where T: Matcher, { fn matcher(&self, m: &T, req: &Request) -> bool; async fn call(&self, m: &T, parts: Parts) -> Result; } // Matcher, essentially just a router that contains routes and some other features #[async_trait] pub trait Matcher: Clone + Send + Sync + 'static { // Essentially a kind of "middleware", a universal matcher. If it doesn't match, it won't // route. async fn unimatch( &mut self, req: &Request, ) -> (bool, Option>); // Return list of routes associated with self matcher fn retrieve(&self) -> Vec + Sync + Send>>; // Wrap self into matcher service fn service(self) -> MatcherService { MatcherService::new(self) } // Do something with TCP stream #[allow(unused_variables)] fn stream(&mut self, stream: &TcpStream) {} // Body parser - made universal for api server cause lazy #[allow(unused_variables)] async fn body(&mut self, body: Incoming) -> Option> { None } } // Wrapper service, wraps matcher into a service #[derive(Clone)] pub struct MatcherService where T: Matcher, { inner: T, } impl MatcherService where T: Matcher, { pub fn new(inner: T) -> Self { Self { inner } } } impl Service> for MatcherService where T: Matcher, { type Response = GeneralResponse; type Error = hyper::Error; type Future = Pin> + Send>>; fn call(&self, req: Request) -> Self::Future { let mut matcher = self.inner.clone(); Box::pin(async move { let unimatched = matcher.unimatch(&req).await; if !unimatched.0 { match unimatched.1 { Some(x) => { return x; } None => { return Ok(custom_resp( StatusCode::NOT_FOUND, "Could not match route".to_string(), ) .await); } } } for r in matcher.retrieve() { if r.matcher(&matcher, &req) { let (parts, body) = req.into_parts(); if let Some(resp) = matcher.body(body).await { return resp; } return r.call(&matcher, parts).await; } } Ok(default_response().await) }) } } impl TcpIntercept for MatcherService where T: Matcher, { fn stream(&mut self, stream: &TcpStream) { self.inner.stream(stream); } }