mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
Fix terminal stream stalls after resize
This commit is contained in:
@@ -40,10 +40,6 @@ export type TerminalStreamControllerOptions = {
|
||||
|
||||
const TERMINAL_EXITED_ERROR = "Terminal exited";
|
||||
|
||||
function logTerminalStreamController(event: string, details: Record<string, unknown>): void {
|
||||
console.log("[terminal-stream-controller]", event, details);
|
||||
}
|
||||
|
||||
export class TerminalStreamController {
|
||||
private readonly decoder = new TextDecoder();
|
||||
private readonly unsubscribeStreamEvents: () => void;
|
||||
@@ -69,19 +65,10 @@ export class TerminalStreamController {
|
||||
|
||||
setTerminal(input: { terminalId: string | null }): void {
|
||||
if (this.disposed || input.terminalId === this.terminalId) {
|
||||
logTerminalStreamController("set_terminal_noop", {
|
||||
disposed: this.disposed,
|
||||
currentTerminalId: this.terminalId,
|
||||
requestedTerminalId: input.terminalId,
|
||||
});
|
||||
return;
|
||||
}
|
||||
const nextTerminalId = input.terminalId;
|
||||
const previousTerminalId = this.terminalId;
|
||||
logTerminalStreamController("set_terminal", {
|
||||
previousTerminalId,
|
||||
nextTerminalId,
|
||||
});
|
||||
this.terminalId = nextTerminalId;
|
||||
this.decoder.decode();
|
||||
if (previousTerminalId) {
|
||||
@@ -95,11 +82,6 @@ export class TerminalStreamController {
|
||||
void this.options.client
|
||||
.subscribeTerminal(nextTerminalId)
|
||||
.then((payload) => {
|
||||
logTerminalStreamController("subscribe_resolved", {
|
||||
nextTerminalId,
|
||||
payloadTerminalId: payload.terminalId,
|
||||
error: payload.error ?? null,
|
||||
});
|
||||
if (this.disposed || this.terminalId !== nextTerminalId) {
|
||||
return;
|
||||
}
|
||||
@@ -113,10 +95,6 @@ export class TerminalStreamController {
|
||||
return;
|
||||
}
|
||||
const preferredSize = this.options.getPreferredSize();
|
||||
logTerminalStreamController("preferred_size_after_subscribe", {
|
||||
nextTerminalId,
|
||||
preferredSize,
|
||||
});
|
||||
if (preferredSize) {
|
||||
this.options.client.sendTerminalInput(nextTerminalId, {
|
||||
type: "resize",
|
||||
@@ -131,10 +109,6 @@ export class TerminalStreamController {
|
||||
});
|
||||
})
|
||||
.catch((error: unknown) => {
|
||||
logTerminalStreamController("subscribe_rejected", {
|
||||
nextTerminalId,
|
||||
error: error instanceof Error ? error.message : "Unable to subscribe to terminal",
|
||||
});
|
||||
if (this.disposed || this.terminalId !== nextTerminalId) {
|
||||
return;
|
||||
}
|
||||
@@ -148,10 +122,6 @@ export class TerminalStreamController {
|
||||
}
|
||||
|
||||
handleTerminalExit(input: { terminalId: string }): void {
|
||||
logTerminalStreamController("terminal_exit", {
|
||||
currentTerminalId: this.terminalId,
|
||||
exitedTerminalId: input.terminalId,
|
||||
});
|
||||
if (this.disposed || input.terminalId !== this.terminalId) {
|
||||
return;
|
||||
}
|
||||
@@ -168,9 +138,6 @@ export class TerminalStreamController {
|
||||
if (this.disposed) {
|
||||
return;
|
||||
}
|
||||
logTerminalStreamController("dispose", {
|
||||
terminalId: this.terminalId,
|
||||
});
|
||||
this.disposed = true;
|
||||
this.decoder.decode();
|
||||
const terminalId = this.terminalId;
|
||||
|
||||
@@ -626,6 +626,45 @@ describe("daemon E2E terminal", () => {
|
||||
rmSync(cwd, { recursive: true, force: true });
|
||||
}, 30000);
|
||||
|
||||
test("resize does not stall streamed output for an attached client", async () => {
|
||||
const cwd = tmpCwd();
|
||||
const created = await ctx.client.createTerminal(cwd);
|
||||
const terminalId = created.terminal!.id;
|
||||
const secondClient = await connectClient(
|
||||
ctx.daemon.port,
|
||||
`terminal-resize-stream-${Date.now()}-${Math.random().toString(36).slice(2)}`,
|
||||
);
|
||||
|
||||
try {
|
||||
await ctx.client.subscribeTerminal(terminalId);
|
||||
await secondClient.subscribeTerminal(terminalId);
|
||||
|
||||
secondClient.sendTerminalInput(terminalId, {
|
||||
type: "resize",
|
||||
rows: 12,
|
||||
cols: 40,
|
||||
});
|
||||
|
||||
const firstOutput = waitForTerminalOutput(ctx.client, terminalId, (text) =>
|
||||
text.includes("after-resize-stream"),
|
||||
);
|
||||
const secondOutput = waitForTerminalOutput(secondClient, terminalId, (text) =>
|
||||
text.includes("after-resize-stream"),
|
||||
);
|
||||
|
||||
secondClient.sendTerminalInput(terminalId, {
|
||||
type: "input",
|
||||
data: "printf 'after-resize-stream\\n'\r",
|
||||
});
|
||||
|
||||
expect(await firstOutput).toContain("after-resize-stream");
|
||||
expect(await secondOutput).toContain("after-resize-stream");
|
||||
} finally {
|
||||
await secondClient.close();
|
||||
rmSync(cwd, { recursive: true, force: true });
|
||||
}
|
||||
}, 30000);
|
||||
|
||||
test("terminal exits notify the client", async () => {
|
||||
const cwd = tmpCwd();
|
||||
const created = await ctx.client.createTerminal(cwd);
|
||||
|
||||
@@ -1817,7 +1817,6 @@ export class Session {
|
||||
if (!resize) {
|
||||
return;
|
||||
}
|
||||
activeStream.needsSnapshot = true;
|
||||
terminal.send({ type: "resize", rows: resize.rows, cols: resize.cols });
|
||||
return;
|
||||
}
|
||||
@@ -7859,6 +7858,7 @@ export class Session {
|
||||
this.markAllActiveTerminalStreamsForSnapshot();
|
||||
}
|
||||
});
|
||||
this.trySendTerminalSnapshot(activeStream);
|
||||
return slot;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user