mirror of
https://github.com/wavetermdev/xterm.js.git
synced 2026-08-05 13:43:48 -07:00
abort in-flight kitty chunks on delete
This commit is contained in:
@@ -431,6 +431,13 @@ export class KittyGraphicsHandler implements IApcHandler, IResetHandler {
|
||||
const id = cmd.id;
|
||||
|
||||
if (id !== undefined) {
|
||||
// Abort in-flight chunked upload for this specific image
|
||||
const pending = this._pendingTransmissions.get(id);
|
||||
if (pending) {
|
||||
pending.decoder.release();
|
||||
this._pendingTransmissions.delete(id);
|
||||
}
|
||||
|
||||
this._images.delete(id);
|
||||
const storageId = this._kittyIdToStorageId.get(id);
|
||||
if (storageId !== undefined) {
|
||||
@@ -438,6 +445,12 @@ export class KittyGraphicsHandler implements IApcHandler, IResetHandler {
|
||||
this._kittyIdToStorageId.delete(id);
|
||||
}
|
||||
} else {
|
||||
// Abort all in-flight chunked uploads
|
||||
for (const pending of this._pendingTransmissions.values()) {
|
||||
pending.decoder.release();
|
||||
}
|
||||
this._pendingTransmissions.clear();
|
||||
|
||||
this._images.clear();
|
||||
for (const storageId of this._kittyIdToStorageId.values()) {
|
||||
this._storage.deleteImage(storageId);
|
||||
@@ -607,4 +620,8 @@ export class KittyGraphicsHandler implements IApcHandler, IResetHandler {
|
||||
public get images(): ReadonlyMap<number, IKittyImageData> {
|
||||
return this._images;
|
||||
}
|
||||
|
||||
public get pendingTransmissions(): ReadonlyMap<number, IPendingTransmission> {
|
||||
return this._pendingTransmissions;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import test from '@playwright/test';
|
||||
import { readFileSync } from 'fs';
|
||||
import { ITestContext, createTestContext, openTerminal, timeout } from '../../../test/playwright/TestUtils';
|
||||
import { deepStrictEqual, strictEqual } from 'assert';
|
||||
import { deepStrictEqual, ok, strictEqual } from 'assert';
|
||||
|
||||
/**
|
||||
* Plugin ctor options.
|
||||
@@ -245,6 +245,71 @@ test.describe('Kitty Graphics Protocol', () => {
|
||||
await timeout(50);
|
||||
strictEqual(await ctx.page.evaluate(`window.imageAddon._handlers.get('kitty').images.size`), 0);
|
||||
});
|
||||
|
||||
test('delete by id aborts in-flight chunked upload', async () => {
|
||||
const half = Math.floor(KITTY_BLACK_1X1_BASE64.length / 2);
|
||||
const part1 = KITTY_BLACK_1X1_BASE64.substring(0, half);
|
||||
|
||||
await ctx.proxy.write(`\x1b_Ga=t,f=100,i=50,m=1;${part1}\x1b\\`);
|
||||
await timeout(50);
|
||||
strictEqual(await ctx.page.evaluate(`window.imageAddon._handlers.get('kitty').pendingTransmissions.size`), 1);
|
||||
|
||||
await ctx.proxy.write(`\x1b_Ga=d,i=50\x1b\\`);
|
||||
await timeout(50);
|
||||
strictEqual(await ctx.page.evaluate(`window.imageAddon._handlers.get('kitty').pendingTransmissions.size`), 0);
|
||||
});
|
||||
|
||||
test('delete by id only aborts targeted upload, not others', async () => {
|
||||
const half = Math.floor(KITTY_BLACK_1X1_BASE64.length / 2);
|
||||
const part1 = KITTY_BLACK_1X1_BASE64.substring(0, half);
|
||||
|
||||
await ctx.proxy.write(`\x1b_Ga=t,f=100,i=55,m=1;${part1}\x1b\\`);
|
||||
await ctx.proxy.write(`\x1b_Ga=t,f=100,i=56,m=1;${part1}\x1b\\`);
|
||||
await timeout(50);
|
||||
strictEqual(await ctx.page.evaluate(`window.imageAddon._handlers.get('kitty').pendingTransmissions.size`), 2);
|
||||
|
||||
await ctx.proxy.write(`\x1b_Ga=d,i=55\x1b\\`);
|
||||
await timeout(50);
|
||||
strictEqual(await ctx.page.evaluate(`window.imageAddon._handlers.get('kitty').pendingTransmissions.size`), 1);
|
||||
strictEqual(await ctx.page.evaluate(`window.imageAddon._handlers.get('kitty').pendingTransmissions.has(56)`), true);
|
||||
});
|
||||
|
||||
test('delete all aborts in-flight chunked upload', async () => {
|
||||
const half = Math.floor(KITTY_BLACK_1X1_BASE64.length / 2);
|
||||
const part1 = KITTY_BLACK_1X1_BASE64.substring(0, half);
|
||||
|
||||
await ctx.proxy.write(`\x1b_Ga=t,f=100,i=60,m=1;${part1}\x1b\\`);
|
||||
await ctx.proxy.write(`\x1b_Ga=t,f=100,i=61,m=1;${part1}\x1b\\`);
|
||||
await timeout(50);
|
||||
strictEqual(await ctx.page.evaluate(`window.imageAddon._handlers.get('kitty').pendingTransmissions.size`), 2);
|
||||
|
||||
await ctx.proxy.write(`\x1b_Ga=d\x1b\\`);
|
||||
await timeout(50);
|
||||
strictEqual(await ctx.page.evaluate(`window.imageAddon._handlers.get('kitty').pendingTransmissions.size`), 0);
|
||||
});
|
||||
|
||||
test('chunks sent after delete are not assembled with previous data', async () => {
|
||||
const half = Math.floor(KITTY_BLACK_1X1_BASE64.length / 2);
|
||||
const part1 = KITTY_BLACK_1X1_BASE64.substring(0, half);
|
||||
const part2 = KITTY_BLACK_1X1_BASE64.substring(half);
|
||||
|
||||
await ctx.proxy.write(`\x1b_Ga=t,f=100,i=70,m=1;${part1}\x1b\\`);
|
||||
await timeout(50);
|
||||
strictEqual(await ctx.page.evaluate(`window.imageAddon._handlers.get('kitty').pendingTransmissions.size`), 1);
|
||||
|
||||
await ctx.proxy.write(`\x1b_Ga=d\x1b\\`);
|
||||
await timeout(50);
|
||||
|
||||
await ctx.proxy.write(`\x1b_Ga=t,f=100,i=70;${part2}\x1b\\`);
|
||||
await timeout(100);
|
||||
|
||||
strictEqual(await ctx.page.evaluate(`window.imageAddon._handlers.get('kitty').images.has(70)`), true);
|
||||
const storedSize: number = await ctx.page.evaluate(async () => {
|
||||
const blob = (window as any).imageAddon._handlers.get('kitty').images.get(70).data;
|
||||
return blob.size;
|
||||
});
|
||||
ok(storedSize < KITTY_BLACK_1X1_BYTES.length, 'stored data should be smaller than full image (only second half)');
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Query support (a=q)', () => {
|
||||
|
||||
Reference in New Issue
Block a user