-
Notifications
You must be signed in to change notification settings - Fork 307
[v1.3?] VSCodeConnect 代码优化 #947
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: release/v1.3
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,103 +1,150 @@ | ||
| import LoggerCore from "@App/app/logger/core"; | ||
| import Logger from "@App/app/logger/logger"; | ||
| import { type Group } from "@Packages/message/server"; | ||
| import type { Server, Group } from "@Packages/message/server"; | ||
| import type { MessageSend } from "@Packages/message/types"; | ||
| import { ScriptClient } from "../service_worker/client"; | ||
| import { v5 as uuidv5 } from "uuid"; | ||
|
|
||
| /* ---------- Types ---------- */ | ||
| export type VSCodeConnectParam = { url: string; reconnect: boolean }; | ||
|
|
||
| /** Actions received from VSCode WebSocket */ | ||
| enum VSCodeAction { | ||
| Hello = "hello", | ||
| OnChange = "onchange", | ||
| } | ||
|
|
||
| /* ---------- Main Class ---------- */ | ||
| // 在offscreen下与scriptcat-vscode建立websocket连接 | ||
| // 需要在vscode中安装scriptcat-vscode插件 | ||
| export class VSCodeConnect { | ||
| logger: Logger = LoggerCore.logger().with({ service: "VSCodeConnect" }); | ||
| private readonly logger: Logger = LoggerCore.logger().with({ service: "VSCodeConnect" }); | ||
|
|
||
| reconnect: boolean = false; | ||
| private ws: WebSocket | undefined; | ||
|
|
||
| wsConnect: WebSocket | undefined; | ||
| private timerId: number | NodeJS.Timeout | undefined; | ||
|
|
||
| connectVSCodeTimer: any; | ||
| private readonly scriptClient: ScriptClient; | ||
|
|
||
| scriptClient: ScriptClient; | ||
| private readonly vscodeConnectGroup: Group; | ||
|
|
||
| constructor( | ||
| private group: Group, | ||
| private msgSender: MessageSend | ||
| ) { | ||
| this.scriptClient = new ScriptClient(this.msgSender); | ||
| constructor(windowServer: Server, msgSender: MessageSend) { | ||
| this.vscodeConnectGroup = windowServer.group("vscodeConnect"); | ||
| this.scriptClient = new ScriptClient(msgSender); | ||
|
Comment on lines
+31
to
+33
|
||
| } | ||
|
|
||
| connect({ url, reconnect }: { url: string; reconnect: boolean }) { | ||
| // 如果已经连接,断开重连 | ||
| if (this.wsConnect) { | ||
| this.wsConnect.close(); | ||
| } | ||
| // 清理老的定时器 | ||
| if (this.connectVSCodeTimer) { | ||
| clearInterval(this.connectVSCodeTimer); | ||
| this.connectVSCodeTimer = undefined; | ||
| } | ||
| const handler = () => { | ||
| if (!this.wsConnect) { | ||
| return this.connectVSCode({ url }); | ||
| } | ||
| return Promise.resolve(); | ||
| }; | ||
| if (reconnect) { | ||
| this.connectVSCodeTimer = setInterval(() => { | ||
| handler(); | ||
| }, 30 * 1000); | ||
| } | ||
| return handler(); | ||
| init() { | ||
| this.vscodeConnectGroup.on("connect", (param: VSCodeConnectParam) => this.connect(param)); | ||
| } | ||
|
|
||
| // 连接到vscode | ||
| connectVSCode({ url }: { url: string }) { | ||
| return new Promise<void>((resolve, reject) => { | ||
| /* ---------- Public API ---------- */ | ||
| /** 启动(或重新启动)与 VSCode 的连接 */ | ||
| public connect({ url, reconnect }: VSCodeConnectParam): Promise<void> { | ||
| const doReconnect = () => { | ||
| // 如果已经连接,断开重连 | ||
| if (this.wsConnect) { | ||
| this.wsConnect.close(); | ||
| } | ||
| try { | ||
| this.wsConnect = new WebSocket(url); | ||
| } catch (e: any) { | ||
| this.logger.debug("connect vscode faild", Logger.E(e)); | ||
| reject(e); | ||
| return; | ||
| } | ||
| let ok = false; | ||
| this.wsConnect.addEventListener("open", () => { | ||
| this.wsConnect!.send('{"action":"hello"}'); | ||
| ok = true; | ||
| resolve(); | ||
| }); | ||
| this.wsConnect.addEventListener("message", async (ev) => { | ||
| const data = JSON.parse(ev.data); | ||
| switch (data.action) { | ||
| case "onchange": { | ||
| // 调用安装脚本接口 | ||
| const code = data.data.script; | ||
| this.scriptClient.installByCode(uuidv5(data.data.uri, uuidv5.URL), code, "vscode"); | ||
| break; | ||
| } | ||
| default: | ||
| this.closeExisting(); | ||
| this.clearTimer(); | ||
| this.timerId = setTimeout(connectVSCode, 100); | ||
|
||
| }; | ||
|
Comment on lines
+43
to
+48
|
||
| const connectVSCode = () => { | ||
| if (this.ws) return; // 已连接则忽略 | ||
|
Comment on lines
+49
to
+50
|
||
| return new Promise<void>((resolve, reject) => { | ||
| let ws; | ||
| try { | ||
| ws = new WebSocket(url); | ||
| } catch (e: any) { | ||
| this.logger.debug("connect vscode faild", Logger.E(e)); | ||
|
||
| reject(e); | ||
| return; | ||
| } | ||
| }); | ||
| let connectOK = false; | ||
| ws.addEventListener("open", () => { | ||
| ws.send('{"action":"hello"}'); | ||
| connectOK = true; | ||
| // 如重复连接,则清除之前的 | ||
| if (this.ws) { | ||
| this.closeExisting(); | ||
| } | ||
| this.ws = ws; | ||
|
Comment on lines
+64
to
+68
|
||
| resolve(); | ||
| this.clearTimer(); | ||
| }); | ||
| ws.addEventListener("message", (ev) => { | ||
| this.handleMessage(ev).catch((err) => { | ||
| this.logger.error("message handler error", Logger.E(err)); | ||
| }); | ||
| }); | ||
|
|
||
| this.wsConnect.addEventListener("error", (e) => { | ||
| this.wsConnect = undefined; | ||
| this.logger.debug("connect vscode faild", Logger.E(e)); | ||
| if (!ok) { | ||
| reject(new Error("connect fail")); | ||
| } | ||
| }); | ||
| ws.addEventListener("error", (e) => { | ||
| this.ws = undefined; | ||
| this.logger.debug("connect vscode faild", Logger.E(e)); | ||
|
||
| if (!connectOK) { | ||
| reject(new Error("connect fail")); | ||
| } | ||
| if (reconnect) doReconnect(); | ||
| }); | ||
|
|
||
| this.wsConnect.addEventListener("close", () => { | ||
| this.wsConnect = undefined; | ||
| this.logger.debug("vscode connection closed"); | ||
| ws.addEventListener("close", () => { | ||
| this.ws = undefined; | ||
| this.logger.debug("vscode connection closed"); | ||
| if (reconnect) doReconnect(); | ||
|
Comment on lines
+84
to
+90
|
||
| }); | ||
| // 如 open, close, error 都不发生,30 秒后reject | ||
| this.clearTimer(); | ||
| this.timerId = setTimeout(() => { | ||
| if (!connectOK) { | ||
| reject(new Error("Timeout")); | ||
| try { | ||
| ws.close(); | ||
| } catch (e) { | ||
| console.error(e); | ||
|
||
| } | ||
| if (reconnect) doReconnect(); | ||
|
||
| } | ||
| }, 30_000); | ||
| }); | ||
| }); | ||
| }; | ||
| // 如果已经连接,断开重连 | ||
| this.closeExisting(); | ||
| // 清理老的定时器 | ||
| this.clearTimer(); | ||
| return Promise.resolve().then(() => connectVSCode()); | ||
|
Comment on lines
+49
to
+111
|
||
| } | ||
|
|
||
| init() { | ||
| this.group.on("connect", this.connect.bind(this)); | ||
| /* ---------- Message Handling ---------- */ | ||
| private async handleMessage(ev: MessageEvent): Promise<void> { | ||
| let data: any; | ||
| try { | ||
| data = JSON.parse(ev.data as string); | ||
| } catch { | ||
| return; // ignore malformed JSON | ||
| } | ||
| switch (data.action as VSCodeAction) { | ||
| case VSCodeAction.OnChange: { | ||
| // 调用安装脚本接口 | ||
| const { script, uri } = data.data; | ||
| const id = uuidv5(uri, uuidv5.URL); | ||
| await this.scriptClient.installByCode(id, script, "vscode"); | ||
| break; | ||
| } | ||
| default: | ||
| // ignore unknown actions | ||
| } | ||
| } | ||
|
|
||
| /* ---------- Helpers ---------- */ | ||
| private closeExisting(): void { | ||
| try { | ||
| this.ws?.close(); | ||
| } catch (e: any) { | ||
| console.error(e); | ||
|
||
| } | ||
| this.ws = undefined; | ||
| } | ||
| private clearTimer(): void { | ||
| if (this.timerId) { | ||
| clearTimeout(this.timerId); | ||
|
||
| this.timerId = undefined; | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
变量命名不一致:在 index.ts 中使用了 camelCase 的
vsCodeConnect(小写 s),但在类型和其他地方都使用VSCode(大写 VS)。为了保持一致性,建议使用vscodeConnect(全小写)或vsCodeConnect,但要在整个项目中保持统一。参考项目中其他地方的命名(如 VscodeConnectClient),应该使用vscodeConnect。