iconoclast 0.3.1

Reusable code for Rust-based business μServices
Documentation
//! managment service (health check etc.) implemented in hyper

use http_body_util::Full;
use hyper::body::{Bytes, Incoming};
use hyper::server::conn::http1;
use hyper::{Method, Request, Response, StatusCode};
use hyper_util::rt::TokioIo;
use hyper_util::service::TowerToHyperService;
use std::convert::Infallible;
use std::net::SocketAddr;
use tokio::net::TcpListener;
use tower::ServiceBuilder;
use tracing::error;

pub async fn run(management_port: u16) -> tokio::io::Result<()> {
    let addr = SocketAddr::from(([0, 0, 0, 0], management_port));

    let listener = TcpListener::bind(addr).await?;

    loop {
        let (stream, _) = listener.accept().await?;
        let io = TokioIo::new(stream);

        let svc = ServiceBuilder::new().service_fn(move |request: Request<Incoming>| async move {
            #[expect(clippy::single_match_else)]
            let response = match (request.method(), request.uri().path()) {
                (&Method::GET, "/healthz") => {
                    Response::new(Full::new(Bytes::from(r#"{"status": "healthy"}"#)))
                }
                _ => {
                    let mut not_found = Response::new(Full::new(Bytes::new()));
                    *not_found.status_mut() = StatusCode::NOT_FOUND;
                    not_found
                }
            };

            Result::<_, Infallible>::Ok(response)
        });
        let svc = TowerToHyperService::new(svc);

        tokio::task::spawn(async move {
            if let Err(err) = http1::Builder::new().serve_connection(io, svc).await {
                error!("Error serving connection: {err:?}");
            }
        });
    }
}