Skip to main content

ruest/http/
server.rs

1use std::net::SocketAddr;
2use std::sync::Arc;
3
4use axum::routing::get;
5use axum::Router;
6use crate::core::RuestApplication;
7use crate::di::Container;
8use tower_http::cors::{Any, CorsLayer};
9use tower_http::trace::TraceLayer;
10
11use super::error::HttpError;
12use super::middleware::LoggerMiddleware;
13
14/// Build and serve a pre-assembled Axum router (routes monomorphisées au compile-time).
15pub async fn serve(app: RuestApplication, router: Router) -> Result<(), HttpError> {
16    let built = finalize_router(app, router)?;
17    let addr: SocketAddr = format!("{}:{}", built.host, built.port)
18        .parse()
19        .map_err(|e: std::net::AddrParseError| HttpError::Message(e.to_string()))?;
20
21    tracing::info!("RUEST listening on http://{addr}");
22
23    let listener = tokio::net::TcpListener::bind(addr)
24        .await
25        .map_err(|e: std::io::Error| HttpError::Message(e.to_string()))?;
26
27    axum::serve(listener, built.router)
28        .await
29        .map_err(|e: std::io::Error| HttpError::Message(e.to_string()))?;
30
31    Ok(())
32}
33
34struct BuiltRouter {
35    router: Router,
36    host: String,
37    port: u16,
38}
39
40fn finalize_router(app: RuestApplication, router: Router) -> Result<BuiltRouter, HttpError> {
41    let container = Arc::new(app.container);
42
43    let router = router
44        .route("/health", get(|| async { "ok" }))
45        .layer(TraceLayer::new_for_http())
46        .layer(CorsLayer::new().allow_origin(Any).allow_methods(Any))
47        .layer(LoggerMiddleware)
48        .layer(axum::Extension(ContainerExtension(Arc::clone(&container))));
49
50    Ok(BuiltRouter {
51        router,
52        host: app.host,
53        port: app.port,
54    })
55}
56
57/// DI container dans les extensions de requête (zero-copy : `Arc` partagé).
58#[derive(Clone)]
59pub struct ContainerExtension(pub Arc<Container>);