use axum::{ extract::{Path, State}, routing::{get, post}, Json, Router, }; use serde::Deserialize; use crate::errors::AppResult; use crate::state::AppState; pub fn routes() -> Router { Router::new() .route("/presence/:fingerprint", get(get_presence)) .route("/presence/batch", post(batch_presence)) } fn normalize_fp(fp: &str) -> String { fp.chars().filter(|c| c.is_ascii_hexdigit()).collect::().to_lowercase() } async fn get_presence( State(state): State, Path(fingerprint): Path, ) -> AppResult> { let fp = normalize_fp(&fingerprint); let online = state.is_online(&fp).await; let devices = state.device_count(&fp).await; Ok(Json(serde_json::json!({ "fingerprint": fp, "online": online, "devices": devices, }))) } #[derive(Deserialize)] struct BatchRequest { fingerprints: Vec, } async fn batch_presence( _auth: crate::auth_middleware::AuthFingerprint, State(state): State, Json(req): Json, ) -> AppResult> { let mut results = Vec::new(); for fp in &req.fingerprints { let fp = normalize_fp(fp); let online = state.is_online(&fp).await; let devices = state.device_count(&fp).await; results.push(serde_json::json!({ "fingerprint": fp, "online": online, "devices": devices, })); } Ok(Json(serde_json::json!({ "results": results }))) }