Archived
Add realtime terminal tab badges
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import type { GlobalSessionEvent, SessionUiEvent } from "../../shared/apiTypes.js";
|
||||
import type { GlobalSessionEvent, RealtimeEvent, SessionUiEvent } from "../../shared/apiTypes.js";
|
||||
import type { WebSocket } from "ws";
|
||||
|
||||
export class SessionEventHub {
|
||||
@@ -30,6 +30,10 @@ export class SessionEventHub {
|
||||
}
|
||||
|
||||
publishGlobal(event: GlobalSessionEvent): void {
|
||||
this.publishRealtime(event);
|
||||
}
|
||||
|
||||
publishRealtime(event: RealtimeEvent): void {
|
||||
const payload = JSON.stringify(event);
|
||||
for (const socket of this.globalSockets) {
|
||||
if (socket.readyState === socket.OPEN) socket.send(payload);
|
||||
|
||||
@@ -15,7 +15,7 @@ await app.register(fastifyWebsocket);
|
||||
|
||||
const eventHub = new SessionEventHub();
|
||||
const sessions = new PiSessionService(eventHub);
|
||||
const terminals = new TerminalService();
|
||||
const terminals = new TerminalService(eventHub);
|
||||
registerSessionRoutes(app, sessions, eventHub);
|
||||
registerTerminalRoutes(app, terminals);
|
||||
|
||||
|
||||
@@ -26,6 +26,10 @@ export function registerSessionProxyRoutes(app: FastifyInstance, daemon = new Se
|
||||
bridgeSockets(socket, daemon.connectWebSocket("/sessions/events"));
|
||||
});
|
||||
|
||||
app.get("/api/events", { websocket: true }, (socket) => {
|
||||
bridgeSockets(socket, daemon.connectWebSocket("/events"));
|
||||
});
|
||||
|
||||
app.all("/api/sessions", (request, reply) => proxy(request, reply));
|
||||
app.all("/api/sessions/*", (request, reply) => proxy(request, reply));
|
||||
}
|
||||
|
||||
@@ -167,6 +167,10 @@ export function registerSessionRoutes(app: FastifyInstance, sessions: PiSessionS
|
||||
app.get(`${prefix}/sessions/events`, { websocket: true }, (socket) => {
|
||||
eventHub.addGlobal(socket);
|
||||
});
|
||||
|
||||
app.get(`${prefix}/events`, { websocket: true }, (socket) => {
|
||||
eventHub.addGlobal(socket);
|
||||
});
|
||||
}
|
||||
|
||||
function optionalField<T>(key: string, value: T | undefined): Record<string, T> | object {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { EventEmitter } from "node:events";
|
||||
import { randomUUID } from "node:crypto";
|
||||
import * as pty from "node-pty";
|
||||
import type { TerminalUiEvent } from "../../shared/apiTypes.js";
|
||||
import type { SessionEventHub } from "../realtime/sessionEventHub.js";
|
||||
|
||||
const MAX_REPLAY_BUFFER = 200_000;
|
||||
|
||||
@@ -22,6 +24,8 @@ interface TerminalRecord extends TerminalInfo {
|
||||
export class TerminalService {
|
||||
private readonly terminals = new Map<string, TerminalRecord>();
|
||||
|
||||
constructor(private readonly events?: SessionEventHub) {}
|
||||
|
||||
list(cwd: string): TerminalInfo[] {
|
||||
return [...this.terminals.values()]
|
||||
.filter((terminal) => terminal.cwd === cwd)
|
||||
@@ -59,9 +63,12 @@ export class TerminalService {
|
||||
record.exited = true;
|
||||
record.exitCode = exitCode;
|
||||
record.events.emit("exit", exitCode);
|
||||
this.publish({ type: "terminal.exited", terminal: toInfo(record) });
|
||||
});
|
||||
this.terminals.set(id, record);
|
||||
return toInfo(record);
|
||||
const info = toInfo(record);
|
||||
this.publish({ type: "terminal.created", terminal: info });
|
||||
return info;
|
||||
}
|
||||
|
||||
get(id: string): TerminalInfo | undefined {
|
||||
@@ -101,6 +108,7 @@ export class TerminalService {
|
||||
this.terminals.delete(id);
|
||||
terminal.events.removeAllListeners();
|
||||
if (!terminal.exited) terminal.pty.kill();
|
||||
this.publish({ type: "terminal.closed", terminalId: id, cwd: terminal.cwd });
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
@@ -112,6 +120,10 @@ export class TerminalService {
|
||||
if (terminal === undefined) throw new Error("Terminal not found");
|
||||
return terminal;
|
||||
}
|
||||
|
||||
private publish(event: TerminalUiEvent): void {
|
||||
this.events?.publishRealtime(event);
|
||||
}
|
||||
}
|
||||
|
||||
function toInfo(record: TerminalRecord): TerminalInfo {
|
||||
|
||||
Reference in New Issue
Block a user