From 44e1449e03c011776a8d2213e51f6a012db129ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E4=B8=80=E4=B9=8B?= Date: Wed, 16 Apr 2025 16:48:58 +0800 Subject: [PATCH] =?UTF-8?q?=E6=A3=80=E6=9F=A5=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/message/server.ts | 2 +- src/app/service/service_worker/client.ts | 8 ++ src/app/service/service_worker/index.ts | 11 +- src/app/service/service_worker/script.ts | 124 ++++++++++++++++- src/app/service/service_worker/value.ts | 10 +- src/manifest.json | 1 + .../components/UserConfigPanel/index.tsx | 59 ++------ src/pages/options/routes/ScriptList.tsx | 130 ++++++++---------- .../options/routes/script/ScriptEditor.tsx | 4 +- src/pages/options/routes/utils.tsx | 4 - src/pages/store/subscribe.ts | 1 + src/pkg/utils/script.ts | 9 +- src/pkg/utils/utils.ts | 5 +- 13 files changed, 228 insertions(+), 140 deletions(-) diff --git a/packages/message/server.ts b/packages/message/server.ts index 805628a..3be2ec0 100644 --- a/packages/message/server.ts +++ b/packages/message/server.ts @@ -173,7 +173,7 @@ export function forwardMessage( } else if (resp !== false) { return resp; } - return handler(params, sender); } + return handler(params, sender); }); } diff --git a/src/app/service/service_worker/client.ts b/src/app/service/service_worker/client.ts index 286d691..47c035f 100644 --- a/src/app/service/service_worker/client.ts +++ b/src/app/service/service_worker/client.ts @@ -53,6 +53,10 @@ export class ScriptClient extends Client { excludeUrl(uuid: string, url: string, remove: boolean) { return this.do("excludeUrl", { uuid, url, remove }); } + + requestCheckUpdate(uuid: string) { + return this.do("requestCheckUpdate", uuid); + } } export class ResourceClient extends Client { @@ -73,6 +77,10 @@ export class ValueClient extends Client { getScriptValue(script: Script) { return this.do("getScriptValue", script); } + + setScriptValue(uuid: string, key: string, value: any) { + return this.do("setScriptValue", { uuid, key, value }); + } } export class RuntimeClient extends Client { diff --git a/src/app/service/service_worker/index.ts b/src/app/service/service_worker/index.ts index e69b602..38125a4 100644 --- a/src/app/service/service_worker/index.ts +++ b/src/app/service/service_worker/index.ts @@ -30,12 +30,21 @@ export default class ServiceWorkerManager { const resource = new ResourceService(this.api.group("resource"), this.mq); resource.init(); const value = new ValueService(this.api.group("value"), this.sender); - const script = new ScriptService(this.api.group("script"), this.mq, value, resource); + const script = new ScriptService(systemConfig, this.api.group("script"), this.mq, value, resource); script.init(); const runtime = new RuntimeService(systemConfig, this.api.group("runtime"), this.sender, this.mq, value, script); runtime.init(); const popup = new PopupService(this.api.group("popup"), this.mq, runtime); popup.init(); value.init(runtime, popup); + + // 定时器处理 + chrome.alarms.onAlarm.addListener((alarm) => { + switch (alarm.name) { + case "checkScriptUpdate": + script.checkScriptUpdate(); + break; + } + }); } } diff --git a/src/app/service/service_worker/script.ts b/src/app/service/service_worker/script.ts index 4e39629..9e100de 100644 --- a/src/app/service/service_worker/script.ts +++ b/src/app/service/service_worker/script.ts @@ -1,11 +1,11 @@ -import { fetchScriptInfo } from "@App/pkg/utils/script"; +import { fetchScriptInfo, prepareScriptByCode } from "@App/pkg/utils/script"; import { v4 as uuidv4 } from "uuid"; import { Group } from "@Packages/message/server"; import Logger from "@App/app/logger/logger"; import LoggerCore from "@App/app/logger/core"; import Cache from "@App/app/cache"; import CacheKey from "@App/app/cache_key"; -import { openInCurrentTab, randomString } from "@App/pkg/utils/utils"; +import { checkSilenceUpdate, ltever, openInCurrentTab, randomString } from "@App/pkg/utils/utils"; import { Script, SCRIPT_RUN_STATUS, @@ -20,6 +20,7 @@ import { InstallSource } from "."; import { ResourceService } from "./resource"; import { ValueService } from "./value"; import { compileScriptCode } from "../content/utils"; +import { SystemConfig } from "@App/pkg/config/config"; export class ScriptService { logger: Logger; @@ -27,6 +28,7 @@ export class ScriptService { scriptCodeDAO: ScriptCodeDAO = new ScriptCodeDAO(); constructor( + private systemConfig: SystemConfig, private group: Group, private mq: MessageQueue, private valueService: ValueService, @@ -305,6 +307,117 @@ export class ScriptService { }); } + async checkUpdate(uuid: string, source: "user" | "system") { + // 检查更新 + const script = await this.scriptDAO.get(uuid); + if (!script) { + return Promise.resolve(false); + } + await this.scriptDAO.update(uuid, { checktime: new Date().getTime() }); + if (!script.checkUpdateUrl) { + return Promise.resolve(false); + } + const logger = LoggerCore.logger({ + uuid: script.uuid, + name: script.name, + }); + try { + const info = await fetchScriptInfo(script.checkUpdateUrl, source, false, script.uuid); + const { metadata } = info; + if (!metadata) { + logger.error("parse metadata failed"); + return Promise.resolve(false); + } + const newVersion = metadata.version && metadata.version[0]; + if (!newVersion) { + logger.error("parse version failed", { version: "" }); + return Promise.resolve(false); + } + let oldVersion = script.metadata.version && script.metadata.version[0]; + if (!oldVersion) { + oldVersion = "0.0.0"; + } + // 对比版本大小 + if (ltever(newVersion, oldVersion, logger)) { + return Promise.resolve(false); + } + // 进行更新 + this.openUpdatePage(script, source); + } catch (e) { + logger.error("check update failed", Logger.E(e)); + return Promise.resolve(false); + } + return Promise.resolve(true); + } + + // 打开更新窗口 + public openUpdatePage(script: Script, source: "user" | "system") { + const logger = this.logger.with({ + uuid: script.uuid, + name: script.name, + downloadUrl: script.downloadUrl, + checkUpdateUrl: script.checkUpdateUrl, + }); + fetchScriptInfo(script.downloadUrl || script.checkUpdateUrl!, source, true, script.uuid) + .then(async (info) => { + // 是否静默更新 + if (await this.systemConfig.getSilenceUpdateScript()) { + try { + const prepareScript = await prepareScriptByCode( + info.code, + script.downloadUrl || script.checkUpdateUrl!, + script.uuid + ); + if (checkSilenceUpdate(prepareScript.oldScript!.metadata, prepareScript.script.metadata)) { + logger.info("silence update script"); + this.installScript({ + script: prepareScript.script, + code: info.code, + upsertBy: source, + }); + return; + } + } catch (e) { + logger.error("prepare script failed", Logger.E(e)); + } + return; + } + // 打开安装页面 + Cache.getInstance().set(CacheKey.scriptInstallInfo(info.uuid), info); + chrome.tabs.create({ + url: `/src/install.html?uuid=${info.uuid}`, + }); + }) + .catch((e) => { + logger.error("fetch script info failed", Logger.E(e)); + }); + } + + checkScriptUpdate() { + this.scriptDAO.all().then(async (scripts) => { + const checkCycle = await this.systemConfig.getCheckScriptUpdateCycle(); + if (!checkCycle) { + return; + } + const check = await this.systemConfig.getUpdateDisableScript(); + scripts.forEach(async (script) => { + // 是否检查禁用脚本 + if (!check && script.status === SCRIPT_STATUS_DISABLE) { + return; + } + // 检查是否符合 + if (script.checktime + checkCycle * 1000 > Date.now()) { + return; + } + this.checkUpdate(script.uuid, "system"); + }); + }); + } + + requestCheckUpdate(uuid: string) { + return this.checkUpdate(uuid, "user"); + } + init() { this.listenerScriptInstall(); @@ -317,5 +430,12 @@ export class ScriptService { this.group.on("getCode", this.getCode.bind(this)); this.group.on("getScriptRunResource", this.buildScriptRunResource.bind(this)); this.group.on("excludeUrl", this.excludeUrl.bind(this)); + this.group.on("requestCheckUpdate", this.requestCheckUpdate.bind(this)); + + // 定时检查更新, 每10分钟检查一次 + chrome.alarms.create("checkScriptUpdate", { + delayInMinutes: 10, + periodInMinutes: 10, + }); } } diff --git a/src/app/service/service_worker/value.ts b/src/app/service/service_worker/value.ts index 158a885..1a7e371 100644 --- a/src/app/service/service_worker/value.ts +++ b/src/app/service/service_worker/value.ts @@ -2,7 +2,7 @@ import LoggerCore from "@App/app/logger/core"; import Logger from "@App/app/logger/logger"; import { Script, SCRIPT_TYPE_NORMAL, ScriptDAO } from "@App/app/repo/scripts"; import { ValueDAO } from "@App/app/repo/value"; -import { Group, MessageSend } from "@Packages/message/server"; +import { GetSender, Group, MessageSend } from "@Packages/message/server"; import { RuntimeService } from "./runtime"; import { PopupService } from "./popup"; import { sendMessage } from "@Packages/message/client"; @@ -95,9 +95,17 @@ export class ValueService { return Promise.resolve(true); } + setScriptValue(data: { uuid: string; key: string; value: any }, sender: GetSender) { + return this.setValue(data.uuid, data.key, data.value, { + runFlag: "user", + tabId: -2, + }); + } + init(runtime: RuntimeService, popup: PopupService) { this.popup = popup; this.runtime = runtime; this.group.on("getScriptValue", this.getScriptValue.bind(this)); + this.group.on("setScriptValue", this.setScriptValue.bind(this)); } } diff --git a/src/manifest.json b/src/manifest.json index 00181fe..4e6a017 100644 --- a/src/manifest.json +++ b/src/manifest.json @@ -23,6 +23,7 @@ "default_locale": "zh_CN", "permissions": [ "tabs", + "alarms", "storage", "cookies", "offscreen", diff --git a/src/pages/components/UserConfigPanel/index.tsx b/src/pages/components/UserConfigPanel/index.tsx index 8ba6106..18badf7 100644 --- a/src/pages/components/UserConfigPanel/index.tsx +++ b/src/pages/components/UserConfigPanel/index.tsx @@ -1,18 +1,10 @@ import React, { useEffect, useRef } from "react"; import { useTranslation } from "react-i18next"; // 添加这行导入语句 import { Script, UserConfig } from "@App/app/repo/scripts"; -import { - Checkbox, - Form, - FormInstance, - Input, - InputNumber, - Message, - Modal, - Select, - Tabs, -} from "@arco-design/web-react"; +import { Checkbox, Form, FormInstance, Input, InputNumber, Message, Modal, Select, Tabs } from "@arco-design/web-react"; import TabPane from "@arco-design/web-react/es/Tabs/tab-pane"; +import { ValueClient } from "@App/app/service/service_worker/client"; +import { message } from "@App/pages/store/global"; const FormItem = Form.Item; @@ -41,17 +33,13 @@ const UserConfigPanel: React.FC<{ if (formRefs.current[tab]) { const saveValues = formRefs.current[tab].getFieldsValue(); // 更新value - const valueCtrl = IoC.instance(ValueController) as ValueController; + const valueClient = new ValueClient(message); Object.keys(saveValues).forEach((key) => { Object.keys(saveValues[key]).forEach((valueKey) => { if (saveValues[key][valueKey] === undefined) { return; } - valueCtrl.setValue( - script.id, - `${key}.${valueKey}`, - saveValues[key][valueKey] - ); + valueClient.setScriptValue(script.uuid, `${key}.${valueKey}`, saveValues[key][valueKey]); }); }); Message.success(t("save_success")!); // 替换为键值对应的英文文本 @@ -73,7 +61,7 @@ const UserConfigPanel: React.FC<{ return (
{Object.keys(value).map((key) => ( - + {() => { const item = value[key]; let { type } = item; @@ -112,20 +96,9 @@ const UserConfigPanel: React.FC<{ switch (type) { case "text": if (item.password) { - return ( - - ); + return ; } - return ( - - ); + return ; case "number": return ( ); case "checkbox": - return ( - - {item.description} - - ); + return {item.description}; case "select": case "mult-select": // eslint-disable-next-line no-case-declarations @@ -159,11 +126,7 @@ const UserConfigPanel: React.FC<{ } return (