use axum::{
extract::{Path, Query, State, WebSocketUpgrade},
response::IntoResponse,
};
use serde::{Deserialize, Serialize};
use crate::AppState;
#[derive(Debug, Deserialize)]
#[serde(tag = "type")]
pub enum ClientControl {
#[serde(rename = "resize")]
Resize { cols: u16, rows: u16 },
#[serde(rename = "ping")]
Ping,
}
#[derive(Debug, Serialize)]
#[serde(tag = "type")]
#[allow(dead_code)] pub enum ServerControl<'a> {
#[serde(rename = "attached")]
Attached { session: &'a str },
#[serde(rename = "pong")]
Pong,
#[serde(rename = "error")]
Error { message: &'a str },
#[serde(rename = "exit")]
Exit { code: Option<i32> },
#[serde(rename = "agent_state")]
AgentState {
agent_kind: Option<&'a str>,
state: &'a str,
attention_reason: Option<&'a str>,
agent_event: Option<&'a str>,
agent_nonce: Option<&'a str>,
},
}
#[derive(Debug, Deserialize)]
pub struct TerminalQuery {
pub cols: Option<u16>,
pub rows: Option<u16>,
}
pub async fn ws_terminal_handler(
ws: WebSocketUpgrade,
Path(session_id): Path<String>,
Query(query): Query<TerminalQuery>,
State(state): State<AppState>,
) -> impl IntoResponse {
ws.on_upgrade(move |socket| async move {
let runtime_kind: Option<(String,)> =
sqlx::query_as("SELECT runtime_kind FROM sessions WHERE id = ?")
.bind(&session_id)
.fetch_optional(&state.db)
.await
.ok()
.flatten();
crate::engine::run_terminal_session(
runtime_kind.map(|(kind,)| kind),
socket,
session_id,
query,
state,
)
.await
})
}
pub async fn ws_external_terminal_handler(
ws: WebSocketUpgrade,
Path(session_name): Path<String>,
Query(query): Query<TerminalQuery>,
State(state): State<AppState>,
) -> impl IntoResponse {
ws.on_upgrade(move |socket| {
crate::engine::run_external_terminal_session(socket, session_name, query, state)
})
}