use crate::http::FerroBody;
use async_trait::async_trait;
use std::sync::{Arc, OnceLock, RwLock};
pub type PreRouteResult = Result<hyper::Request<hyper::body::Incoming>, hyper::Response<FerroBody>>;
#[async_trait]
pub trait PreRouteMiddleware: Send + Sync {
async fn handle(&self, req: hyper::Request<hyper::body::Incoming>) -> PreRouteResult;
}
type BoxedPreRoute = Arc<dyn PreRouteMiddleware>;
static PRE_ROUTE_REGISTRY: OnceLock<RwLock<Vec<BoxedPreRoute>>> = OnceLock::new();
pub fn register_pre_route_middleware<M: PreRouteMiddleware + 'static>(middleware: M) {
let registry = PRE_ROUTE_REGISTRY.get_or_init(|| RwLock::new(Vec::new()));
if let Ok(mut vec) = registry.write() {
vec.push(Arc::new(middleware));
}
}
pub fn get_pre_route_middleware() -> Vec<BoxedPreRoute> {
PRE_ROUTE_REGISTRY
.get()
.and_then(|lock| lock.read().ok())
.map(|vec| vec.clone())
.unwrap_or_default()
}
pub fn rewrite_request_path(
req: hyper::Request<hyper::body::Incoming>,
new_path: &str,
) -> hyper::Request<hyper::body::Incoming> {
let (mut parts, body) = req.into_parts();
let query = parts
.uri
.query()
.map(|q| format!("?{q}"))
.unwrap_or_default();
let new_uri_str = format!("{new_path}{query}");
if let Ok(new_uri) = new_uri_str.parse::<hyper::Uri>() {
parts.uri = new_uri;
}
hyper::Request::from_parts(parts, body)
}