use axum::extract::State;
use axum::http::HeaderMap;
use axum::response::IntoResponse;
use crate::control::server::http::auth::{ApiError, AppState, resolve_identity};
pub async fn status(
headers: HeaderMap,
State(state): State<AppState>,
) -> Result<impl IntoResponse, ApiError> {
let _identity = resolve_identity(&headers, &state, "http")?;
let wal_next_lsn = state.shared.wal.next_lsn().as_u64();
let node_id = state.shared.node_id;
let user_count = state.shared.credentials.list_user_details().len();
let user_details = state.shared.credentials.list_user_details();
let mut tenant_ids = std::collections::HashSet::new();
for user in &user_details {
tenant_ids.insert(user.tenant_id.as_u32());
}
let tenant_count = tenant_ids.len();
let audit_entries = match state.shared.audit.lock() {
Ok(log) => log.all().len(),
Err(p) => p.into_inner().all().len(),
};
let mut result = serde_json::json!({
"node_id": node_id,
"wal_next_lsn": wal_next_lsn,
"users": user_count,
"tenants": tenant_count,
"audit_entries": audit_entries,
});
if let Some(ref topo) = state.shared.cluster_topology {
let topo = topo.read().unwrap_or_else(|p| p.into_inner());
let nodes: Vec<serde_json::Value> = topo
.all_nodes()
.map(|n| {
serde_json::json!({
"node_id": n.node_id,
"addr": n.addr,
"state": format!("{:?}", n.state),
})
})
.collect();
let raft_groups = if let Some(ref routing) = state.shared.cluster_routing {
let routing = routing.read().unwrap_or_else(|p| p.into_inner());
routing
.group_ids()
.iter()
.filter_map(|&gid| {
routing.group_info(gid).map(|info| {
serde_json::json!({
"group_id": gid,
"leader": info.leader,
"members": info.members,
"vshard_count": routing.vshards_for_group(gid).len(),
})
})
})
.collect::<Vec<_>>()
} else {
vec![]
};
result["cluster"] = serde_json::json!({
"nodes": nodes,
"raft_groups": raft_groups,
});
}
if let Some(ref tracker) = state.shared.migration_tracker {
let snapshots = tracker.snapshot();
result["migrations"] = serde_json::json!(
snapshots
.iter()
.map(|s| serde_json::json!({
"vshard_id": s.vshard_id,
"phase": s.phase,
"elapsed_ms": s.elapsed_ms,
"is_active": s.is_active,
}))
.collect::<Vec<_>>()
);
}
Ok(axum::Json(result))
}