diff --git a/src/server.ts b/src/server.ts index 1342e95..4b9a0ee 100644 --- a/src/server.ts +++ b/src/server.ts @@ -19,6 +19,7 @@ import { updateLastSeen, updateSessionStats, } from "./db"; +import { createTerminal, disposeTerminal, type TerminalSession } from "./terminal"; import type { AnswerResponse, ClientMessage, @@ -33,6 +34,7 @@ const sessionWebSockets = new Map>(); const sessionStates = new Map(); // Buffer for incomplete ANSI sequences per session to avoid leaking partial control codes const ansiCarryovers = new Map(); +const sessionTerminals = new Map(); interface SessionData { deviceId: number; @@ -437,6 +439,10 @@ const server = Bun.serve({ // Initialize in-memory session state sessionStates.set(session.id, createDefaultSessionState()); + // Create terminal emulator with default size (will be resized later) + const termSession = createTerminal(80, 24); + sessionTerminals.set(session.id, termSession); + console.debug( `Session ${session.id} started for device ${device.id}`, ); @@ -506,6 +512,12 @@ const server = Bun.serve({ appendOutput(sessionId, body); // Store raw ANSI without trailing incomplete fragment + // Write to terminal emulator + const termSession = sessionTerminals.get(sessionId); + if (termSession) { + termSession.terminal.write(msg.data); + } + broadcastSSE({ type: "output", session_id: sessionId, @@ -615,6 +627,13 @@ const server = Bun.serve({ console.debug( `Session ${ws.data.sessionId} resized to ${msg.cols}x${msg.rows}`, ); + + // Resize terminal emulator + const termSession = sessionTerminals.get(ws.data.sessionId); + if (termSession) { + termSession.terminal.resize(msg.cols, msg.rows); + } + return; } @@ -654,6 +673,13 @@ const server = Bun.serve({ sessionWebSockets.delete(ws.data.sessionId); ansiCarryovers.delete(ws.data.sessionId); + // Dispose terminal emulator + const termSession = sessionTerminals.get(ws.data.sessionId); + if (termSession) { + disposeTerminal(termSession); + sessionTerminals.delete(ws.data.sessionId); + } + // Persist final state before cleanup const state = sessionStates.get(ws.data.sessionId); if (state?.dirty) {