use axum::{extract::State, Json};
use serde::Serialize;
use crate::error::Result;
use crate::state::AppState;
#[derive(Debug, Serialize)]
pub struct StatsResponse {
pub graph: GraphStatsDto,
pub server: ServerStatsDto,
}
#[derive(Debug, Serialize)]
pub struct GraphStatsDto {
pub triple_count: usize,
pub subject_count: usize,
pub predicate_count: usize,
pub object_count: usize,
}
#[derive(Debug, Serialize)]
pub struct ServerStatsDto {
pub connected_clients: usize,
pub uptime_seconds: u64,
pub version: String,
}
pub async fn get_stats(State(state): State<AppState>) -> Result<Json<StatsResponse>> {
let stats = state.stats().await;
Ok(Json(StatsResponse {
graph: GraphStatsDto {
triple_count: stats.triple_count,
subject_count: stats.subject_count,
predicate_count: stats.predicate_count,
object_count: stats.object_count,
},
server: ServerStatsDto {
connected_clients: stats.connected_clients,
uptime_seconds: 0, version: env!("CARGO_PKG_VERSION").to_string(),
},
}))
}
#[derive(Debug, Serialize)]
pub struct HealthResponse {
pub status: String,
pub components: ComponentHealth,
}
#[derive(Debug, Serialize)]
pub struct ComponentHealth {
pub graph: ComponentStatus,
pub logic: ComponentStatus,
}
#[derive(Debug, Serialize)]
pub struct ComponentStatus {
pub status: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub message: Option<String>,
}
#[derive(Debug, Serialize)]
pub struct FlushResponse {
pub ok: bool,
}
pub async fn flush_data(State(state): State<AppState>) -> Result<Json<FlushResponse>> {
{
let graph = state.graph.read().await;
graph.flush()?;
}
Ok(Json(FlushResponse { ok: true }))
}
pub async fn health_check(State(state): State<AppState>) -> Json<HealthResponse> {
let graph_health = {
let graph = state.graph.read().await;
let stats = graph.stats();
ComponentStatus {
status: "healthy".to_string(),
message: Some(format!("{} triples", stats.triple_count)),
}
};
let logic_health = {
let logic = state.logic.read().await;
let stats = logic.stats();
ComponentStatus {
status: "healthy".to_string(),
message: Some(format!("{} rules evaluated", stats.rules_evaluated)),
}
};
let overall_status = if graph_health.status == "healthy" && logic_health.status == "healthy" {
"healthy"
} else if graph_health.status == "unhealthy" || logic_health.status == "unhealthy" {
"unhealthy"
} else {
"degraded"
};
Json(HealthResponse {
status: overall_status.to_string(),
components: ComponentHealth {
graph: graph_health,
logic: logic_health,
},
})
}