From 5bf63df8247f3c33f5406435ca0d23efb6cc52c3 Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Thu, 28 May 2026 10:05:02 +0900 Subject: [PATCH 1/2] fix connection cleanup --- packages/message/extension_message.ts | 35 +++++++++++++++--------- packages/message/types.ts | 2 +- packages/message/window_message.ts | 3 +- src/app/service/content/gm_api/gm_xhr.ts | 2 +- 4 files changed, 26 insertions(+), 16 deletions(-) diff --git a/packages/message/extension_message.ts b/packages/message/extension_message.ts index e1fd75720..c5b2bc058 100644 --- a/packages/message/extension_message.ts +++ b/packages/message/extension_message.ts @@ -38,35 +38,43 @@ export class ExtensionMessage implements Message { }; onConnect(callback: (data: TMessage, con: MessageConnect) => void) { - chrome.runtime.onConnect.addListener((port: chrome.runtime.Port | null) => { + chrome.runtime.onConnect.addListener((port: chrome.runtime.Port) => { + let myPort: chrome.runtime.Port | null = port; const lastError = chrome.runtime.lastError; if (lastError) { console.error("chrome.runtime.lastError in chrome.runtime.onConnect", lastError); // 消息API发生错误因此不继续执行 } const handler = (msg: TMessage) => { - port!.onMessage.removeListener(handler); - callback(msg, new ExtensionMessageConnect(port!)); - port = null; + const port = myPort; + if (port !== null) { + myPort = null; + port.onMessage.removeListener(handler); + callback(msg, new ExtensionMessageConnect(port)); + } }; - port!.onMessage.addListener(handler); + myPort.onMessage.addListener(handler); }); if (this.backgroundPrimary) { let addUserScriptConnectionListener: (() => void) | null = () => { try { // 监听用户脚本的连接 - chrome.runtime.onUserScriptConnect.addListener((port: chrome.runtime.Port | null) => { + chrome.runtime.onUserScriptConnect.addListener((port: chrome.runtime.Port) => { + let myPort: chrome.runtime.Port | null = port; const lastError = chrome.runtime.lastError; if (lastError) { console.error("chrome.runtime.lastError in chrome.runtime.onUserScriptConnect:", lastError); } const handler = (msg: TMessage) => { - port!.onMessage.removeListener(handler); - callback(msg, new ExtensionMessageConnect(port!)); - port = null; + const port = myPort; + if (port !== null) { + myPort = null; + port.onMessage.removeListener(handler); + callback(msg, new ExtensionMessageConnect(port)); + } }; - port!.onMessage.addListener(handler); + myPort.onMessage.addListener(handler); }); addUserScriptConnectionListener = null; } catch { @@ -157,8 +165,9 @@ export class ExtensionMessageConnect implements MessageConnect { const handler = (msg: TMessage, _con: chrome.runtime.Port) => { listenerMgr.emit(`onMessage:${this.listenerId}`, msg); }; - const cleanup = (con: chrome.runtime.Port) => { - if (this.con) { + const cleanup = () => { + const con = this.con; + if (con !== null) { this.con = null; listenerMgr.removeAllListeners(`cleanup:${this.listenerId}`); con.onMessage.removeListener(handler); @@ -179,7 +188,7 @@ export class ExtensionMessageConnect implements MessageConnect { // 無法 sendMessage 不应该屏蔽错误 throw new Error("Attempted to sendMessage on a disconnected port."); } - this.con?.postMessage(data); + this.con.postMessage(data); } onMessage(callback: (data: TMessage) => void) { diff --git a/packages/message/types.ts b/packages/message/types.ts index 3c3e94a91..29f7fe004 100644 --- a/packages/message/types.ts +++ b/packages/message/types.ts @@ -49,7 +49,7 @@ export interface MessageSend { export interface MessageConnect { onMessage(callback: (data: TMessage) => void): void; sendMessage(data: TMessage): void; - disconnect(): void; + disconnect(ignoreAlreadyDisconnected?: boolean): void; onDisconnect(callback: (isSelfDisconnected: boolean) => void): void; } diff --git a/packages/message/window_message.ts b/packages/message/window_message.ts index c40f0d94f..4f7987937 100644 --- a/packages/message/window_message.ts +++ b/packages/message/window_message.ts @@ -185,8 +185,9 @@ export class WindowMessageConnect implements MessageConnect { listenerMgr.addListener(`onMessage:${this.listenerId}`, callback); } - disconnect() { + disconnect(ignoreAlreadyDisconnected: boolean = false) { if (!this.target) { + if (ignoreAlreadyDisconnected) return; console.warn("Attempted to disconnect on a disconnected Target."); // 重复 disconnect() 不应该屏蔽错误 throw new Error("Attempted to disconnect on a disconnected Target."); diff --git a/src/app/service/content/gm_api/gm_xhr.ts b/src/app/service/content/gm_api/gm_xhr.ts index 341dd8c06..8eaa241b8 100644 --- a/src/app/service/content/gm_api/gm_xhr.ts +++ b/src/app/service/content/gm_api/gm_xhr.ts @@ -306,7 +306,7 @@ export function GM_xmlhttpRequest( onMessageHandler = null; doAbort = null; refCleanup = null; - connect?.disconnect(); // 确保 connect 断开 + connect?.disconnect(true); // 确保 connect 断开 connect = null; }; From 0baadc7cfd0b7247e745c640a1cde11e8373b53b Mon Sep 17 00:00:00 2001 From: cyfung1031 <44498510+cyfung1031@users.noreply.github.com> Date: Thu, 28 May 2026 16:58:52 +0900 Subject: [PATCH 2/2] code fix --- packages/message/extension_message.ts | 3 +- packages/message/mock_message.ts | 32 +++++++++++++++++-- .../service/service_worker/gm_api/gm_api.ts | 11 ++++--- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/packages/message/extension_message.ts b/packages/message/extension_message.ts index c5b2bc058..e0702c98f 100644 --- a/packages/message/extension_message.ts +++ b/packages/message/extension_message.ts @@ -200,8 +200,9 @@ export class ExtensionMessageConnect implements MessageConnect { listenerMgr.addListener(`onMessage:${this.listenerId}`, callback); } - disconnect() { + disconnect(ignoreAlreadyDisconnected?: boolean) { if (!this.con) { + if (ignoreAlreadyDisconnected) return; console.warn("Attempted to disconnect on a disconnected port."); // 重复 disconnect() 不应该屏蔽错误 throw new Error("Attempted to disconnect on a disconnected port."); diff --git a/packages/message/mock_message.ts b/packages/message/mock_message.ts index e49d04481..53c8adfa7 100644 --- a/packages/message/mock_message.ts +++ b/packages/message/mock_message.ts @@ -3,23 +3,49 @@ import EventEmitter from "eventemitter3"; import { sleep } from "@App/pkg/utils/utils"; export class MockMessageConnect implements MessageConnect { - constructor(protected EE: EventEmitter) {} + EE: EventEmitter | null; + constructor(EE: EventEmitter) { + this.EE = EE; + } onMessage(callback: (data: TMessage) => void): void { + if (!this.EE) { + console.error("onMessage Invalid MockConnection"); + // 無法監聽的話不应该屏蔽错误 + throw new Error("onMessage Invalid MockConnection"); + } this.EE.on("message", (data: any) => { callback(data); }); } sendMessage(data: TMessage): void { + if (!this.EE) { + console.warn("Attempted to sendMessage on a disconnected MockConnection."); + // 無法 sendMessage 不应该屏蔽错误 + throw new Error("Attempted to sendMessage on a disconnected MockConnection."); + } this.EE.emit("message", data); } - disconnect(): void { - this.EE.emit("disconnect", true); // MockMessageConnect 未有模拟由另一端触发 disconnect() 的情况 + disconnect(ignoreAlreadyDisconnected?: boolean): void { + if (!this.EE) { + if (ignoreAlreadyDisconnected) return; + console.warn("Attempted to disconnect on a disconnected MockConnection."); + // 重复 disconnect() 不应该屏蔽错误 + throw new Error("Attempted to disconnect on a disconnected MockConnection."); + } + const EE = this.EE; + this.EE = null; + EE?.emit("disconnect", true); // MockMessageConnect 未有模拟由另一端触发 disconnect() 的情况 } onDisconnect(callback: (isSelfDisconnected: boolean) => void) { + if (!this.EE) { + console.error("onDisconnect Invalid MockConnection."); + // 無法監聽的話不应该屏蔽错误 + throw new Error("onDisconnect Invalid MockConnection."); + } this.EE.once("disconnect", callback); } } diff --git a/src/app/service/service_worker/gm_api/gm_api.ts b/src/app/service/service_worker/gm_api/gm_api.ts index 2dfcd51fe..fa6670f7c 100644 --- a/src/app/service/service_worker/gm_api/gm_api.ts +++ b/src/app/service/service_worker/gm_api/gm_api.ts @@ -774,10 +774,11 @@ export default class GMApi { throw new Error("GM_xmlhttpRequest ERROR: msgConn is undefined"); } // conn 为 nested scope 内 local 存取 - let throwErrorFn: ((error: string) => Error) | null = ((conn: MessageConnect | null) => { + let throwErrorFn: ((error: string) => Error) | null = ((conn: MessageConnect) => { + let myConn: MessageConnect | null = conn; let errorOccur: string | null = null; const doLoadEnd = () => { - conn?.sendMessage({ + myConn?.sendMessage({ action: "onloadend", data: { status: 0, @@ -786,12 +787,12 @@ export default class GMApi { readyState: 4, // ERROR. DONE. }, }); - conn?.disconnect(); // 断开连结 - conn = null; // 释放 + myConn?.disconnect(); // 断开连结 + myConn = null; // 释放 }; return (error: string) => { errorOccur = error; - conn?.sendMessage({ + myConn?.sendMessage({ action: "onerror", data: { status: 0,