server: api/sessions.rs — CRUD endpoints + HUD command forwarding
This commit is contained in:
parent
40bf516264
commit
94a992d72a
88
server/src/api/sessions.rs
Normal file
88
server/src/api/sessions.rs
Normal file
@ -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<Arc<AppState>>) -> HttpResponse {
|
||||||
|
let sessions: Vec<Session> = 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<Arc<AppState>>) -> 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<Arc<AppState>>,
|
||||||
|
path: web::Path<String>,
|
||||||
|
) -> 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<Arc<AppState>>,
|
||||||
|
path: web::Path<String>,
|
||||||
|
) -> 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<Arc<AppState>>,
|
||||||
|
path: web::Path<String>,
|
||||||
|
body: web::Json<HudCommandPayload>,
|
||||||
|
) -> 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")),
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user