chore(extension): do not send if socket is already closed (#834)

* Remove debugger listeners if closed() is called as `ws.onclosed` is
dispatched asynchronously
* Tabs can be closed while update badge command is in flight
* Inflight CDP commands fail if the tab closes, do not try to send their
response to a closed socket
This commit is contained in:
Yury Semikhatsky
2025-08-05 13:47:08 -07:00
committed by GitHub
parent 46ce86f97e
commit eab20aa69e
2 changed files with 25 additions and 8 deletions

View File

@@ -130,9 +130,13 @@ class TabShareExtension {
}
private async _updateBadge(tabId: number, { text, color }: { text: string; color: string | null }): Promise<void> {
try {
await chrome.action.setBadgeText({ tabId, text });
if (color)
await chrome.action.setBadgeBackgroundColor({ tabId, color });
} catch (error: any) {
// Ignore errors as the tab may be closed already.
}
}
private async _onTabRemoved(tabId: number): Promise<void> {
@@ -165,7 +169,8 @@ class TabShareExtension {
if (!tab.active && !pending.timerId) {
debugLog('Starting inactivity timer', tabId);
pending.timerId = window.setTimeout(() => {
this._pendingTabSelection.delete(tabId);
const existed = this._pendingTabSelection.delete(tabId);
if (existed)
pending.connection.close('Tab is not active');
}, 5000);
return;

View File

@@ -43,6 +43,7 @@ export class RelayConnection {
private _detachListener: (source: chrome.debugger.Debuggee, reason: string) => void;
private _tabPromise: Promise<void>;
private _tabPromiseResolve!: () => void;
private _closed = false;
onclose?: () => void;
@@ -51,7 +52,7 @@ export class RelayConnection {
this._tabPromise = new Promise(resolve => this._tabPromiseResolve = resolve);
this._ws = ws;
this._ws.onmessage = this._onMessage.bind(this);
this._ws.onclose = () => this.onclose?.();
this._ws.onclose = () => this._onClose();
// Store listeners for cleanup
this._eventListener = this._onDebuggerEvent.bind(this);
this._detachListener = this._onDebuggerDetach.bind(this);
@@ -66,9 +67,19 @@ export class RelayConnection {
}
close(message: string): void {
this._ws.close(1000, message);
// ws.onclose is called asynchronously, so we call it here to avoid forwarding
// CDP events to the closed connection.
this._onClose();
}
private _onClose() {
if (this._closed)
return;
this._closed = true;
chrome.debugger.onEvent.removeListener(this._eventListener);
chrome.debugger.onDetach.removeListener(this._detachListener);
this._ws.close(1000, message);
this.onclose?.();
}
private _onDebuggerEvent(source: chrome.debugger.DebuggerSession, method: string, params: any): void {
@@ -160,6 +171,7 @@ export class RelayConnection {
}
private _sendMessage(message: any): void {
if (this._ws.readyState === WebSocket.OPEN)
this._ws.send(JSON.stringify(message));
}
}