use std::collections::HashMap; use axum::{extract::State, response::IntoResponse, Json}; use serde::{Deserialize, Serialize}; use crate::{service::Services, Check, Error, Status}; pub mod services; pub fn router() -> axum::Router { use axum::routing::get; axum::Router::new() .route("/healthcheck", get(healthcheck)) .merge(services::router()) .fallback(fallback) } #[derive(Debug, Clone, Default, Serialize, Deserialize)] pub struct Health { pub status: Status, pub output: Option, pub checks: HashMap, } impl From for Health { fn from(value: T) -> Self { Health { status: Status::Fail, output: Some(value.to_string()), ..Default::default() } } } impl IntoResponse for Health { fn into_response(self) -> axum::response::Response { Json(self).into_response() } } pub async fn healthcheck(State(services): State) -> Health { let checks = match services.check().await { Ok(c) => c, Err(err) => { return Health { status: Status::Fail, output: Some(err.to_string()), ..Default::default() } } }; let (status, output) = match checks .values() .filter(|s| !matches!(s.status, Status::Pass)) .count() { 0 => (Status::Pass, None), 1 => (Status::Fail, Some("1 issue detected".to_string())), n => (Status::Fail, Some(format!("{n} issues detected"))), }; Health { status, output, checks, } } pub async fn fallback(uri: axum::http::Uri) -> Error { Error::RouteNotFound(uri) }