value变更
Some checks failed
test / Run tests (push) Failing after 3s
build / Build (push) Failing after 5s

This commit is contained in:
王一之 2025-04-08 23:54:06 +08:00
parent 3e660a2ea8
commit 9f70b7eb7a
7 changed files with 110 additions and 28 deletions

View File

@ -15,8 +15,8 @@
// ==/UserScript== // ==/UserScript==
GM_addValueChangeListener("test_set", function (name, oldval, newval, remote, tabid) { GM_addValueChangeListener("test_set", function (name, oldval, newval, remote, tabid) {
GM_cookie("store", tabid,(storeId) => { GM_cookie("store", tabid, (storeId) => {
console.log("store",storeId); console.log("store", storeId);
}); });
}); });
@ -30,3 +30,7 @@ setTimeout(() => {
}, 3000); }, 3000);
GM_setValue("test_set", new Date().getTime()); GM_setValue("test_set", new Date().getTime());
console.log(GM_getValue("test_set2"));
GM_setValue("test_set2", new Date().getTime());

View File

@ -9,6 +9,7 @@ import Cache, { incr } from "@App/app/cache";
import { unsafeHeaders } from "@App/runtime/utils"; import { unsafeHeaders } from "@App/runtime/utils";
import EventEmitter from "eventemitter3"; import EventEmitter from "eventemitter3";
import { MessageQueue } from "@Packages/message/message_queue"; import { MessageQueue } from "@Packages/message/message_queue";
import { RuntimeService } from "./runtime";
// GMApi,处理脚本的GM API调用请求 // GMApi,处理脚本的GM API调用请求
@ -36,7 +37,8 @@ export default class GMApi {
private group: Group, private group: Group,
private send: MessageSend, private send: MessageSend,
private mq: MessageQueue, private mq: MessageQueue,
private value: ValueService private value: ValueService,
private runtime: RuntimeService
) { ) {
this.logger = LoggerCore.logger().with({ service: "runtime/gm_api" }); this.logger = LoggerCore.logger().with({ service: "runtime/gm_api" });
} }
@ -69,12 +71,13 @@ export default class GMApi {
} }
@PermissionVerify.API() @PermissionVerify.API()
GM_setValue(request: Request): Promise<any> { async GM_setValue(request: Request) {
console.log("setValue", request);
if (!request.params || request.params.length !== 2) { if (!request.params || request.params.length !== 2) {
return Promise.reject(new Error("param is failed")); return Promise.reject(new Error("param is failed"));
} }
const [key, value] = request.params; const [key, value] = request.params;
return this.value.setValue(request.script.uuid, key, value); await this.value.setValue(request.script.uuid, key, value);
} }
// 根据header生成dnr规则 // 根据header生成dnr规则

View File

@ -26,13 +26,13 @@ export default class ServiceWorkerManager {
const resource = new ResourceService(this.api.group("resource"), this.mq); const resource = new ResourceService(this.api.group("resource"), this.mq);
resource.init(); resource.init();
const value = new ValueService(this.api.group("value")); const value = new ValueService(this.api.group("value"), this.sender);
value.init();
const script = new ScriptService(this.api.group("script"), this.mq, value, resource); const script = new ScriptService(this.api.group("script"), this.mq, value, resource);
script.init(); script.init();
const runtime = new RuntimeService(this.api.group("runtime"), this.sender, this.mq, value, script); const runtime = new RuntimeService(this.api.group("runtime"), this.sender, this.mq, value, script);
runtime.init(); runtime.init();
const popup = new PopupService(this.api.group("popup"), this.mq, runtime); const popup = new PopupService(this.api.group("popup"), this.mq, runtime);
popup.init(); popup.init();
value.init(runtime, popup);
} }
} }

View File

