Replace ansiToHtml with terminal serialization (Phase 2)
The output handler now: - Writes raw data to terminal emulator - Stores raw data in DB (unchanged) - Serializes terminal state as HTML - Broadcasts serialized HTML via SSE This replaces the ansiToHtml() + splitAnsiCarryover() approach with proper terminal emulation. The terminal emulator handles all ANSI sequences internally, including incomplete sequences across chunks.
This commit is contained in:
parent
6c7de2332b
commit
88afb7249d
1 changed files with 22 additions and 25 deletions
|
|
@ -1,8 +1,6 @@
|
|||
// Core server: HTTP + WebSocket + SSE
|
||||
|
||||
import type { ServerWebSocket } from "bun";
|
||||
import { ansiToHtml } from "./ansi";
|
||||
import { splitAnsiCarryover } from "./ansi-carryover";
|
||||
import {
|
||||
appendOutput,
|
||||
createDevice,
|
||||
|
|
@ -19,7 +17,12 @@ import {
|
|||
updateLastSeen,
|
||||
updateSessionStats,
|
||||
} from "./db";
|
||||
import { createTerminal, disposeTerminal, type TerminalSession } from "./terminal";
|
||||
import {
|
||||
createTerminal,
|
||||
disposeTerminal,
|
||||
serializeAsHTML,
|
||||
type TerminalSession,
|
||||
} from "./terminal";
|
||||
import type {
|
||||
AnswerResponse,
|
||||
ClientMessage,
|
||||
|
|
@ -494,35 +497,29 @@ const server = Bun.serve<SessionData>({
|
|||
// Handle output message
|
||||
if (msg.type === "output") {
|
||||
const sessionId = ws.data.sessionId;
|
||||
// Join with any saved carryover from previous chunk
|
||||
const prevCarry = ansiCarryovers.get(sessionId) || "";
|
||||
const combined = prevCarry ? prevCarry + msg.data : msg.data;
|
||||
// Determine if new tail is an incomplete control sequence and split
|
||||
const [body, carry] = splitAnsiCarryover(combined);
|
||||
if (carry) {
|
||||
console.debug(
|
||||
`Session ${sessionId}: ANSI carryover detected (${carry.length} bytes)`,
|
||||
);
|
||||
ansiCarryovers.set(sessionId, carry);
|
||||
} else if (prevCarry) {
|
||||
console.debug(`Session ${sessionId}: ANSI carryover resolved`);
|
||||
// Clear carry if previously set and now resolved
|
||||
ansiCarryovers.delete(sessionId);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
if (!termSession) {
|
||||
console.error(`No terminal for session ${sessionId}`);
|
||||
return;
|
||||
}
|
||||
|
||||
// Write to terminal emulator (handles all ANSI sequences)
|
||||
termSession.terminal.write(msg.data);
|
||||
|
||||
// Store raw ANSI in database
|
||||
appendOutput(sessionId, msg.data);
|
||||
|
||||
// Serialize current terminal state as HTML
|
||||
const html = serializeAsHTML(termSession);
|
||||
|
||||
// Broadcast to dashboards
|
||||
broadcastSSE({
|
||||
type: "output",
|
||||
session_id: sessionId,
|
||||
data: ansiToHtml(body), // Parse for display
|
||||
data: html,
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue