Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 11 additions & 17 deletions packages/message/custom_event_message.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { v4 as uuidv4 } from "uuid";
import { type PostMessage, type WindowMessageBody, WindowMessageConnect } from "./window_message";
import LoggerCore from "@App/app/logger/core";
import EventEmitter from "eventemitter3";
import { DefinedFlags } from "@App/app/service/service_worker/runtime.consts";

export class CustomEventPostMessage implements PostMessage {
constructor(private send: CustomEventMessage) {}
Expand All @@ -15,23 +16,20 @@ export class CustomEventPostMessage implements PostMessage {
// 使用CustomEvent来进行通讯, 可以在content与inject中传递一些dom对象
export class CustomEventMessage implements Message {
EE = new EventEmitter<string, any>();
readonly receiveFlag: string;
readonly sendFlag: string;

// 关联dom目标
relatedTarget: Map<number, EventTarget> = new Map();

protected flags: {
injectFlag: string;
contentFlag: string;
messageFlag: string;
};

constructor(
flags: typeof CustomEventMessage.prototype.flags | string,
protected isContent: boolean
flags: MessageFlags | string,
protected readonly isContent: boolean
) {
flags = typeof flags === "string" ? { injectFlag: "inject", contentFlag: "content", messageFlag: flags } : flags;
this.flags = flags;
window.addEventListener((isContent ? flags.contentFlag : flags.injectFlag) + flags.messageFlag, (event) => {
const messageFlag = typeof flags === "string" ? flags : flags.messageFlag;
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) {
Expand Down Expand Up @@ -103,16 +101,12 @@ export class CustomEventMessage implements Message {
}
}

const ev = new CustomEvent(this.sendEventName(), {
const ev = new CustomEvent(this.sendFlag, {
detail,
});
window.dispatchEvent(ev);
}

sendEventName(): string {
return (this.isContent ? this.flags.injectFlag : this.flags.contentFlag) + this.flags.messageFlag;
}

sendMessage<T = any>(data: TMessage): Promise<T> {
return new Promise((resolve: ((value: T) => void) | null) => {
const messageId = uuidv4();
Expand Down Expand Up @@ -160,7 +154,7 @@ export class CustomEventMessage implements Message {
// 先将relatedTarget转换成id发送过去
const id = ++this.relateId;
// 可以使用此种方式交互element
const ev = new MouseEvent(this.sendEventName(), {
const ev = new MouseEvent(this.sendFlag, {
movementX: id,
relatedTarget: target,
});
Expand Down
57 changes: 27 additions & 30 deletions packages/message/server.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { describe, expect, it, beforeEach, vi, afterEach } from "vitest";
import { GetSenderType, SenderConnect, SenderRuntime, Server, type IGetSender } from "./server";
import { CustomEventMessage } from "./custom_event_message";
import type { MessageConnect, RuntimeMessageSender } from "./types";
import { DefinedFlags } from "@App/app/service/service_worker/runtime.consts";

let contentMessage: CustomEventMessage;
let injectMessage: CustomEventMessage;
Expand All @@ -11,11 +12,7 @@ let client: CustomEventMessage;
const nextTick = () => Promise.resolve().then(() => {});

const setupGlobal = () => {
const flags = {
contentFlag: "ct",
injectFlag: "fd",
messageFlag: "test",
};
const flags = { messageFlag: "-test.server" };
// 创建 content 和 inject 之间的消息通道
contentMessage = new CustomEventMessage(flags, true); // content 端
injectMessage = new CustomEventMessage(flags, false); // inject 端
Expand All @@ -36,35 +33,35 @@ const setupGlobal = () => {
vi.fn().mockImplementation((event: Event) => {
if (event instanceof CustomEvent) {
const eventType = event.type;
if (eventType.includes("test")) {
if (eventType.includes("-test.server")) {
let targetEventType: string;
let messageThis: CustomEventMessage;
let messageThat: CustomEventMessage;
// 根据事件类型确定目标消息处理器
if (eventType.startsWith("ct")) {
if (eventType.includes(DefinedFlags.contentFlag)) {
// inject -> content
nextTick().then(() => {
contentMessage.messageHandle(event.detail, {
postMessage: (data: any) => {
// content -> inject 的响应
const responseEvent = new CustomEvent("fd" + "test", { detail: data });
injectMessage.messageHandle(responseEvent.detail, {
postMessage: vi.fn(),
});
},
});
});
} else if (eventType.startsWith("fd")) {
targetEventType = eventType.replace(DefinedFlags.contentFlag, DefinedFlags.injectFlag);
messageThis = contentMessage;
messageThat = injectMessage;
} else if (eventType.includes(DefinedFlags.injectFlag)) {
// content -> inject
nextTick().then(() => {
injectMessage.messageHandle(event.detail, {
postMessage: (data: any) => {
// inject -> content 的响应
const responseEvent = new CustomEvent("ct" + "test", { detail: data });
contentMessage.messageHandle(responseEvent.detail, {
postMessage: vi.fn(),
});
},
});
});
targetEventType = eventType.replace(DefinedFlags.injectFlag, DefinedFlags.contentFlag);
messageThis = injectMessage;
messageThat = contentMessage;
} else {
throw new Error("test mock failed");
}
nextTick().then(() => {
messageThis.messageHandle(event.detail, {
postMessage: (data: any) => {
// 响应
const responseEvent = new CustomEvent(targetEventType, { detail: data });
messageThat.messageHandle(responseEvent.detail, {
postMessage: vi.fn(),
});
},
});
});
}
}
return true;
Expand Down
11 changes: 8 additions & 3 deletions src/app/service/content/script_executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type { EmitEventRequest, ScriptLoadInfo } from "../service_worker/types";
import ExecScript from "./exec_script";
import type { GMInfoEnv, ScriptFunc, PreScriptFunc, ValueUpdateDataEncoded } from "./types";
import { addStyle, definePropertyListener } from "./utils";
import { DefinedFlags } from "../service_worker/runtime.consts";

export type ExecScriptEntry = {
scriptLoadInfo: ScriptLoadInfo;
Expand Down Expand Up @@ -71,10 +72,14 @@ export class ScriptExecutor {
}

checkEarlyStartScript(env: "content" | "inject", messageFlags: MessageFlags) {
const eventNamePrefix = env === "content" ? messageFlags.contentFlag : messageFlags.injectFlag;
const isContent = env === "content";
const messageFlag = messageFlags.messageFlag;
const eventNamePrefix = `evt${messageFlag}${isContent ? DefinedFlags.contentFlag : DefinedFlags.injectFlag}`;
const scriptLoadCompleteEvtName = `${eventNamePrefix}${DefinedFlags.scriptLoadComplete}`;
const envLoadCompleteEvtName = `${eventNamePrefix}${DefinedFlags.envLoadComplete}`;
// 监听 脚本加载
// 适用于此「通知环境加载完成」代码执行后的脚本加载
window.addEventListener(`${eventNamePrefix}${messageFlags.scriptLoadComplete}`, (event) => {
window.addEventListener(scriptLoadCompleteEvtName, (event) => {
if (event instanceof CustomEvent) {
if (typeof event.detail.scriptFlag === "string") {
event.preventDefault(); // dispatchEvent 会回传 false -> 分离环境也能得知环境加载代码已执行
Expand All @@ -85,7 +90,7 @@ export class ScriptExecutor {
});
// 通知 环境 加载完成
// 适用于此「通知环境加载完成」代码执行前的脚本加载
const ev = new CustomEvent(eventNamePrefix + messageFlags.envLoadComplete);
const ev = new CustomEvent(envLoadCompleteEvtName);
window.dispatchEvent(ev);
}

Expand Down
11 changes: 8 additions & 3 deletions src/app/service/content/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { SCMetadata, ScriptRunResource } from "@App/app/repo/scripts";
import type { ScriptFunc } from "./types";
import type { ScriptLoadInfo } from "../service_worker/types";
import { DefinedFlags } from "../service_worker/runtime.consts";

export type CompileScriptCodeResource = {
name: string;
Expand Down Expand Up @@ -104,21 +105,25 @@ export function compilePreInjectScript(
scriptCode: string,
autoDeleteMountFunction: boolean = false
): string {
const eventNamePrefix = isInjectIntoContent(script.metadata) ? messageFlags.contentFlag : messageFlags.injectFlag;
const isContent = isInjectIntoContent(script.metadata);
const messageFlag = messageFlags.messageFlag;
const eventNamePrefix = `evt${messageFlag}${isContent ? DefinedFlags.contentFlag : DefinedFlags.injectFlag}`;
const scriptLoadCompleteEvtName = `${eventNamePrefix}${DefinedFlags.scriptLoadComplete}`;
const envLoadCompleteEvtName = `${eventNamePrefix}${DefinedFlags.envLoadComplete}`;
const autoDeleteMountCode = autoDeleteMountFunction ? `try{delete window['${script.flag}']}catch(e){}` : "";
return `window['${script.flag}'] = {
scriptInfo: ${JSON.stringify(script)},
func: function(){${autoDeleteMountCode}${scriptCode}}
};
(() => {
const f = () => {
const event = new CustomEvent('${eventNamePrefix}${messageFlags.scriptLoadComplete}',
const event = new CustomEvent('${scriptLoadCompleteEvtName}',
{ cancelable: true, detail: { scriptFlag: '${script.flag}' } });
return window.dispatchEvent(event);
};
const noCheckEarlyStartScript = f();
if (noCheckEarlyStartScript) {
window.addEventListener('${eventNamePrefix}${messageFlags.envLoadComplete}', f, { once: true });
window.addEventListener('${envLoadCompleteEvtName}', f, { once: true });
}
})();
`;
Expand Down
12 changes: 12 additions & 0 deletions src/app/service/service_worker/runtime.consts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export const DefinedFlags = {
// content 环境flag
contentFlag: ".ct",
// inject 环境flag
injectFlag: ".fd",
// 脚本加载完成事件
scriptLoadComplete: ".slc",
// 环境加载完成事件
envLoadComplete: ".elc",
// 使用CustomEvent来进行通讯
domEvent: ".dom",
} as const;
19 changes: 5 additions & 14 deletions src/app/service/service_worker/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,7 @@ const ORIGINAL_URLMATCH_SUFFIX = "{ORIGINAL}"; // 用于标记原始URLPatterns
const runtimeGlobal = {
registered: false,
messageFlags: {
contentFlag: "PENDING",
injectFlag: "PENDING",
messageFlag: "PENDING",
scriptLoadComplete: "PENDING",
envLoadComplete: "PENDING",
} as MessageFlags,
};

Expand Down Expand Up @@ -95,7 +91,7 @@ export class RuntimeService {
sitesLoaded: Set<string> = new Set<string>();
updateSitesBusy: boolean = false;

loadingInitFlagPromise: Promise<any> | undefined;
loadingInitFlagsPromise: Promise<any> | undefined;
loadingInitProcessPromise: Promise<any> | undefined;
initialCompiledResourcePromise: Promise<any> | undefined;

Expand All @@ -112,7 +108,7 @@ export class RuntimeService {
private scriptDAO: ScriptDAO,
private localStorageDAO: LocalStorageDAO
) {
this.loadingInitFlagPromise = this.localStorageDAO
this.loadingInitFlagsPromise = this.localStorageDAO
.get("scriptInjectMessageFlags")
.then((res) => {
runtimeGlobal.messageFlags = res?.value || this.generateMessageFlags();
Expand Down Expand Up @@ -533,7 +529,7 @@ export class RuntimeService {
checkUserScriptsAvailable(),
this.systemConfig.getEnableScript(),
this.systemConfig.getBlacklist(),
this.loadingInitFlagPromise, // messageFlag 初始化等待
this.loadingInitFlagsPromise, // messageFlags 初始化等待
this.loadingInitProcessPromise, // 初始化程序等待
this.initUserAgentData(), // 初始化:userAgentData
]);
Expand Down Expand Up @@ -615,13 +611,8 @@ export class RuntimeService {

// 生成messageFlags
generateMessageFlags(): MessageFlags {
return {
injectFlag: randomMessageFlag(),
contentFlag: randomMessageFlag(),
messageFlag: randomMessageFlag(),
scriptLoadComplete: randomMessageFlag(),
envLoadComplete: randomMessageFlag(),
};
const r = randomMessageFlag();
return { messageFlag: r };
}

getMessageFlags() {
Expand Down
8 changes: 0 additions & 8 deletions src/types/main.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,8 @@ interface FileSystemObserverInstance {
}

interface MessageFlags {
// inject 环境flag
injectFlag: string;
// content 环境flag
contentFlag: string;
// 通信flag
messageFlag: string;
// 脚本加载完成事件
scriptLoadComplete: string;
// 环境加载完成事件
envLoadComplete: string;
}

declare const MessageFlags: MessageFlags;
Expand Down
Loading