diff --git a/packages/message/custom_event_message.ts b/packages/message/custom_event_message.ts index ebdeb094b..b3e8cf952 100644 --- a/packages/message/custom_event_message.ts +++ b/packages/message/custom_event_message.ts @@ -5,6 +5,23 @@ import LoggerCore from "@App/app/logger/core"; import EventEmitter from "eventemitter3"; import { DefinedFlags } from "@App/app/service/service_worker/runtime.consts"; +// 避免页面载入后改动 EventTarget.prototype 的方法导致消息传递失败 +const pageDispatchEvent = performance.dispatchEvent.bind(performance); +const pageAddEventListener = performance.addEventListener.bind(performance); + +// 避免页面载入后改动全域物件导致消息传递失败 +const MouseEventClone = MouseEvent; +const CustomEventClone = CustomEvent; + +// 避免页面载入后改动 Map.prototype 导致消息传递失败 +const relatedTargetMap = new Map(); +relatedTargetMap.set = Map.prototype.set; +relatedTargetMap.get = Map.prototype.get; +relatedTargetMap.delete = Map.prototype.delete; + +let relateId = 0; +const maxInteger = Number.MAX_SAFE_INTEGER; + export class CustomEventPostMessage implements PostMessage { constructor(private send: CustomEventMessage) {} @@ -28,10 +45,10 @@ export class CustomEventMessage implements Message { ) { this.receiveFlag = `evt${messageFlag}${isContent ? DefinedFlags.contentFlag : DefinedFlags.injectFlag}${DefinedFlags.domEvent}`; this.sendFlag = `evt${messageFlag}${isContent ? DefinedFlags.injectFlag : DefinedFlags.contentFlag}${DefinedFlags.domEvent}`; - window.addEventListener(this.receiveFlag, (event) => { - if (event instanceof MouseEvent && event.movementX && event.relatedTarget) { - this.relatedTarget.set(event.movementX, event.relatedTarget!); - } else if (event instanceof CustomEvent) { + pageAddEventListener(this.receiveFlag, (event) => { + if (event instanceof MouseEventClone && event.movementX && event.relatedTarget) { + relatedTargetMap.set(event.movementX, event.relatedTarget!); + } else if (event instanceof CustomEventClone) { this.messageHandle(event.detail, new CustomEventPostMessage(this)); } }); @@ -100,10 +117,10 @@ export class CustomEventMessage implements Message { } } - const ev = new CustomEvent(this.sendFlag, { + const ev = new CustomEventClone(this.sendFlag, { detail, }); - window.dispatchEvent(ev); + pageDispatchEvent(ev); } sendMessage(data: TMessage): Promise { @@ -146,24 +163,22 @@ export class CustomEventMessage implements Message { return ret; } - relateId = 0; - sendRelatedTarget(target: EventTarget): number { // 特殊处理relatedTarget,返回id进行关联 // 先将relatedTarget转换成id发送过去 - const id = ++this.relateId; + const id = (relateId = relateId === maxInteger ? 1 : relateId + 1); // 可以使用此种方式交互element - const ev = new MouseEvent(this.sendFlag, { + const ev = new MouseEventClone(this.sendFlag, { movementX: id, relatedTarget: target, }); - window.dispatchEvent(ev); + pageDispatchEvent(ev); return id; } getAndDelRelatedTarget(id: number) { - const target = this.relatedTarget.get(id); - this.relatedTarget.delete(id); + const target = relatedTargetMap.get(id); + relatedTargetMap.delete(id); return target; } } diff --git a/packages/message/extension_message.ts b/packages/message/extension_message.ts index 81f25874c..7b6dfc745 100644 --- a/packages/message/extension_message.ts +++ b/packages/message/extension_message.ts @@ -180,7 +180,7 @@ export class ExtensionContentMessageSend implements MessageSend { sendMessage(data: TMessage): Promise { return new Promise((resolve) => { - if (!this.options?.documentId || this.options?.frameId) { + if (!this.options?.documentId && !this.options?.frameId) { // 发送给指定的tab chrome.tabs.sendMessage(this.tabId, data, (resp: T) => { const lastError = chrome.runtime.lastError; diff --git a/src/app/service/content/content.ts b/src/app/service/content/content.ts index e09b6be71..da0445cfd 100644 --- a/src/app/service/content/content.ts +++ b/src/app/service/content/content.ts @@ -5,6 +5,8 @@ import type { MessageSend } from "@Packages/message/types"; import type { ScriptExecutor } from "./script_executor"; import { RuntimeClient } from "../service_worker/client"; import type { GMInfoEnv } from "./types"; +import type { Logger } from "@App/app/repo/logger"; +import LoggerCore from "@App/app/logger/core"; // content页的处理 export default class ContentRuntime { @@ -36,6 +38,9 @@ export default class ContentRuntime { this.scriptExecutor.valueUpdate(data); return sendMessage(this.senderToInject, "inject/runtime/valueUpdate", data); }); + this.server.on("logger", (data: Logger) => { + LoggerCore.logger().log(data.level, data.message, data.label); + }); forwardMessage("serviceWorker", "script/isInstalled", this.server, this.senderToExt); forwardMessage( "serviceWorker", diff --git a/src/app/service/content/script_executor.ts b/src/app/service/content/script_executor.ts index 460922974..32e499bfb 100644 --- a/src/app/service/content/script_executor.ts +++ b/src/app/service/content/script_executor.ts @@ -90,7 +90,7 @@ export class ScriptExecutor { const envLoadCompleteEvtName = `${eventNamePrefix}${DefinedFlags.envLoadComplete}`; // 监听 脚本加载 // 适用于此「通知环境加载完成」代码执行后的脚本加载 - window.addEventListener(scriptLoadCompleteEvtName, (ev) => { + performance.addEventListener(scriptLoadCompleteEvtName, (ev) => { const detail = (ev as CustomEvent).detail; const scriptFlag = detail?.scriptFlag; if (typeof scriptFlag === "string") { @@ -101,7 +101,7 @@ export class ScriptExecutor { // 通知 环境 加载完成 // 适用于此「通知环境加载完成」代码执行前的脚本加载 const ev = new CustomEvent(envLoadCompleteEvtName); - window.dispatchEvent(ev); + performance.dispatchEvent(ev); } execEarlyScript(flag: string, scriptInfo: TScriptInfo, envInfo: GMInfoEnv) { diff --git a/src/app/service/content/utils.ts b/src/app/service/content/utils.ts index f8996ddab..fb035f4ba 100644 --- a/src/app/service/content/utils.ts +++ b/src/app/service/content/utils.ts @@ -150,9 +150,9 @@ export function compilePreInjectScript( return `window['${flag}'] = function(){${autoDeleteMountCode}${scriptCode}}; { let o = { cancelable: true, detail: { scriptFlag: '${flag}', scriptInfo: (${scriptInfoJSON}) } }, - f = () => window.dispatchEvent(new CustomEvent('${evScriptLoad}', o)), + f = () => performance.dispatchEvent(new CustomEvent('${evScriptLoad}', o)), needWait = f(); - if (needWait) window.addEventListener('${evEnvLoad}', f, { once: true }); + if (needWait) performance.addEventListener('${evEnvLoad}', f, { once: true }); } `; } diff --git a/src/app/service/service_worker/value.ts b/src/app/service/service_worker/value.ts index 7de284644..a7f70997e 100644 --- a/src/app/service/service_worker/value.ts +++ b/src/app/service/service_worker/value.ts @@ -101,6 +101,7 @@ export class ValueService { await this.valueDAO.save(storageName, valueModel); return true; }); + this.pushValueToTab({ id, entries: encodeMessage([[key, value, oldValue]]), diff --git a/src/content.ts b/src/content.ts index 8947fe19c..4b74ac99b 100644 --- a/src/content.ts +++ b/src/content.ts @@ -18,7 +18,7 @@ if (typeof chrome?.runtime?.onMessage?.addListener !== "function") { const extMsgComm: Message = new ExtensionMessage(false); // 初始化日志组件 const loggerCore = new LoggerCore({ - writer: new MessageWriter(extMsgComm), + writer: new MessageWriter(extMsgComm, "serviceWorker/logger"), labels: { env: "content" }, }); diff --git a/src/inject.ts b/src/inject.ts index da80cd0a9..b434858d1 100644 --- a/src/inject.ts +++ b/src/inject.ts @@ -14,7 +14,8 @@ const msg: Message = new CustomEventMessage(MessageFlag, false); // 加载logger组件 const logger = new LoggerCore({ - writer: new MessageWriter(msg), + writer: new MessageWriter(msg, "content/logger"), + consoleLevel: "none", // 只让日志在content环境中打印 labels: { env: "inject", href: window.location.href }, }); diff --git a/tests/vitest.setup.ts b/tests/vitest.setup.ts index a992f3f32..3cac3508f 100644 --- a/tests/vitest.setup.ts +++ b/tests/vitest.setup.ts @@ -227,3 +227,16 @@ vi.stubGlobal("define", "特殊关键字不能穿透沙盒"); if (!URL.createObjectURL) URL.createObjectURL = undefined; //@ts-expect-error if (!URL.revokeObjectURL) URL.revokeObjectURL = undefined; + +// 测试环境使用 window 代替 performance 作为 EventTarget +performance.addEventListener = function (type: string, listener: any, options?: any) { + return window.addEventListener(type, listener, options); +}; + +performance.removeEventListener = function (type: string, listener: any, options?: any) { + return window.removeEventListener(type, listener, options); +}; + +performance.dispatchEvent = function (event: Event) { + return window.dispatchEvent(event); +};