use std::sync::atomic::Ordering;
use std::sync::Arc;
use axum::extract::{Request, State};
use axum::http::{header, HeaderValue, StatusCode};
use axum::response::IntoResponse;
use crate::auth::{Scope, TenantAccess};
use crate::error::{ApiError, ApiResult};
use crate::request::{json_response, principal};
use crate::routes;
use crate::tenants::AppState;
use crate::types::{body, Health};
pub async fn healthz() -> ApiResult {
Ok(json_response(
StatusCode::OK,
&body(&Health {
status: "ok".into(),
}),
))
}
pub async fn readyz(State(state): State<Arc<AppState>>) -> ApiResult {
if state.ready.load(Ordering::Acquire) {
Ok(json_response(
StatusCode::OK,
&body(&Health {
status: "ready".into(),
}),
))
} else {
Err(ApiError::new(
StatusCode::SERVICE_UNAVAILABLE,
"not_ready",
"server is starting or shutting down",
))
}
}
pub async fn metrics(State(state): State<Arc<AppState>>, req: Request) -> ApiResult {
let principal = if state.cfg.metrics_public {
None
} else {
let principal = principal(&req)?;
principal.require(Scope::Admin)?;
Some(principal)
};
let mut saturation = state.saturation();
if let Some(TenantAccess::Only(allowed)) = principal.as_ref().map(|p| &p.tenants) {
saturation.tenants.retain(|t| allowed.contains(&t.name));
}
let text = state.metrics.render(&saturation);
Ok((
[(
header::CONTENT_TYPE,
HeaderValue::from_static("text/plain; version=0.0.4; charset=utf-8"),
)],
text,
)
.into_response())
}
pub async fn openapi() -> ApiResult {
Ok(json_response(StatusCode::OK, routes::openapi()))
}