From 78152222f3d8fa595e5dd85e37c6ea23d08a5752 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E4=B8=80=E4=B9=8B?= Date: Fri, 27 Dec 2024 17:48:15 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B6=88=E6=81=AF=E9=80=9A=E8=AE=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- packages/message/client.ts | 32 + packages/message/message_queue.ts | 15 +- packages/message/server.ts | 29 +- rspack.config.ts | 11 +- src/app/cache_key.ts | 41 +- src/app/logger/core.ts | 5 +- src/app/logger/logger.ts | 2 - src/app/migrate.ts | 4 + src/app/repo/repo.ts | 58 + src/app/repo/scripts.ts | 43 +- src/app/repo/subscribe.ts | 11 +- src/app/service/service_worker/client.ts | 17 + src/app/service/service_worker/index.ts | 130 +- src/app/service/service_worker/script.ts | 157 +++ src/manifest.json | 1 + src/pages/install/App.tsx | 154 ++- src/pages/options/index.css | 41 + src/pages/options/main.tsx | 25 + src/pages/options/routes/Logger.tsx | 362 ++++++ src/pages/options/routes/ScriptList.tsx | 1051 +++++++++++++++++ src/pages/options/routes/Setting.tsx | 269 +++++ src/pages/options/routes/SubscribeList.tsx | 320 +++++ src/pages/options/routes/Tools.tsx | 346 ++++++ .../options/routes/script/ScriptEditor.tsx | 927 +++++++++++++++ src/pages/options/routes/script/index.css | 6 + src/pages/options/routes/utils.tsx | 223 ++++ .../{install/index.html => template.html} | 0 src/pkg/utils/script.ts | 19 +- src/pkg/utils/utils.ts | 4 + 29 files changed, 4051 insertions(+), 252 deletions(-) create mode 100644 packages/message/client.ts create mode 100644 src/app/repo/repo.ts create mode 100644 src/app/service/service_worker/client.ts create mode 100644 src/app/service/service_worker/script.ts create mode 100644 src/pages/options/index.css create mode 100644 src/pages/options/main.tsx create mode 100644 src/pages/options/routes/Logger.tsx create mode 100644 src/pages/options/routes/ScriptList.tsx create mode 100644 src/pages/options/routes/Setting.tsx create mode 100644 src/pages/options/routes/SubscribeList.tsx create mode 100644 src/pages/options/routes/Tools.tsx create mode 100644 src/pages/options/routes/script/ScriptEditor.tsx create mode 100644 src/pages/options/routes/script/index.css create mode 100644 src/pages/options/routes/utils.tsx rename src/pages/{install/index.html => template.html} (100%) diff --git a/packages/message/client.ts b/packages/message/client.ts new file mode 100644 index 0000000..238c2db --- /dev/null +++ b/packages/message/client.ts @@ -0,0 +1,32 @@ +export function sendMessage(action: string, params?: any): Promise { + return new Promise((resolve, reject) => { + chrome.runtime.sendMessage({ action, data: params }, (res) => { + if (res.code) { + console.error(res); + reject(res.message); + } else { + resolve(res.data); + } + }); + }); +} + +export function connect(action: string, params?: any): Promise { + return new Promise((resolve) => { + const port = chrome.runtime.connect(); + port.postMessage({ action, data: params }); + resolve(port); + }); +} + +export class Client { + constructor(private prefix: string) { + if (!this.prefix.endsWith("/")) { + this.prefix += "/"; + } + } + + do(action: string, params?: any): Promise { + return sendMessage(this.prefix + action, params); + } +} diff --git a/packages/message/message_queue.ts b/packages/message/message_queue.ts index f233e7e..cf537d4 100644 --- a/packages/message/message_queue.ts +++ b/packages/message/message_queue.ts @@ -1,12 +1,12 @@ -import { ApiFunction } from "./server"; +import { connect } from "./client"; +import { ApiFunction, Server } from "./server"; export class Broker { constructor() {} // 订阅 - subscribe(topic: string, handler: (message: any) => void) { - const con = chrome.runtime.connect({ name: topic }); - con.postMessage({ action: "subscribe", topic }); + async subscribe(topic: string, handler: (message: any) => void) { + const con = await connect("messageQueue", { action: "subscribe", topic }); con.onMessage.addListener((msg: { action: string; topic: string; message: any }) => { if (msg.action === "message") { handler(msg.message); @@ -24,6 +24,10 @@ export class Broker { export class MessageQueue { topicConMap: Map = new Map(); + constructor(api: Server) { + api.on("messageQueue", this.handler()); + } + handler(): ApiFunction { return ({ action, topic, message }: { action: string; topic: string; message: any }, con) => { if (!con) { @@ -53,7 +57,10 @@ export class MessageQueue { } list.push({ name: topic, con }); con.onDisconnect.addListener(() => { + let list = this.topicConMap.get(topic); + // 移除断开连接的con list = list!.filter((item) => item.con !== con); + this.topicConMap.set(topic, list); }); } diff --git a/packages/message/server.ts b/packages/message/server.ts index 93b821e..78ad6c6 100644 --- a/packages/message/server.ts +++ b/packages/message/server.ts @@ -5,18 +5,22 @@ export class Server { constructor(private env: string) { chrome.runtime.onConnect.addListener((port) => { - const handler = (msg: { action: string }) => { + const handler = (msg: { action: string; data: any }) => { port.onMessage.removeListener(handler); - this.connectHandle(msg.action, msg, port); + this.connectHandle(msg.action, msg.data, port); }; port.onMessage.addListener(handler); }); chrome.runtime.onMessage.addListener((msg, sender, sendResponse) => { - this.messageHandle(msg.action, msg, sender, sendResponse); + this.messageHandle(msg.action, msg.data, sender, sendResponse); }); } + group(name: string) { + return new Group(this, name); + } + on(name: string, func: ApiFunction) { this.apiFunctionMap.set(name, func); } @@ -45,3 +49,22 @@ export class Server { } } } + +export class Group { + constructor( + private server: Server, + private name: string + ) { + if (!name.endsWith("/")) { + this.name += "/"; + } + } + + group(name: string) { + return new Group(this.server, `${this.name}${name}`); + } + + on(name: string, func: ApiFunction) { + this.server.on(`${this.name}${name}`, func); + } +} diff --git a/rspack.config.ts b/rspack.config.ts index d1fe169..4a8b5ad 100644 --- a/rspack.config.ts +++ b/rspack.config.ts @@ -28,6 +28,7 @@ export default defineConfig({ sandbox: `${src}/sandbox.ts`, popup: `${src}/pages/popup/main.tsx`, install: `${src}/pages/install/main.tsx`, + options: `${src}/pages/options/main.tsx`, }, output: { path: `${dist}/ext/src`, @@ -130,12 +131,20 @@ export default defineConfig({ }), new rspack.HtmlRspackPlugin({ filename: `${dist}/ext/src/install.html`, - template: `${src}/pages/install/index.html`, + template: `${src}/pages/template.html`, inject: "head", title: "Install - ScriptCat", minify: true, chunks: ["install"], }), + new rspack.HtmlRspackPlugin({ + filename: `${dist}/ext/src/options.html`, + template: `${src}/pages/template.html`, + inject: "head", + title: "Home - ScriptCat", + minify: true, + chunks: ["options"], + }), new rspack.HtmlRspackPlugin({ filename: `${dist}/ext/src/popup.html`, template: `${src}/pages/popup/index.html`, diff --git a/src/app/cache_key.ts b/src/app/cache_key.ts index 844eba1..d4d4191 100644 --- a/src/app/cache_key.ts +++ b/src/app/cache_key.ts @@ -1,43 +1,6 @@ -// 缓存key,所有缓存相关的key都需要定义在此 -// 使用装饰器维护缓存值 -import { ConfirmParam } from "@App/runtime/background/permission_verify"; - export default class CacheKey { - // 缓存触发器 - static Trigger(): (target: unknown, propertyName: string, descriptor: PropertyDescriptor) => void { - return (target, propertyName, descriptor) => { - descriptor.value(); - }; - } - - // 脚本缓存 - static script(id: number): string { - return `script:${id.toString()}`; - } - - // 加载脚本信息时的缓存,已处理删除 - static scriptInfo(uuid: string): string { + // 加载脚本信息时的缓存 + static scriptInstallInfo(uuid: string): string { return `scriptInfo:${uuid}`; } - - // 脚本资源url缓存,可能存在泄漏 - static resourceByUrl(url: string): string { - return `resource:${url}`; - } - - // 脚本value缓存,可能存在泄漏 - static scriptValue(id: number, storagename?: string[]): string { - if (storagename) { - return `value:storagename:${storagename[0]}`; - } - return `value:id:${id.toString()}`; - } - - static permissionConfirm(scriptId: number, confirm: ConfirmParam): string { - return `permission:${scriptId.toString()}:${confirm.permissionValue || ""}:${confirm.permission || ""}`; - } - - static importInfo(uuid: string): string { - return `import:${uuid}`; - } } diff --git a/src/app/logger/core.ts b/src/app/logger/core.ts index 6b8f5ed..9c2f14d 100644 --- a/src/app/logger/core.ts +++ b/src/app/logger/core.ts @@ -1,4 +1,3 @@ -import EventEmitter from "eventemitter3"; import Logger from "./logger"; export type LogLevel = "debug" | "info" | "warn" | "error"; @@ -20,7 +19,7 @@ export default class LoggerCore { return LoggerCore.instance; } - static getLogger(...label: LogLabel[]) { + static logger(...label: LogLabel[]) { return LoggerCore.getInstance().logger(...label); } @@ -45,6 +44,4 @@ export default class LoggerCore { logger(...label: LogLabel[]) { return new Logger(this, this.labels, ...label); } - - static EE = new EventEmitter(); } diff --git a/src/app/logger/logger.ts b/src/app/logger/logger.ts index 0430d4d..7ad471b 100644 --- a/src/app/logger/logger.ts +++ b/src/app/logger/logger.ts @@ -1,4 +1,3 @@ -/* eslint-disable no-console */ import dayjs from "dayjs"; import LoggerCore, { LogLabel, LogLevel } from "./core"; @@ -54,7 +53,6 @@ export default class Logger { break; } } - LoggerCore.EE.emit("log", { level, message, label }); } with(...label: LogLabel[]) { diff --git a/src/app/migrate.ts b/src/app/migrate.ts index e72569c..ffd1a30 100644 --- a/src/app/migrate.ts +++ b/src/app/migrate.ts @@ -32,6 +32,10 @@ function renameField(): void { // export是0.10.x时的兼容性处理 export: "++id,&scriptId", }); + // 将脚本数据迁移到chrome.storage + // db.version(18) + // .stores({}) + // .upgrade((tx) => {}); } export default function migrate() { diff --git a/src/app/repo/repo.ts b/src/app/repo/repo.ts new file mode 100644 index 0000000..2e5e3f3 --- /dev/null +++ b/src/app/repo/repo.ts @@ -0,0 +1,58 @@ +export abstract class Repo { + constructor(private prefix: string) { + if (!prefix.endsWith(":")) { + prefix += ":"; + } + } + + private joinKey(key: string) { + return this.prefix + key; + } + + public async _save(key: string, val: T) { + return new Promise((resolve) => { + const data = { + [this.joinKey(key)]: val, + }; + chrome.storage.local.set(data, () => { + resolve(val); + }); + }); + } + + public get(key: string): Promise { + return new Promise((resolve) => { + key = this.joinKey(key); + chrome.storage.local.get(key, (result) => { + resolve(result[key]); + }); + }); + } + + public find(filters?: (key: string, value: T) => boolean): Promise { + return new Promise((resolve) => { + chrome.storage.local.get((result) => { + const ret = []; + for (const key in result) { + if (key.startsWith(this.prefix) && (!filters || filters(key, result[key]))) { + ret.push(result[key]); + } + } + resolve(ret); + }); + }); + } + + findOne(filters?: (key: string, value: T) => boolean): Promise { + return new Promise((resolve) => { + chrome.storage.local.get((result) => { + for (const key in result) { + if (key.startsWith(this.prefix) && (!filters || filters(key, result[key]))) { + return resolve(result[key]); + } + } + resolve(undefined); + }); + }); + } +} diff --git a/src/app/repo/scripts.ts b/src/app/repo/scripts.ts index 5776870..c57bc4e 100644 --- a/src/app/repo/scripts.ts +++ b/src/app/repo/scripts.ts @@ -1,4 +1,4 @@ -import { DAO, db } from "./dao"; +import { Repo } from "./repo"; import { Resource } from "./resource"; import { Value } from "./value"; @@ -26,14 +26,7 @@ export const SCRIPT_RUN_STATUS_RETRY: SCRIPT_RUN_STATUS = "retry"; export type Metadata = { [key: string]: string[] }; -export type ConfigType = - | "text" - | "checkbox" - | "select" - | "mult-select" - | "number" - | "textarea" - | "time"; +export type ConfigType = "text" | "checkbox" | "select" | "mult-select" | "number" | "textarea" | "time"; export interface Config { [key: string]: any; @@ -88,34 +81,40 @@ export interface ScriptRunResouce extends Script { sourceCode: string; } -export class ScriptDAO extends DAO