注入脚本和inject/content通信
Some checks failed
build / Build (push) Failing after 6s
test / Run tests (push) Failing after 2s
Some checks failed
build / Build (push) Failing after 6s
test / Run tests (push) Failing after 2s
This commit is contained in:
133
packages/message/custom_event_message.ts
Normal file
133
packages/message/custom_event_message.ts
Normal file
@ -0,0 +1,133 @@
|
||||
import { Message, MessageConnect } from "./server";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { PostMessage, WindowMessageBody, WindowMessageConnect } from "./window_message";
|
||||
import LoggerCore from "@App/app/logger/core";
|
||||
import EventEmitter from "eventemitter3";
|
||||
|
||||
export class CustomEventPostMessage implements PostMessage {
|
||||
constructor(private send: CustomEventMessage) {}
|
||||
|
||||
postMessage(message: any): void {
|
||||
this.send.nativeSend(message);
|
||||
}
|
||||
}
|
||||
|
||||
// 使用CustomEvent来进行通讯, 可以在content与inject中传递一些dom对象
|
||||
export class CustomEventMessage implements Message {
|
||||
EE: EventEmitter = new EventEmitter();
|
||||
|
||||
// 关联dom目标
|
||||
relatedTarget: Map<number, Element> = new Map();
|
||||
|
||||
constructor(
|
||||
protected flag: string,
|
||||
protected isContent: boolean
|
||||
) {
|
||||
window.addEventListener((isContent ? "ct" : "fd") + flag, (event) => {
|
||||
if (event instanceof MouseEvent) {
|
||||
this.relatedTarget.set(event.clientX, <Element>event.relatedTarget);
|
||||
return;
|
||||
} else if (event instanceof CustomEvent) {
|
||||
this.messageHandle(event.detail, new CustomEventPostMessage(this));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
messageHandle(data: WindowMessageBody, target: PostMessage) {
|
||||
// 处理消息
|
||||
if (data.type === "sendMessage") {
|
||||
// 接收到消息
|
||||
this.EE.emit("message", data.data, (resp: any) => {
|
||||
// 发送响应消息
|
||||
// 无消息id则不发送响应消息
|
||||
if (!data.messageId) {
|
||||
return;
|
||||
}
|
||||
const body: WindowMessageBody = {
|
||||
messageId: data.messageId,
|
||||
type: "respMessage",
|
||||
data: resp,
|
||||
};
|
||||
target.postMessage(body);
|
||||
});
|
||||
} else if (data.type === "respMessage") {
|
||||
// 接收到响应消息
|
||||
this.EE.emit("response:" + data.messageId, data);
|
||||
} else if (data.type === "connect") {
|
||||
this.EE.emit("connect", data.data, new WindowMessageConnect(data.messageId, this.EE, target));
|
||||
} else if (data.type === "disconnect") {
|
||||
this.EE.emit("disconnect:" + data.messageId);
|
||||
} else if (data.type === "connectMessage") {
|
||||
this.EE.emit("connectMessage:" + data.messageId, data.data);
|
||||
}
|
||||
}
|
||||
|
||||
onConnect(callback: (data: any, con: MessageConnect) => void): void {
|
||||
this.EE.addListener("connect", callback);
|
||||
}
|
||||
|
||||
onMessage(callback: (data: any, sendResponse: (data: any) => void) => void): void {
|
||||
this.EE.addListener("message", callback);
|
||||
}
|
||||
|
||||
connect(data: any): Promise<MessageConnect> {
|
||||
return new Promise((resolve) => {
|
||||
const body: WindowMessageBody = {
|
||||
messageId: uuidv4(),
|
||||
type: "connect",
|
||||
data,
|
||||
};
|
||||
this.nativeSend(body);
|
||||
resolve(new WindowMessageConnect(body.messageId, this.EE, new CustomEventPostMessage(this)));
|
||||
});
|
||||
}
|
||||
|
||||
nativeSend(data: any) {
|
||||
let detail = data;
|
||||
|
||||
// 特殊处理relatedTarget
|
||||
if (detail.data && typeof detail.data.relatedTarget === "object") {
|
||||
// 先将relatedTarget转换成id发送过去
|
||||
const target = detail.data.relatedTarget;
|
||||
delete detail.data.relatedTarget;
|
||||
detail.data.relatedTarget = Math.ceil(Math.random() * 1000000);
|
||||
// 可以使用此种方式交互element
|
||||
const ev = new MouseEvent((this.isContent ? "fd" : "ct") + this.flag, {
|
||||
clientX: detail.data.relatedTarget,
|
||||
relatedTarget: target,
|
||||
});
|
||||
window.dispatchEvent(ev);
|
||||
}
|
||||
|
||||
if (typeof cloneInto !== "undefined") {
|
||||
try {
|
||||
LoggerCore.logger().info("nativeSend");
|
||||
detail = cloneInto(detail, document.defaultView);
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
LoggerCore.logger().info("error data");
|
||||
}
|
||||
}
|
||||
|
||||
const ev = new CustomEvent((this.isContent ? "fd" : "ct") + this.flag, {
|
||||
detail,
|
||||
});
|
||||
window.dispatchEvent(ev);
|
||||
}
|
||||
|
||||
sendMessage(data: any): Promise<any> {
|
||||
return new Promise((resolve) => {
|
||||
const body: WindowMessageBody = {
|
||||
messageId: uuidv4(),
|
||||
type: "sendMessage",
|
||||
data,
|
||||
};
|
||||
const callback = (body: WindowMessageBody) => {
|
||||
this.EE.removeListener("response:" + body.messageId, callback);
|
||||
resolve(body.data);
|
||||
};
|
||||
this.EE.addListener("response:" + body.messageId, callback);
|
||||
this.nativeSend(body);
|
||||
});
|
||||
}
|
||||
}
|
@ -5,7 +5,7 @@ import { Message, MessageConnect, MessageSend } from "./server";
|
||||
|
||||
import EventEmitter from "eventemitter3";
|
||||
|
||||
interface PostMessage {
|
||||
export interface PostMessage {
|
||||
postMessage(message: any): void;
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,8 @@ export default defineConfig({
|
||||
service_worker: `${src}/service_worker.ts`,
|
||||
offscreen: `${src}/offscreen.ts`,
|
||||
sandbox: `${src}/sandbox.ts`,
|
||||
content: `${src}/content.ts`,
|
||||
inject: `${src}/inject.ts`,
|
||||
popup: `${src}/pages/popup/main.tsx`,
|
||||
install: `${src}/pages/install/main.tsx`,
|
||||
options: `${src}/pages/options/main.tsx`,
|
||||
|
@ -6,7 +6,7 @@ import { ResourceClient, ScriptClient, ValueClient } from "../service_worker/cli
|
||||
import { SCRIPT_STATUS_ENABLE, SCRIPT_TYPE_NORMAL, ScriptRunResouce } from "@App/app/repo/scripts";
|
||||
import { disableScript, enableScript, runScript, stopScript } from "../sandbox/client";
|
||||
import { Group, MessageSend } from "@Packages/message/server";
|
||||
import { subscribeScriptEnable, subscribeScriptInstall } from "../queue";
|
||||
import { subscribeScriptDelete, subscribeScriptEnable, subscribeScriptInstall } from "../queue";
|
||||
|
||||
export class ScriptService {
|
||||
logger: Logger;
|
||||
@ -34,7 +34,6 @@ export class ScriptService {
|
||||
|
||||
async init() {
|
||||
subscribeScriptEnable(this.messageQueue, async (data) => {
|
||||
console.log("subscribeScriptEnable", data);
|
||||
const script = await this.scriptClient.info(data.uuid);
|
||||
if (script.type === SCRIPT_TYPE_NORMAL) {
|
||||
return;
|
||||
@ -48,7 +47,6 @@ export class ScriptService {
|
||||
}
|
||||
});
|
||||
subscribeScriptInstall(this.messageQueue, async (data) => {
|
||||
console.log("subscribeScriptInstall", data);
|
||||
// 判断是开启还是关闭
|
||||
if (data.script.status === SCRIPT_STATUS_ENABLE) {
|
||||
// 构造脚本运行资源,发送给沙盒运行
|
||||
@ -58,6 +56,9 @@ export class ScriptService {
|
||||
disableScript(this.windowMessage, data.script.uuid);
|
||||
}
|
||||
});
|
||||
subscribeScriptDelete(this.messageQueue, async (data) => {
|
||||
disableScript(this.windowMessage, data.uuid);
|
||||
});
|
||||
|
||||
this.group.on("runScript", this.runScript.bind(this));
|
||||
this.group.on("stopScript", this.stopScript.bind(this));
|
||||
|
@ -81,4 +81,8 @@ export class RuntimeClient extends Client {
|
||||
stopScript(uuid: string) {
|
||||
return this.do("stopScript", uuid);
|
||||
}
|
||||
|
||||
pageLoad(): Promise<{ flag: string; scripts: ScriptRunResouce[] }> {
|
||||
return this.do("pageLoad");
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,29 @@
|
||||
import { MessageQueue } from "@Packages/message/message_queue";
|
||||
import { Group, MessageSend } from "@Packages/message/server";
|
||||
import { Script, SCRIPT_STATUS_ENABLE, SCRIPT_TYPE_NORMAL, ScriptAndCode, ScriptDAO } from "@App/app/repo/scripts";
|
||||
import {
|
||||
Script,
|
||||
SCRIPT_STATUS_ENABLE,
|
||||
SCRIPT_TYPE_NORMAL,
|
||||
ScriptDAO,
|
||||
ScriptRunResouce,
|
||||
} from "@App/app/repo/scripts";
|
||||
import { ValueService } from "./value";
|
||||
import GMApi from "./gm_api";
|
||||
import { subscribeScriptEnable } from "../queue";
|
||||
import { subscribeScriptDelete, subscribeScriptEnable, subscribeScriptInstall } from "../queue";
|
||||
import { ScriptService } from "./script";
|
||||
import { runScript, stopScript } from "../offscreen/client";
|
||||
import { dealMatches } from "./utils";
|
||||
import { dealMatches, getRunAt } from "./utils";
|
||||
import { randomString } from "@App/pkg/utils/utils";
|
||||
import { compileInjectScript, compileScriptCode } from "@App/runtime/content/utils";
|
||||
|
||||
export class RuntimeService {
|
||||
scriptDAO: ScriptDAO = new ScriptDAO();
|
||||
|
||||
scriptFlag: string = randomString(8);
|
||||
|
||||
// 运行中的页面脚本
|
||||
runningPageScript = new Map<string, ScriptRunResouce>();
|
||||
|
||||
constructor(
|
||||
private group: Group,
|
||||
private sender: MessageSend,
|
||||
@ -20,6 +33,8 @@ export class RuntimeService {
|
||||
) {}
|
||||
|
||||
async init() {
|
||||
// 读取inject.js注入页面
|
||||
this.registerInjectScript();
|
||||
// 监听脚本开启
|
||||
subscribeScriptEnable(this.mq, async (data) => {
|
||||
const script = await this.scriptDAO.getAndCode(data.uuid);
|
||||
@ -37,6 +52,26 @@ export class RuntimeService {
|
||||
}
|
||||
}
|
||||
});
|
||||
// 监听脚本安装
|
||||
subscribeScriptInstall(this.mq, async (data) => {
|
||||
const script = await this.scriptDAO.get(data.script.uuid);
|
||||
if (!script) {
|
||||
return;
|
||||
}
|
||||
if (script.type === SCRIPT_TYPE_NORMAL) {
|
||||
this.registryPageScript(script);
|
||||
}
|
||||
});
|
||||
// 监听脚本删除
|
||||
subscribeScriptDelete(this.mq, async (data) => {
|
||||
const script = await this.scriptDAO.get(data.uuid);
|
||||
if (!script) {
|
||||
return;
|
||||
}
|
||||
if (script.type === SCRIPT_TYPE_NORMAL) {
|
||||
this.unregistryPageScript(script);
|
||||
}
|
||||
});
|
||||
|
||||
// 将开启的脚本发送一次enable消息
|
||||
const scriptDao = new ScriptDAO();
|
||||
@ -63,6 +98,11 @@ export class RuntimeService {
|
||||
|
||||
this.group.on("stopScript", this.stopScript.bind(this));
|
||||
this.group.on("runScript", this.runScript.bind(this));
|
||||
this.group.on("pageLoad", this.pageLoad.bind(this));
|
||||
}
|
||||
|
||||
pageLoad() {
|
||||
return Promise.resolve({ flag: this.scriptFlag });
|
||||
}
|
||||
|
||||
// 停止脚本
|
||||
@ -80,16 +120,41 @@ export class RuntimeService {
|
||||
return runScript(this.sender, res);
|
||||
}
|
||||
|
||||
registryPageScript(script: ScriptAndCode) {
|
||||
console.log(script);
|
||||
registerInjectScript() {
|
||||
fetch("inject.js")
|
||||
.then((res) => res.text())
|
||||
.then((injectJs) => {
|
||||
// 替换ScriptFlag
|
||||
const code = `(function (ScriptFlag) {\n${injectJs}\n})('${this.scriptFlag}')`;
|
||||
chrome.userScripts.register([
|
||||
{
|
||||
id: "scriptcat-inject",
|
||||
js: [{ code }],
|
||||
matches: ["<all_urls>"],
|
||||
allFrames: true,
|
||||
world: "MAIN",
|
||||
runAt: "document_start",
|
||||
},
|
||||
]);
|
||||
});
|
||||
}
|
||||
|
||||
async registryPageScript(script: Script) {
|
||||
const matches = script.metadata["match"];
|
||||
if (!matches) {
|
||||
return;
|
||||
}
|
||||
const scriptRes = await this.script.buildScriptRunResource(script);
|
||||
|
||||
scriptRes.code = compileScriptCode(scriptRes);
|
||||
scriptRes.code = compileInjectScript(scriptRes);
|
||||
|
||||
this.runningPageScript.set(scriptRes.uuid, scriptRes);
|
||||
|
||||
matches.push(...(script.metadata["include"] || []));
|
||||
const registerScript: chrome.userScripts.RegisteredUserScript = {
|
||||
id: script.uuid,
|
||||
js: [{ code: script.code }],
|
||||
id: scriptRes.uuid,
|
||||
js: [{ code: scriptRes.code }],
|
||||
matches: dealMatches(matches),
|
||||
world: "MAIN",
|
||||
};
|
||||
@ -102,7 +167,7 @@ export class RuntimeService {
|
||||
registerScript.excludeMatches = dealMatches(excludeMatches);
|
||||
}
|
||||
if (script.metadata["run-at"]) {
|
||||
registerScript.runAt = script.metadata["run-at"][0] as chrome.userScripts.RunAt;
|
||||
registerScript.runAt = getRunAt(script.metadata["run-at"]);
|
||||
}
|
||||
chrome.userScripts.register([registerScript]);
|
||||
}
|
||||
|
@ -273,7 +273,8 @@ export class ScriptService {
|
||||
if (!code) {
|
||||
throw new Error("code is null");
|
||||
}
|
||||
ret.code = compileScriptCode(ret, code.code);
|
||||
ret.code = code.code;
|
||||
ret.code = compileScriptCode(ret);
|
||||
|
||||
return Promise.resolve(ret);
|
||||
}
|
||||
|
@ -9,3 +9,16 @@ export function isExtensionRequest(details: chrome.webRequest.ResourceRequest &
|
||||
export function dealMatches(matches: string[]) {
|
||||
return matches;
|
||||
}
|
||||
|
||||
export function getRunAt(runAts: string[]): chrome.userScripts.RunAt {
|
||||
if (runAts.length === 0) {
|
||||
return "document_idle";
|
||||
}
|
||||
const runAt = runAts[0];
|
||||
if (runAt === "document-start") {
|
||||
return "document_start";
|
||||
} else if (runAt === "document-end") {
|
||||
return "document_end";
|
||||
}
|
||||
return "document_idle";
|
||||
}
|
||||
|
@ -1,24 +1,25 @@
|
||||
import LoggerCore from "./app/logger/core";
|
||||
import MessageWriter from "./app/logger/message_writer";
|
||||
import { SandboxManager } from "./app/service/sandbox";
|
||||
import { ExtensionMessageSend } from "@Packages/message/extension_message";
|
||||
import { CustomEventMessage } from "@Packages/message/custom_event_message";
|
||||
import { RuntimeClient } from "./app/service/service_worker/client";
|
||||
import ContentRuntime from "./runtime/content/content";
|
||||
|
||||
function main() {
|
||||
// 建立与service_worker页面的连接
|
||||
const msg = new ExtensionMessageSend();
|
||||
// 建立与service_worker页面的连接
|
||||
const send = new ExtensionMessageSend();
|
||||
|
||||
// 初始化日志组件
|
||||
const loggerCore = new LoggerCore({
|
||||
writer: new MessageWriter(msg),
|
||||
labels: { env: "content" },
|
||||
});
|
||||
// 初始化日志组件
|
||||
const loggerCore = new LoggerCore({
|
||||
writer: new MessageWriter(send),
|
||||
labels: { env: "content" },
|
||||
});
|
||||
|
||||
const client = new RuntimeClient(send);
|
||||
client.pageLoad().then((data) => {
|
||||
loggerCore.logger().debug("content start");
|
||||
|
||||
console.log("content", data);
|
||||
const msg = new CustomEventMessage(data.flag, true);
|
||||
// 初始化运行环境
|
||||
const contentMessage = new MessageContent(scriptFlag, true);
|
||||
const runtime = new ContentRuntime(contentMessage, internalMessage);
|
||||
runtime.start();
|
||||
}
|
||||
|
||||
main();
|
||||
const runtime = new ContentRuntime(send, msg);
|
||||
runtime.start(data.scripts);
|
||||
});
|
||||
|
26
src/inject.ts
Normal file
26
src/inject.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import LoggerCore from "./app/logger/core";
|
||||
import MessageWriter from "./app/logger/message_writer";
|
||||
import { CustomEventMessage } from "@Packages/message/custom_event_message";
|
||||
import { Server } from "@Packages/message/server";
|
||||
import { InjectRuntime } from "./runtime/content/inject";
|
||||
import { ScriptRunResouce } from "./app/repo/scripts";
|
||||
|
||||
// 通过flag与content建立通讯,这个ScriptFlag是后端注入时候生成的
|
||||
const flag = ScriptFlag;
|
||||
|
||||
const msg = new CustomEventMessage(flag, false);
|
||||
|
||||
// 加载logger组件
|
||||
const logger = new LoggerCore({
|
||||
writer: new MessageWriter(msg),
|
||||
labels: { env: "inject", href: window.location.href },
|
||||
});
|
||||
|
||||
const server = new Server("inject", msg);
|
||||
|
||||
server.on("pageLoad", (data: ScriptRunResouce[]) => {
|
||||
logger.logger().debug("inject start");
|
||||
console.log("inject", data);
|
||||
const runtime = new InjectRuntime(msg, data);
|
||||
runtime.start();
|
||||
});
|
@ -1,23 +0,0 @@
|
||||
import LoggerCore from "./app/logger/core";
|
||||
import MessageWriter from "./app/logger/message_writer";
|
||||
import MessageContent from "./app/message/content";
|
||||
import InjectRuntime from "./runtime/content/inject";
|
||||
|
||||
// 通过flag与content建立通讯,这个ScriptFlag是后端注入时候生成的
|
||||
// eslint-disable-next-line no-undef
|
||||
const flag = ScriptFlag;
|
||||
|
||||
const message = new MessageContent(flag, false);
|
||||
|
||||
// 加载logger组件
|
||||
const logger = new LoggerCore({
|
||||
debug: process.env.NODE_ENV === "development",
|
||||
writer: new MessageWriter(message),
|
||||
labels: { env: "inject", href: window.location.href },
|
||||
});
|
||||
|
||||
message.setHandler("pageLoad", (_action, data) => {
|
||||
logger.logger().debug("inject start");
|
||||
const runtime = new InjectRuntime(message, data.scripts, flag);
|
||||
runtime.start();
|
||||
});
|
@ -17,6 +17,18 @@
|
||||
"128": "assets/logo.png"
|
||||
}
|
||||
},
|
||||
"content_scripts": [
|
||||
{
|
||||
"matches": [
|
||||
"<all_urls>"
|
||||
],
|
||||
"js": [
|
||||
"src/content.js"
|
||||
],
|
||||
"run_at": "document_start",
|
||||
"all_frames": true
|
||||
}
|
||||
],
|
||||
"icons": {
|
||||
"128": "assets/logo.png"
|
||||
},
|
||||
|
@ -1,115 +1,94 @@
|
||||
import { ExternalMessage } from "@App/app/const";
|
||||
import MessageContent from "@App/app/message/content";
|
||||
import MessageInternal from "@App/app/message/internal";
|
||||
import { MessageHander, MessageManager } from "@App/app/message/message";
|
||||
import { ScriptRunResouce } from "@App/app/repo/scripts";
|
||||
import { Client } from "@Packages/message/client";
|
||||
import { Message, MessageSend } from "@Packages/message/server";
|
||||
|
||||
// content页的处理
|
||||
export default class ContentRuntime {
|
||||
contentMessage: MessageHander & MessageManager;
|
||||
|
||||
internalMessage: MessageInternal;
|
||||
|
||||
constructor(
|
||||
contentMessage: MessageHander & MessageManager,
|
||||
internalMessage: MessageInternal
|
||||
) {
|
||||
this.contentMessage = contentMessage;
|
||||
this.internalMessage = internalMessage;
|
||||
}
|
||||
private send: MessageSend,
|
||||
private msg: Message
|
||||
) {}
|
||||
|
||||
start(resp: { scripts: ScriptRunResouce[] }) {
|
||||
start(scripts: ScriptRunResouce[]) {
|
||||
// 由content到background
|
||||
// 转发gmApi消息
|
||||
this.contentMessage.setHandler("gmApi", (action, data) => {
|
||||
return this.internalMessage.syncSend(action, data);
|
||||
});
|
||||
// 转发log消息
|
||||
this.contentMessage.setHandler("log", (action, data) => {
|
||||
this.internalMessage.send(action, data);
|
||||
});
|
||||
// 转发externalMessage消息
|
||||
this.contentMessage.setHandler(ExternalMessage, (action, data) => {
|
||||
return this.internalMessage.syncSend(action, data);
|
||||
});
|
||||
// this.contentMessage.setHandler("gmApi", (action, data) => {
|
||||
// return this.internalMessage.syncSend(action, data);
|
||||
// });
|
||||
// // 转发log消息
|
||||
// this.contentMessage.setHandler("log", (action, data) => {
|
||||
// this.internalMessage.send(action, data);
|
||||
// });
|
||||
// // 转发externalMessage消息
|
||||
// this.contentMessage.setHandler(ExternalMessage, (action, data) => {
|
||||
// return this.internalMessage.syncSend(action, data);
|
||||
// });
|
||||
// 处理GM_addElement
|
||||
// @ts-ignore
|
||||
this.contentMessage.setHandler("GM_addElement", (action, data) => {
|
||||
const parma = data.param;
|
||||
let attr: { [x: string]: any; textContent?: any };
|
||||
let textContent = "";
|
||||
if (!parma[1]) {
|
||||
attr = {};
|
||||
} else {
|
||||
attr = { ...parma[1] };
|
||||
if (attr.textContent) {
|
||||
textContent = attr.textContent;
|
||||
delete attr.textContent;
|
||||
}
|
||||
}
|
||||
const el = <Element>document.createElement(parma[0]);
|
||||
Object.keys(attr).forEach((key) => {
|
||||
el.setAttribute(key, attr[key]);
|
||||
});
|
||||
if (textContent) {
|
||||
el.innerHTML = textContent;
|
||||
}
|
||||
let parentNode;
|
||||
if (data.relatedTarget) {
|
||||
parentNode = (<MessageContent>(
|
||||
this.contentMessage
|
||||
)).getAndDelRelatedTarget(data.relatedTarget);
|
||||
}
|
||||
(
|
||||
<Element>parentNode ||
|
||||
document.head ||
|
||||
document.body ||
|
||||
document.querySelector("*")
|
||||
).appendChild(el);
|
||||
return {
|
||||
relatedTarget: el,
|
||||
};
|
||||
});
|
||||
|
||||
// 转发长连接的gmApi消息
|
||||
this.contentMessage.setHandlerWithChannel(
|
||||
"gmApiChannel",
|
||||
(inject, action, data) => {
|
||||
const background = this.internalMessage.channel();
|
||||
// 转发inject->background
|
||||
inject.setHandler((req) => {
|
||||
background.send(req.data);
|
||||
});
|
||||
inject.setCatch((err) => {
|
||||
background.throw(err);
|
||||
});
|
||||
inject.setDisChannelHandler(() => {
|
||||
background.disChannel();
|
||||
});
|
||||
// 转发background->inject
|
||||
background.setHandler((bgResp) => {
|
||||
inject.send(bgResp);
|
||||
});
|
||||
background.setCatch((err) => {
|
||||
inject.throw(err);
|
||||
});
|
||||
background.setDisChannelHandler(() => {
|
||||
inject.disChannel();
|
||||
});
|
||||
// 建立连接
|
||||
background.channel(action, data);
|
||||
}
|
||||
);
|
||||
|
||||
this.listenCATApi();
|
||||
|
||||
// 由background到content
|
||||
// 转发value更新事件
|
||||
this.internalMessage.setHandler("valueUpdate", (action, data) => {
|
||||
this.contentMessage.send(action, data);
|
||||
});
|
||||
|
||||
this.contentMessage.send("pageLoad", resp);
|
||||
// this.contentMessage.setHandler("GM_addElement", (action, data) => {
|
||||
// const parma = data.param;
|
||||
// let attr: { [x: string]: any; textContent?: any };
|
||||
// let textContent = "";
|
||||
// if (!parma[1]) {
|
||||
// attr = {};
|
||||
// } else {
|
||||
// attr = { ...parma[1] };
|
||||
// if (attr.textContent) {
|
||||
// textContent = attr.textContent;
|
||||
// delete attr.textContent;
|
||||
// }
|
||||
// }
|
||||
// const el = <Element>document.createElement(parma[0]);
|
||||
// Object.keys(attr).forEach((key) => {
|
||||
// el.setAttribute(key, attr[key]);
|
||||
// });
|
||||
// if (textContent) {
|
||||
// el.innerHTML = textContent;
|
||||
// }
|
||||
// let parentNode;
|
||||
// if (data.relatedTarget) {
|
||||
// parentNode = (<MessageContent>this.contentMessage).getAndDelRelatedTarget(data.relatedTarget);
|
||||
// }
|
||||
// (<Element>parentNode || document.head || document.body || document.querySelector("*")).appendChild(el);
|
||||
// return {
|
||||
// relatedTarget: el,
|
||||
// };
|
||||
// });
|
||||
// // 转发长连接的gmApi消息
|
||||
// this.contentMessage.setHandlerWithChannel("gmApiChannel", (inject, action, data) => {
|
||||
// const background = this.internalMessage.channel();
|
||||
// // 转发inject->background
|
||||
// inject.setHandler((req) => {
|
||||
// background.send(req.data);
|
||||
// });
|
||||
// inject.setCatch((err) => {
|
||||
// background.throw(err);
|
||||
// });
|
||||
// inject.setDisChannelHandler(() => {
|
||||
// background.disChannel();
|
||||
// });
|
||||
// // 转发background->inject
|
||||
// background.setHandler((bgResp) => {
|
||||
// inject.send(bgResp);
|
||||
// });
|
||||
// background.setCatch((err) => {
|
||||
// inject.throw(err);
|
||||
// });
|
||||
// background.setDisChannelHandler(() => {
|
||||
// inject.disChannel();
|
||||
// });
|
||||
// // 建立连接
|
||||
// background.channel(action, data);
|
||||
// });
|
||||
// this.listenCATApi();
|
||||
// // 由background到content
|
||||
// // 转发value更新事件
|
||||
// this.internalMessage.setHandler("valueUpdate", (action, data) => {
|
||||
// this.contentMessage.send(action, data);
|
||||
// });
|
||||
// this.msg.sendMessage({ action: "pageLoad", data: { scripts } });
|
||||
const client = new Client(this.msg, "inject");
|
||||
client.do("pageLoad", { scripts });
|
||||
}
|
||||
|
||||
listenCATApi() {
|
||||
@ -117,16 +96,13 @@ export default class ContentRuntime {
|
||||
this.contentMessage.setHandler("CAT_fetchBlob", (_action, data: string) => {
|
||||
return fetch(data).then((res) => res.blob());
|
||||
});
|
||||
this.contentMessage.setHandler(
|
||||
"CAT_createBlobUrl",
|
||||
(_action, data: Blob) => {
|
||||
const url = URL.createObjectURL(data);
|
||||
setTimeout(() => {
|
||||
URL.revokeObjectURL(url);
|
||||
}, 60 * 1000);
|
||||
return Promise.resolve(url);
|
||||
}
|
||||
);
|
||||
this.contentMessage.setHandler("CAT_createBlobUrl", (_action, data: Blob) => {
|
||||
const url = URL.createObjectURL(data);
|
||||
setTimeout(() => {
|
||||
URL.revokeObjectURL(url);
|
||||
}, 60 * 1000);
|
||||
return Promise.resolve(url);
|
||||
});
|
||||
// 处理CAT_fetchDocument
|
||||
this.contentMessage.setHandler("CAT_fetchDocument", (_action, data) => {
|
||||
return new Promise((resolve) => {
|
||||
|
11
src/runtime/content/inject.ts
Normal file
11
src/runtime/content/inject.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { ScriptRunResouce } from "@App/app/repo/scripts";
|
||||
import { Message } from "@Packages/message/server";
|
||||
|
||||
export class InjectRuntime {
|
||||
constructor(
|
||||
private msg: Message,
|
||||
private scripts: ScriptRunResouce[]
|
||||
) {}
|
||||
|
||||
start(){}
|
||||
}
|
@ -5,7 +5,7 @@ import { has } from "@App/pkg/utils/lodash";
|
||||
import { Message } from "@Packages/message/server";
|
||||
|
||||
// 构建脚本运行代码
|
||||
export function compileScriptCode(scriptRes: ScriptRunResouce, code: string): string {
|
||||
export function compileScriptCode(scriptRes: ScriptRunResouce): string {
|
||||
let require = "";
|
||||
if (scriptRes.metadata.require) {
|
||||
scriptRes.metadata.require.forEach((val) => {
|
||||
@ -15,7 +15,7 @@ export function compileScriptCode(scriptRes: ScriptRunResouce, code: string): st
|
||||
}
|
||||
});
|
||||
}
|
||||
code = require + code;
|
||||
const code = require + scriptRes.code;
|
||||
return `with (context) return (async ()=>{\n${code}\n//# sourceURL=${chrome.runtime.getURL(
|
||||
`/${encodeURI(scriptRes.name)}.user.js`
|
||||
)}\n})()`;
|
||||
|
@ -55,7 +55,8 @@ async function main() {
|
||||
});
|
||||
loggerCore.logger().debug("service worker start");
|
||||
// 初始化管理器
|
||||
const server = new Server("serviceWorker", new ExtensionMessage());
|
||||
const message = new ExtensionMessage();
|
||||
const server = new Server("serviceWorker", message);
|
||||
const manager = new ServiceWorkerManager(server, new MessageQueue(), new ServiceWorkerMessageSend());
|
||||
manager.initManager();
|
||||
// 初始化沙盒环境
|
||||
|
5
src/types/main.d.ts
vendored
5
src/types/main.d.ts
vendored
@ -7,6 +7,11 @@ declare const sandbox: Window;
|
||||
|
||||
declare const self: ServiceWorkerGlobalScope;
|
||||
|
||||
declare const ScriptFlag: string;
|
||||
|
||||
// 可以让content与inject环境交换携带dom的对象
|
||||
declare let cloneInto: ((detail: any, view: any) => any) | undefined;
|
||||
|
||||
declare namespace GMSend {
|
||||
interface XHRDetails {
|
||||
method?: "GET" | "HEAD" | "POST" | "PUT" | "DELETE" | "PATCH" | "OPTIONS";
|
||||
|
Reference in New Issue
Block a user