From f5ec7a4b44b902a6c519c0fffaeea56e7750dac0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=8E=8B=E4=B8=80=E4=B9=8B?= Date: Wed, 16 Nov 2022 23:15:33 +0800 Subject: [PATCH] =?UTF-8?q?=E2=99=BB=EF=B8=8F=20=E9=87=8D=E6=9E=84vscode?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/service/script/event.ts | 7 +- src/app/service/script/manager.ts | 5 +- src/app/service/subscribe/manager.ts | 3 + src/app/service/system/controller.ts | 17 ++++ src/app/service/system/manager.ts | 77 +++++++++++++++++++ src/pages/options/routes/Setting.tsx | 27 ++++++- src/pages/options/routes/Tools.tsx | 63 ++++++++++++++- .../options/routes/script/ScriptEditor.tsx | 14 +++- src/pkg/utils/script.ts | 18 +++-- 9 files changed, 214 insertions(+), 17 deletions(-) create mode 100644 src/app/service/system/controller.ts diff --git a/src/app/service/script/event.ts b/src/app/service/script/event.ts index fb4c10e5..4283e06b 100644 --- a/src/app/service/script/event.ts +++ b/src/app/service/script/event.ts @@ -8,7 +8,7 @@ import { SCRIPT_STATUS_ENABLE, ScriptDAO, } from "../../repo/scripts"; -import ScriptManager from "./manager"; +import ScriptManager, { InstallSource } from "./manager"; export type ScriptEvent = | "upsert" @@ -49,10 +49,7 @@ export default class ScriptEventListener { // 安装或者更新脚本,将数据保存到数据库 @ListenEventDecorator("upsert") - public upsertHandler( - script: Script, - upsertBy: "user" | "system" | "sync" = "user" - ) { + public upsertHandler(script: Script, upsertBy: InstallSource = "user") { return new Promise((resolve, reject) => { const logger = this.logger.with({ scriptId: script.id, diff --git a/src/app/service/script/manager.ts b/src/app/service/script/manager.ts index 088a0ada..4fcb049f 100644 --- a/src/app/service/script/manager.ts +++ b/src/app/service/script/manager.ts @@ -12,7 +12,7 @@ import { Script, SCRIPT_STATUS_DISABLE, ScriptDAO } from "../../repo/scripts"; import ScriptEventListener from "./event"; import Hook from "../hook"; -export type InstallSource = "user" | "system" | "sync" | "subscribe"; +export type InstallSource = "user" | "system" | "sync" | "subscribe" | "vscode"; // 脚本管理器,负责脚本实际的安装、卸载、更新等操作 @IoC.Singleton(MessageHander, SystemConfig) @@ -52,6 +52,9 @@ export class ScriptManager extends Manager { // 启动脚本检查更新 // 十分钟对符合要求的脚本进行检查更新 setInterval(() => { + if (!this.systemConfig.checkScriptUpdateCycle) { + return; + } this.logger.debug("start check update"); this.scriptDAO.table .where("checktime") diff --git a/src/app/service/subscribe/manager.ts b/src/app/service/subscribe/manager.ts index d862ab4b..2d1b88e3 100644 --- a/src/app/service/subscribe/manager.ts +++ b/src/app/service/subscribe/manager.ts @@ -58,6 +58,9 @@ export default class SubscribeManager extends Manager { // 启动订阅检查更新 // 十分钟对符合要求的订阅进行检查更新 setInterval(() => { + if (!this.systemConfig.checkScriptUpdateCycle) { + return; + } this.logger.debug("start check update"); this.subscribeDAO.table .where("checktime") diff --git a/src/app/service/system/controller.ts b/src/app/service/system/controller.ts new file mode 100644 index 00000000..387dd09a --- /dev/null +++ b/src/app/service/system/controller.ts @@ -0,0 +1,17 @@ +import IoC from "@App/app/ioc"; +import MessageInternal from "@App/app/message/internal"; +import Controller from "../controller"; + +@IoC.Singleton(MessageInternal) +export default class SystemController extends Controller { + internal: MessageInternal; + + constructor(internal: MessageInternal) { + super(internal, "system"); + this.internal = internal; + } + + connectVSCode() { + return this.dispatchEvent("connectVSCode", {}); + } +} diff --git a/src/app/service/system/manager.ts b/src/app/service/system/manager.ts index 392065b8..d35f42cc 100644 --- a/src/app/service/system/manager.ts +++ b/src/app/service/system/manager.ts @@ -1,10 +1,13 @@ import { ExternalMessage, ExtVersion, ExtServer } from "@App/app/const"; import IoC from "@App/app/ioc"; +import { v5 as uuidv5 } from "uuid"; import { MessageHander } from "@App/app/message/message"; import { ScriptDAO } from "@App/app/repo/scripts"; import { SystemConfig } from "@App/pkg/config/config"; +import { prepareScriptByCode } from "@App/pkg/utils/script"; import semver from "semver"; import Manager from "../manager"; +import ScriptManager from "../script/manager"; // value管理器,负责value等更新获取等操作 @IoC.Singleton(MessageHander, SystemConfig) @@ -13,10 +16,15 @@ export class SystemManager extends Manager { scriptDAO: ScriptDAO; + scriptManager: ScriptManager; + + wsVscode?: WebSocket; + constructor(message: MessageHander, systemConfig: SystemConfig) { super(message, "system"); this.scriptDAO = new ScriptDAO(); this.systemConfig = systemConfig; + this.scriptManager = IoC.instance(ScriptManager) as ScriptManager; } init() { @@ -92,6 +100,75 @@ export class SystemManager extends Manager { return Promise.resolve(false); } ); + this.listenEvent("connectVSCode", this.connectVSCode.bind(this)); + + this.reconnectVSCode(); + } + + reconnectVSCode() { + let connectVSCodeTimer: any; + const handler = () => { + if (!this.wsVscode) { + this.connectVSCode(); + } + }; + if (this.systemConfig.vscodeReconnect) { + connectVSCodeTimer = setInterval(() => { + handler(); + }, 30 * 1000); + } + + SystemConfig.hook.addListener("update", (key, val) => { + if (key === "vscodeReconnect") { + if (val) { + connectVSCodeTimer = setInterval(() => { + handler(); + }, 30 * 1000); + } else { + clearInterval(connectVSCodeTimer); + } + } + }); + } + + connectVSCode() { + return new Promise((resolve, reject) => { + // 与vsc扩展建立连接 + if (this.wsVscode) { + this.wsVscode.close(); + } + try { + this.wsVscode = new WebSocket(this.systemConfig.vscodeUrl); + } catch (e: any) { + reject(e); + return; + } + this.wsVscode.addEventListener("open", () => { + this.wsVscode!.send('{"action":"hello"}'); + resolve(); + }); + this.wsVscode.addEventListener("message", async (ev) => { + const data = JSON.parse(ev.data); + switch (data.action) { + case "onchange": { + const code = data.data.script; + const script = await prepareScriptByCode( + code, + "", + uuidv5(code.data.uri, uuidv5.URL) + ); + this.scriptManager.event.upsertHandler(script, "vscode"); + break; + } + default: + } + }); + + this.wsVscode.addEventListener("error", () => { + reject(new Error("VSCode连接失败")); + this.wsVscode = undefined; + }); + }); } getNotice(): Promise<{ notice: string; isRead: boolean }> { diff --git a/src/pages/options/routes/Setting.tsx b/src/pages/options/routes/Setting.tsx index c58b0e33..f943af5b 100644 --- a/src/pages/options/routes/Setting.tsx +++ b/src/pages/options/routes/Setting.tsx @@ -1,5 +1,12 @@ import React, { useState } from "react"; -import { Button, Card, Checkbox, Message, Space } from "@arco-design/web-react"; +import { + Button, + Card, + Checkbox, + Message, + Select, + Space, +} from "@arco-design/web-react"; import FileSystemParams from "@App/pages/components/FileSystemParams"; import { SystemConfig } from "@App/pkg/config/config"; import IoC from "@App/app/ioc"; @@ -94,6 +101,24 @@ function Setting() { + + 脚本/订阅检查更新间隔: + + { systemConfig.updateDisableScript = checked; diff --git a/src/pages/options/routes/Tools.tsx b/src/pages/options/routes/Tools.tsx index 369d4f58..a7e01a02 100644 --- a/src/pages/options/routes/Tools.tsx +++ b/src/pages/options/routes/Tools.tsx @@ -2,6 +2,7 @@ import React, { useRef, useState } from "react"; import { Button, Card, + Checkbox, Drawer, Empty, Input, @@ -18,6 +19,9 @@ import { SystemConfig } from "@App/pkg/config/config"; import { File, FileReader } from "@Pkg/filesystem/filesystem"; import { formatUnixTime } from "@App/pkg/utils/utils"; import FileSystemParams from "@App/pages/components/FileSystemParams"; +import { IconQuestionCircleFill } from "@arco-design/web-react/icon"; +import { RefInputType } from "@arco-design/web-react/es/Input/interface"; +import SystemController from "@App/app/service/system/controller"; function Tools() { const [loading, setLoading] = useState<{ [key: string]: boolean }>({}); @@ -32,6 +36,8 @@ function Tools() { }>(systemConfig.backup.params[fileSystemType] || {}); const [backupFileList, setBackupFileList] = useState([]); + const vscodeRef = useRef(null); + return ( - + + 开发调试 + diff --git a/src/pages/options/routes/script/ScriptEditor.tsx b/src/pages/options/routes/script/ScriptEditor.tsx index 9561e368..dda6443e 100644 --- a/src/pages/options/routes/script/ScriptEditor.tsx +++ b/src/pages/options/routes/script/ScriptEditor.tsx @@ -647,7 +647,7 @@ function ScriptEditor() { ))}
- {editors.map((item, index) => { + {editors.map((item) => { // 先这样吧 setTimeout(() => { if (item.active && item.editor) { @@ -668,7 +668,11 @@ function ScriptEditor() { hotKeys={item.hotKeys} callbackEditor={(e) => { setEditors((prev) => { - prev[index].editor = e; + prev.forEach((v) => { + if (v.script.uuid === item.script.uuid) { + v.editor = e; + } + }); return [...prev]; }); }} @@ -676,7 +680,11 @@ function ScriptEditor() { const isChanged = !(item.code === code); if (isChanged !== item.isChanged) { setEditors((prev) => { - prev[index].isChanged = isChanged; + prev.forEach((v) => { + if (v.script.id === item.script.id) { + v.isChanged = isChanged; + } + }); return [...prev]; }); } diff --git a/src/pkg/utils/script.ts b/src/pkg/utils/script.ts index c52b6acf..3f7f6173 100644 --- a/src/pkg/utils/script.ts +++ b/src/pkg/utils/script.ts @@ -129,7 +129,7 @@ export async function fetchScriptInfo( export function copyScript(script: Script, old: Script): Script { const ret = script; ret.id = old.id; - ret.uuid = old.uuid; + // ret.uuid = old.uuid; ret.createtime = old.createtime; ret.lastruntime = old.lastruntime; // ret.delayruntime = old.delayruntime; @@ -247,11 +247,16 @@ export function prepareScriptByCode( [, domain] = urlSplit; } } - // N1-MTIwLjIyOC4wLjE4ODoxNjY4NTIyOTgyOjQ3OTYzNDc5NTMxMzQ1MzM0OQ== - // N1-MTIwLjIyOC4wLjE4ODoxNjY4NTIyOTgyOjQ3OTYzNDc5NTMxMzQ1MzM0OQ== + if (!uuid) { + if (url) { + uuid = uuidv5(url, uuidv5.URL); + } else { + uuid = uuidv4(); + } + } let script: Script & { oldScript?: Script } = { id: 0, - uuid: uuid || uuidv4(), + uuid, name: metadata.name[0], code, author: metadata.author && metadata.author[0], @@ -273,8 +278,11 @@ export function prepareScriptByCode( }; const handler = async () => { let old: Script | undefined; - if (uuid !== undefined) { + if (uuid) { old = await dao.findByUUID(uuid); + if (!old && url) { + old = await dao.findByNameAndNamespace(script.name, script.namespace); + } } else { old = await dao.findByNameAndNamespace(script.name, script.namespace); if (!old) {