use std::sync::Arc;
use axum::{
Json, Router,
extract::{Query, State},
http::{HeaderValue, StatusCode, header::CONTENT_TYPE},
response::IntoResponse,
routing::get,
};
use relay_core_runtime::{
CoreAuditQuery, CoreAuditSnapshot, CoreMetrics, CoreState, CoreStatusSnapshot,
audit::{AuditActor, AuditEventKind, AuditOutcome},
};
use serde::Deserialize;
pub fn router(state: Arc<CoreState>) -> Router {
Router::new()
.route("/api/v1/metrics", get(get_metrics))
.route("/api/v1/metrics/prometheus", get(get_metrics_prometheus))
.route("/api/v1/audit", get(get_audit))
.route("/api/v1/status", get(get_status))
.with_state(state)
}
async fn get_metrics(State(state): State<Arc<CoreState>>) -> Json<CoreMetrics> {
Json(state.get_metrics().await)
}
async fn get_metrics_prometheus(State(state): State<Arc<CoreState>>) -> impl IntoResponse {
(
StatusCode::OK,
[(
CONTENT_TYPE,
HeaderValue::from_static("text/plain; version=0.0.4; charset=utf-8"),
)],
state.get_metrics_prometheus_text().await,
)
}
async fn get_status(State(state): State<Arc<CoreState>>) -> Json<CoreStatusSnapshot> {
Json(state.status_snapshot())
}
#[derive(Debug, Deserialize)]
struct AuditQueryParams {
since_ms: Option<u64>,
until_ms: Option<u64>,
actor: Option<String>,
kind: Option<String>,
outcome: Option<String>,
limit: Option<usize>,
}
async fn get_audit(
State(state): State<Arc<CoreState>>,
Query(params): Query<AuditQueryParams>,
) -> Json<CoreAuditSnapshot> {
let query = CoreAuditQuery {
since_ms: params.since_ms,
until_ms: params.until_ms,
actor: params.actor.as_deref().and_then(|v| v.parse::<AuditActor>().ok()),
kind: params
.kind
.as_deref()
.and_then(|v| v.parse::<AuditEventKind>().ok()),
outcome: params
.outcome
.as_deref()
.and_then(|v| v.parse::<AuditOutcome>().ok()),
limit: params.limit.unwrap_or(50),
};
Json(state.query_audit_snapshot(query).await)
}