@ -20,6 +20,7 @@ import {
subscribeScriptMenuRegister, subscribeScriptMenuRegister,
subscribeScriptRunStatus, subscribeScriptRunStatus,
} from "../queue"; } from "../queue";
import { storageKey } from "@App/runtime/utils";
export type ScriptMenuItem = { export type ScriptMenuItem = {
id: number; id: number;
@ -33,6 +34,7 @@ export type ScriptMenuItem = {
export type ScriptMenu = { export type ScriptMenu = {
uuid: string; // 脚本uuid uuid: string; // 脚本uuid
name: string; // 脚本名称 name: string; // 脚本名称
storageName: string; // 脚本存储名称
enable: boolean; // 脚本是否启用 enable: boolean; // 脚本是否启用
updatetime: number; // 脚本更新时间 updatetime: number; // 脚本更新时间
hasUserConfig: boolean; // 是否有用户配置 hasUserConfig: boolean; // 是否有用户配置
@ -124,12 +126,6 @@ export class PopupService {
frameId: message.frameId, frameId: message.frameId,
documentId: message.documentId, documentId: message.documentId,
}); });
} else {
menu.name = message.name;
menu.accessKey = message.accessKey;
menu.tabId = message.tabId;
menu.frameId = message.frameId;
menu.documentId = message.documentId;
} }
} }
this.updateScriptMenu(); this.updateScriptMenu();
@ -167,6 +163,7 @@ export class PopupService {
return { return {
uuid: script.uuid, uuid: script.uuid,
name: script.name, name: script.name,
storageName: storageKey(script),
enable: script.status === SCRIPT_STATUS_ENABLE, enable: script.status === SCRIPT_STATUS_ENABLE,
updatetime: script.updatetime || 0, updatetime: script.updatetime || 0,
hasUserConfig: !!script.config, hasUserConfig: !!script.config,
@ -195,6 +192,13 @@ export class PopupService {
} }
return this.scriptToMenu(script); return this.scriptToMenu(script);
}); });
runScript.forEach((script) => {
const index = scriptMenu.findIndex((item) => item.uuid === script.uuid);
// 把运行了但是不在匹配中的脚本加入菜单
if (index === -1) {
scriptMenu.push(script);
}
});
// 后台脚本只显示开启或者运行中的脚本 // 后台脚本只显示开启或者运行中的脚本
return { scriptList: scriptMenu, backScriptList: await this.getScriptMenu(-1) }; return { scriptList: scriptMenu, backScriptList: await this.getScriptMenu(-1) };
} }
@ -221,7 +225,9 @@ export class PopupService {
}) { }) {
// 设置数据 // 设置数据
return this.txUpdateScriptMenu(tabId, async (data) => { return this.txUpdateScriptMenu(tabId, async (data) => {
data = []; if (!frameId) {
data = [];
}
// 设置脚本运行次数 // 设置脚本运行次数
scripts.forEach((script) => { scripts.forEach((script) => {
const scriptMenu = data.find((item) => item.uuid === script.uuid); const scriptMenu = data.find((item) => item.uuid === script.uuid);

View File

@ -46,7 +46,7 @@ export class RuntimeService {
async init() { async init() {
// 启动gm api // 启动gm api
const gmApi = new GMApi(this.group, this.sender, this.mq, this.value); const gmApi = new GMApi(this.group, this.sender, this.mq, this.value, this);
gmApi.start(); gmApi.start();
this.group.on("stopScript", this.stopScript.bind(this)); this.group.on("stopScript", this.stopScript.bind(this));
@ -147,7 +147,6 @@ export class RuntimeService {
match.add(uuid); match.add(uuid);
}); });
// 转化为数组 // 转化为数组
console.log("matchScriptUuid", matchScriptUuid);
return Array.from(match); return Array.from(match);
} }
return matchScriptUuid; return matchScriptUuid;
@ -187,6 +186,14 @@ export class RuntimeService {
const enableScript = scripts.filter((item) => item); const enableScript = scripts.filter((item) => item);
// 加载value
await Promise.all(
enableScript.map(async (script) => {
const value = await this.value.getScriptValue(script!);
script!.value = value;
})
);
this.mq.emit("pageLoad", { this.mq.emit("pageLoad", {
tabId: chromeSender.tab?.id, tabId: chromeSender.tab?.id,
frameId: chromeSender.frameId, frameId: chromeSender.frameId,

View File

@ -1,16 +1,25 @@
import LoggerCore from "@App/app/logger/core"; import LoggerCore from "@App/app/logger/core";
import Logger from "@App/app/logger/logger"; import Logger from "@App/app/logger/logger";
import { Script, ScriptDAO } from "@App/app/repo/scripts"; import { Script, SCRIPT_TYPE_NORMAL, ScriptDAO } from "@App/app/repo/scripts";
import { ValueDAO } from "@App/app/repo/value"; import { ValueDAO } from "@App/app/repo/value";
import { storageKey } from "@App/runtime/utils"; import { storageKey } from "@App/runtime/utils";
import { Group } from "@Packages/message/server"; import { Group, MessageSend } from "@Packages/message/server";
import { RuntimeService } from "./runtime";
import { PopupService } from "./popup";
import { ValueUpdateData } from "@App/runtime/content/exec_script";
import { sendMessage } from "@Packages/message/client";
export class ValueService { export class ValueService {
logger: Logger; logger: Logger;
scriptDAO: ScriptDAO = new ScriptDAO(); scriptDAO: ScriptDAO = new ScriptDAO();
valueDAO: ValueDAO = new ValueDAO(); valueDAO: ValueDAO = new ValueDAO();
private popup: PopupService | undefined;
private runtime: RuntimeService | undefined;
constructor(private group: Group) { constructor(
private group: Group,
private send: MessageSend
) {
this.logger = LoggerCore.logger().with({ service: "value" }); this.logger = LoggerCore.logger().with({ service: "value" });
} }
@ -19,33 +28,63 @@ export class ValueService {
if (!ret) { if (!ret) {
return {}; return {};
} }
return Promise.resolve(ret?.data); return ret.data;
} }
async setValue(uuid: string, key: string, value: any): Promise<boolean> { async setValue(uuid: string, key: string, value: any, sender?: any): Promise<boolean> {
// 查询出脚本 // 查询出脚本
const script = await this.scriptDAO.get(uuid); const script = await this.scriptDAO.get(uuid);
if (!script) { if (!script) {
return Promise.reject(new Error("script not found")); return Promise.reject(new Error("script not found"));
} }
// 查询老的值 // 查询老的值
const oldValue = await this.valueDAO.get(storageKey(script)); const storageName = storageKey(script);
if (!oldValue) { const valueModel = await this.valueDAO.get(storageName);
this.valueDAO.save(storageKey(script), { let oldValue;
if (!valueModel) {
this.valueDAO.save(storageName, {
uuid: script.uuid, uuid: script.uuid,
storageName: storageKey(script), storageName: storageName,
data: { [key]: value }, data: { [key]: value },
createtime: Date.now(), createtime: Date.now(),
updatetime: Date.now(), updatetime: Date.now(),
}); });
} else { } else {
oldValue.data[key] = value; oldValue = valueModel.data[key];
this.valueDAO.save(storageKey(script), oldValue); valueModel.data[key] = value;
this.valueDAO.save(storageName, valueModel);
} }
const sendData: ValueUpdateData = {
oldValue,
sender,
value,
key,
uuid,
storageKey: storageName,
};
// 判断是后台脚本还是前台脚本
console.log("value update", script, sendData);
if (script.type === SCRIPT_TYPE_NORMAL) {
chrome.tabs.query({}, (tabs) => {
// 推送到所有加载了本脚本的tab中
tabs.forEach(async (tab) => {
const scriptMenu = await this.popup!.getScriptMenu(tab.id!);
if (scriptMenu.find((item) => item.storageName === storageName)) {
this.runtime!.sendMessageToTab(tab.id!, "valueUpdate", sendData);
}
});
});
} else {
// 推送到offscreen中
sendMessage(this.send, "offscreen/runtime/valueUpdate", sendData);
}
return Promise.resolve(true); return Promise.resolve(true);
} }
init() { init(runtime: RuntimeService, popup: PopupService) {
this.popup = popup;
this.runtime = runtime;
this.group.on("getScriptValue", this.getScriptValue.bind(this)); this.group.on("getScriptValue", this.getScriptValue.bind(this));
} }
} }

View File

@ -178,6 +178,29 @@ export default class GMApi {
this.GM_setValue(name, undefined); this.GM_setValue(name, undefined);
} }
valueChangeId: number | undefined;
@GMContext.API()
public GM_addValueChangeListener(name: string, listener: GMTypes.ValueChangeListener): number {
if (!this.valueChangeId) {
this.valueChangeId = 1;
} else {
this.valueChangeId += 1;
}
this.valueChangeListener.set(this.valueChangeId, { name, listener });
return this.valueChangeId;
}
@GMContext.API()
public GM_removeValueChangeListener(listenerId: number): void {
this.valueChangeListener.delete(listenerId);
}
@GMContext.API()
public GM_listValues(): string[] {
return Object.keys(this.scriptRes.value);
}
@GMContext.API() @GMContext.API()
GM_log(message: string, level?: GMTypes.LoggerLevel, labels?: GMTypes.LoggerLabel) { GM_log(message: string, level?: GMTypes.LoggerLevel, labels?: GMTypes.LoggerLabel) {
if (typeof message !== "string") { if (typeof message !== "string") {