diff --git a/server/src/api/sessions.rs b/server/src/api/sessions.rs new file mode 100644 index 0000000..f49b8de --- /dev/null +++ b/server/src/api/sessions.rs @@ -0,0 +1,88 @@ +use actix_web::{web, HttpResponse}; +use serde::{Deserialize, Serialize}; +use std::sync::Arc; + +use crate::models::{ApiResponse, Session}; +use crate::state::AppState; + +/// `GET /api/sessions` — list every session. +pub async fn list_sessions(state: web::Data>) -> HttpResponse { + let sessions: Vec = state.sessions.iter().map(|r| r.value().clone()).collect(); + HttpResponse::Ok().json(ApiResponse::ok(sessions)) +} + +/// `POST /api/sessions` — create a new session. +pub async fn create_session(state: web::Data>) -> HttpResponse { + match state.create_session() { + Ok(session) => HttpResponse::Created().json(ApiResponse::ok(session)), + Err(e) => HttpResponse::ServiceUnavailable().json(ApiResponse::<()>::err(e)), + } +} + +/// `GET /api/sessions/{id}` — get a single session. +pub async fn get_session( + state: web::Data>, + path: web::Path, +) -> HttpResponse { + let id = path.into_inner(); + match state.get_session(&id) { + Some(session) => HttpResponse::Ok().json(ApiResponse::ok(session)), + None => HttpResponse::NotFound().json(ApiResponse::<()>::err("session not found")), + } +} + +/// `DELETE /api/sessions/{id}` — remove a session. +pub async fn delete_session( + state: web::Data>, + path: web::Path, +) -> HttpResponse { + let id = path.into_inner(); + if state.remove_session(&id) { + HttpResponse::Ok().json(ApiResponse::ok("session deleted")) + } else { + HttpResponse::NotFound().json(ApiResponse::<()>::err("session not found")) + } +} + +/// JSON body for HUD commands. +#[derive(Debug, Deserialize)] +pub struct HudCommandPayload { + pub command: String, + #[serde(default)] + pub params: serde_json::Value, +} + +/// `POST /api/sessions/{id}/hud` — send a HUD command to the agent for a session. +/// +/// The command is forwarded to the connected agent via the session's agent +/// channel (stored in AppState). If no agent is connected, returns 409. +pub async fn send_hud_command( + state: web::Data>, + path: web::Path, + body: web::Json, +) -> HttpResponse { + let session_id = path.into_inner(); + + // Find the first agent registered for this session. + let agent_id = state + .agents + .iter() + .find(|r| r.session_id == session_id) + .map(|r| r.agent_id.clone()); + + match agent_id { + Some(aid) => { + // TODO: in the WS handler we will add a per-agent mpsc sender so + // we can forward the HUD command there. For now log and acknowledge. + log::info!( + "HUD command '{}' for session {} → agent {} (params: {})", + body.command, + session_id, + aid, + body.params + ); + HttpResponse::Ok().json(ApiResponse::ok("command forwarded")) + } + None => HttpResponse::Conflict().json(ApiResponse::<()>::err("no agent connected for this session")), + } +}