diff --git a/packages/message/extension_message.ts b/packages/message/extension_message.ts index e1fd75720..e0702c98f 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) { @@ -191,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/packages/message/types.ts b/packages/message/types.ts index 70a77f592..fea7719e6 100644 --- a/packages/message/types.ts +++ b/packages/message/types.ts @@ -53,7 +53,7 @@ export interface IOffscreenSend extends 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..cc22fce5a 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) { 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_api.ts b/src/app/service/content/gm_api/gm_api.ts index 381ec533c..8bead733a 100644 --- a/src/app/service/content/gm_api/gm_api.ts +++ b/src/app/service/content/gm_api/gm_api.ts @@ -1189,7 +1189,7 @@ export default class GMApi extends GM_Base { retPromise, abort: () => { aborted = true; - connect?.disconnect(); + connect?.disconnect(true); // 断开连结(容忍已断开) nativeAbort?.(); }, }; diff --git a/src/app/service/content/gm_api/gm_xhr.ts b/src/app/service/content/gm_api/gm_xhr.ts index 341dd8c06..37ccd7364 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; }; @@ -725,7 +725,7 @@ export function GM_xmlhttpRequest( retPromise, abort: () => { if (connect) { - connect.disconnect(); + connect.disconnect(true); // 断开连结(容忍已断开) connect = null; } if (doAbort && details.onabort && !reqDone) { 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 fa293e22d..e9184b44e 100644 --- a/src/app/service/service_worker/gm_api/gm_api.ts +++ b/src/app/service/service_worker/gm_api/gm_api.ts @@ -770,10 +770,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, @@ -782,12 +783,12 @@ export default class GMApi { readyState: 4, // ERROR. DONE. }, }); - conn?.disconnect(); // 断开连结 - conn = null; // 释放 + myConn?.disconnect(true); // 断开连结(容忍已断开) + myConn = null; // 释放 }; return (error: string) => { errorOccur = error; - conn?.sendMessage({ + myConn?.sendMessage({ action: "onerror", data: { status: 0,