use axum::{
extract::{Request, State},
http::HeaderMap,
middleware::Next,
response::Response,
};
use std::sync::Arc;
use crate::{client::{proxy_request, ProxyConfig}, error::ProxyError, routing::{extract_subdomain, RouteResolver}};
#[derive(Debug, Clone)]
pub struct Subdomain(pub String);
pub async fn subdomain_extractor(
headers: HeaderMap,
mut request: Request,
next: Next,
) -> Response {
let subdomain = headers
.get("host")
.and_then(|host| host.to_str().ok())
.and_then(extract_subdomain);
if let Some(subdomain) = subdomain {
request.extensions_mut().insert(Subdomain(subdomain));
}
next.run(request).await
}
pub async fn subdomain_proxy<R>(
State((resolver, config)): State<(Arc<R>, ProxyConfig)>,
request: Request,
) -> Result<Response, ProxyError>
where
R: RouteResolver,
{
let subdomain = request
.extensions()
.get::<Subdomain>()
.map(|s| s.0.clone());
let subdomain = subdomain.ok_or_else(|| ProxyError::RouteNotFound("No subdomain found".to_string()))?;
let backend_url = resolver
.resolve(&subdomain)
.await
.ok_or_else(|| ProxyError::RouteNotFound(format!("No route for subdomain: {}", subdomain)))?;
proxy_request(request, &backend_url, config).await
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_subdomain_type() {
let subdomain = Subdomain("api".to_string());
assert_eq!(subdomain.0, "api");
}
}