Skip to content

Commit 84d3fc7

Browse files
fix(server): renegotiate when attached client peeks
1 parent e5a2686 commit 84d3fc7

2 files changed

Lines changed: 50 additions & 1 deletion

File tree

src/server.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -691,7 +691,10 @@ export class PtyServer {
691691

692692
case MessageType.PEEK: {
693693
client.readonly = true;
694-
socket.write(encodeGeometry(this.terminal.rows, this.terminal.cols));
694+
const resized = this.negotiateSize();
695+
if (!resized) {
696+
socket.write(encodeGeometry(this.terminal.rows, this.terminal.cols));
697+
}
695698
const flags = packet.payload.length > 0 ? packet.payload.readUInt8(0) : 0;
696699
const plain = (flags & 1) !== 0;
697700
const full = (flags & 2) !== 0;

tests/integration.test.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1439,6 +1439,52 @@ describe("STATUS message", () => {
14391439
statsClient.destroy();
14401440
});
14411441

1442+
it("relinquishes a writable client's geometry constraints when it peeks", async () => {
1443+
const name = uniqueName();
1444+
await startServer(name, "cat", [], { rows: 50, cols: 120 });
1445+
1446+
const smaller = await connect(name);
1447+
const smallerReader = new PacketReader();
1448+
smaller.write(encodeAttach(30, 80));
1449+
await waitForType(smaller, smallerReader, MessageType.SCREEN);
1450+
1451+
const larger = await connect(name);
1452+
const largerReader = new PacketReader();
1453+
larger.write(encodeAttach(50, 120));
1454+
await waitForType(larger, largerReader, MessageType.SCREEN);
1455+
1456+
smaller.write(encodePeek());
1457+
await waitForType(smaller, smallerReader, MessageType.SCREEN);
1458+
const geometry = await waitForType(larger, largerReader, MessageType.GEOMETRY);
1459+
expect(geometry.payload.readUInt16BE(0)).toBe(50);
1460+
expect(geometry.payload.readUInt16BE(2)).toBe(120);
1461+
1462+
const statsClient = await connect(name);
1463+
const statsReader = new PacketReader();
1464+
statsClient.write(encodeStatus());
1465+
const packet = await waitForType(statsClient, statsReader, MessageType.STATUS);
1466+
const stats = JSON.parse(packet.payload.toString());
1467+
1468+
expect(stats.terminal).toMatchObject({ rows: 50, cols: 120 });
1469+
expect(stats.clients.connections).toEqual(expect.arrayContaining([
1470+
{
1471+
role: "readonly",
1472+
constrains: { rows: false, cols: false },
1473+
},
1474+
{
1475+
role: "writable",
1476+
rows: 50,
1477+
cols: 120,
1478+
lastRequestSequence: 2,
1479+
constrains: { rows: true, cols: true },
1480+
},
1481+
]));
1482+
1483+
smaller.destroy();
1484+
larger.destroy();
1485+
statsClient.destroy();
1486+
});
1487+
14421488
it("reports exited process", async () => {
14431489
const name = uniqueName();
14441490
await startServer(name, "sh", ["-c", "exit 7"]);

0 commit comments

Comments
 (0)