Skip to content

Commit a849db0

Browse files
committed
VSCodeConnect 代码优化
1 parent 1134586 commit a849db0

4 files changed

Lines changed: 124 additions & 80 deletions

File tree

src/app/service/offscreen/client.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { type WindowMessage } from "@Packages/message/window_message";
22
import type { SCRIPT_RUN_STATUS, ScriptRunResource } from "@App/app/repo/scripts";
33
import { Client, sendMessage } from "@Packages/message/client";
44
import type { MessageSend } from "@Packages/message/types";
5-
import { type VSCodeConnect } from "./vscode-connect";
5+
import type { VSCodeConnectParam } from "./vscode-connect";
66

77
export function preparationSandbox(windowMessage: WindowMessage) {
88
return sendMessage(windowMessage, "offscreen/preparationSandbox");
@@ -42,7 +42,7 @@ export class VscodeConnectClient extends Client {
4242
super(msgSender, "offscreen/vscodeConnect");
4343
}
4444

45-
connect(params: Parameters<VSCodeConnect["connect"]>[0]): ReturnType<VSCodeConnect["connect"]> {
45+
connect(params: VSCodeConnectParam): Promise<void> {
4646
return this.do("connect", params);
4747
}
4848
}

src/app/service/offscreen/index.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,8 +58,8 @@ export class OffscreenManager {
5858

5959
const gmApi = new GMApi(this.windowServer.group("gmApi"));
6060
gmApi.init();
61-
const vscodeConnect = new VSCodeConnect(this.windowServer.group("vscodeConnect"), this.extMsgSender);
62-
vscodeConnect.init();
61+
const vscodeConnectServer = this.windowServer.group("vscodeConnect");
62+
new VSCodeConnect(vscodeConnectServer, this.extMsgSender);
6363

6464
this.windowServer.on("createObjectURL", async (params: { data: Blob; persistence: boolean }) => {
6565
const url = URL.createObjectURL(params.data);

src/app/service/offscreen/vscode-connect.ts

Lines changed: 118 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -5,99 +5,143 @@ import type { MessageSend } from "@Packages/message/types";
55
import { ScriptClient } from "../service_worker/client";
66
import { v5 as uuidv5 } from "uuid";
77

8+
/* ---------- Types ---------- */
9+
export type VSCodeConnectParam = { url: string; reconnect: boolean };
10+
11+
/** Actions received from VSCode WebSocket */
12+
enum VSCodeAction {
13+
Hello = "hello",
14+
OnChange = "onchange",
15+
}
16+
17+
/* ---------- Main Class ---------- */
818
// 在offscreen下与scriptcat-vscode建立websocket连接
919
// 需要在vscode中安装scriptcat-vscode插件
1020
export class VSCodeConnect {
11-
logger: Logger = LoggerCore.logger().with({ service: "VSCodeConnect" });
21+
private readonly logger: Logger = LoggerCore.logger().with({ service: "VSCodeConnect" });
1222

13-
reconnect: boolean = false;
23+
private ws: WebSocket | undefined;
1424

15-
wsConnect: WebSocket | undefined;
25+
private timerId: number | NodeJS.Timeout | undefined;
1626

17-
connectVSCodeTimer: any;
18-
19-
scriptClient: ScriptClient;
27+
private readonly scriptClient: ScriptClient;
2028

2129
constructor(
22-
private group: Group,
23-
private msgSender: MessageSend
30+
vscodeConnectServer: Group,
31+
private readonly msgSender: MessageSend
2432
) {
2533
this.scriptClient = new ScriptClient(this.msgSender);
34+
vscodeConnectServer.on("connect", (param: VSCodeConnectParam) => this.connect(param));
2635
}
2736

28-
connect({ url, reconnect }: { url: string; reconnect: boolean }) {
29-
// 如果已经连接,断开重连
30-
if (this.wsConnect) {
31-
this.wsConnect.close();
32-
}
33-
// 清理老的定时器
34-
if (this.connectVSCodeTimer) {
35-
clearInterval(this.connectVSCodeTimer);
36-
this.connectVSCodeTimer = undefined;
37-
}
38-
const handler = () => {
39-
if (!this.wsConnect) {
40-
return this.connectVSCode({ url });
41-
}
42-
return Promise.resolve();
37+
/* ---------- Public API ---------- */
38+
/** 启动(或重新启动)与 VSCode 的连接 */
39+
public connect({ url, reconnect }: VSCodeConnectParam): Promise<void> {
40+
const doReconnect = () => {
41+
// 如果已经连接,断开重连
42+
this.closeExisting();
43+
this.clearTimer();
44+
this.timerId = setTimeout(connectVSCode, 100);
4345
};
44-
if (reconnect) {
45-
this.connectVSCodeTimer = setInterval(() => {
46-
handler();
47-
}, 30 * 1000);
48-
}
49-
return handler();
50-
}
46+
const connectVSCode = () => {
47+
if (this.ws) return; // 已连接则忽略
48+
return new Promise<void>((resolve, reject) => {
49+
let ws;
50+
try {
51+
ws = new WebSocket(url);
52+
} catch (e: any) {
53+
this.logger.debug("connect vscode faild", Logger.E(e));
54+
reject(e);
55+
return;
56+
}
57+
let connectOK = false;
58+
ws.addEventListener("open", () => {
59+
ws.send('{"action":"hello"}');
60+
connectOK = true;
61+
// 如重复连接,则清除之前的
62+
if (this.ws) {
63+
this.closeExisting();
64+
}
65+
this.ws = ws;
66+
resolve();
67+
this.clearTimer();
68+
});
69+
ws.addEventListener("message", (ev) => {
70+
this.handleMessage(ev).catch((err) => {
71+
this.logger.error("message handler error", Logger.E(err));
72+
});
73+
});
5174

52-
// 连接到vscode
53-
connectVSCode({ url }: { url: string }) {
54-
return new Promise<void>((resolve, reject) => {
55-
// 如果已经连接,断开重连
56-
if (this.wsConnect) {
57-
this.wsConnect.close();
58-
}
59-
try {
60-
this.wsConnect = new WebSocket(url);
61-
} catch (e: any) {
62-
this.logger.debug("connect vscode faild", Logger.E(e));
63-
reject(e);
64-
return;
65-
}
66-
let ok = false;
67-
this.wsConnect.addEventListener("open", () => {
68-
this.wsConnect!.send('{"action":"hello"}');
69-
ok = true;
70-
resolve();
71-
});
72-
this.wsConnect.addEventListener("message", async (ev) => {
73-
const data = JSON.parse(ev.data);
74-
switch (data.action) {
75-
case "onchange": {
76-
// 调用安装脚本接口
77-
const code = data.data.script;
78-
this.scriptClient.installByCode(uuidv5(data.data.uri, uuidv5.URL), code, "vscode");
79-
break;
75+
ws.addEventListener("error", (e) => {
76+
this.ws = undefined;
77+
this.logger.debug("connect vscode faild", Logger.E(e));
78+
if (!connectOK) {
79+
reject(new Error("connect fail"));
8080
}
81-
default:
82-
}
83-
});
81+
if (reconnect) doReconnect();
82+
});
8483

85-
this.wsConnect.addEventListener("error", (e) => {
86-
this.wsConnect = undefined;
87-
this.logger.debug("connect vscode faild", Logger.E(e));
88-
if (!ok) {
89-
reject(new Error("connect fail"));
90-
}
84+
ws.addEventListener("close", () => {
85+
this.ws = undefined;
86+
this.logger.debug("vscode connection closed");
87+
if (reconnect) doReconnect();
88+
});
89+
// 如 open, close, error 都不发生,30 秒后reject
90+
this.clearTimer();
91+
this.timerId = setTimeout(() => {
92+
if (!connectOK) {
93+
reject(new Error("Timeout"));
94+
try {
95+
ws.close();
96+
} catch (e) {
97+
console.error(e);
98+
}
99+
if (reconnect) doReconnect();
100+
}
101+
}, 30_000);
91102
});
103+
};
104+
// 如果已经连接,断开重连
105+
this.closeExisting();
106+
// 清理老的定时器
107+
this.clearTimer();
108+
return Promise.resolve().then(() => connectVSCode());
109+
}
92110

93-
this.wsConnect.addEventListener("close", () => {
94-
this.wsConnect = undefined;
95-
this.logger.debug("vscode connection closed");
96-
});
97-
});
111+
/* ---------- Message Handling ---------- */
112+
private async handleMessage(ev: MessageEvent): Promise<void> {
113+
let data: any;
114+
try {
115+
data = JSON.parse(ev.data as string);
116+
} catch {
117+
return; // ignore malformed JSON
118+
}
119+
switch (data.action as VSCodeAction) {
120+
case VSCodeAction.OnChange: {
121+
// 调用安装脚本接口
122+
const { script, uri } = data.data;
123+
const id = uuidv5(uri, uuidv5.URL);
124+
await this.scriptClient.installByCode(id, script, "vscode");
125+
break;
126+
}
127+
default:
128+
// ignore unknown actions
129+
}
98130
}
99131

100-
init() {
101-
this.group.on("connect", this.connect.bind(this));
132+
/* ---------- Helpers ---------- */
133+
private closeExisting(): void {
134+
try {
135+
this.ws?.close();
136+
} catch (e: any) {
137+
console.error(e);
138+
}
139+
this.ws = undefined;
140+
}
141+
private clearTimer(): void {
142+
if (this.timerId) {
143+
clearTimeout(this.timerId);
144+
this.timerId = undefined;
145+
}
102146
}
103147
}

src/app/service/service_worker/client.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import { v4 as uuidv4 } from "uuid";
1212
import { cacheInstance } from "@App/app/cache";
1313
import { CACHE_KEY_IMPORT_FILE } from "@App/app/cache_key";
1414
import { type ResourceBackup } from "@App/pkg/backup/struct";
15-
import { type VSCodeConnect } from "../offscreen/vscode-connect";
15+
import type { VSCodeConnectParam, VSCodeConnect } from "../offscreen/vscode-connect";
1616
import { type SystemService } from "./system";
1717
import { type ScriptInfo } from "@App/pkg/utils/scriptInstall";
1818
import type { ScriptService, TCheckScriptUpdateOption, TOpenBatchUpdatePageOption } from "./script";
@@ -393,7 +393,7 @@ export class SystemClient extends Client {
393393
super(msgSender, "serviceWorker/system");
394394
}
395395

396-
connectVSCode(params: Parameters<VSCodeConnect["connect"]>[0]): ReturnType<VSCodeConnect["connect"]> {
396+
connectVSCode(params: VSCodeConnectParam): ReturnType<VSCodeConnect["connect"]> {
397397
return this.do("connectVSCode", params);
398398
}
399399

0 commit comments

Comments
 (0)