@xcanwin/manyoyo 7.0.25 → 7.0.26
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/web/AGENTS.md +2 -0
- package/lib/web/frontend/shadcn.html +65 -65
- package/lib/web/server.js +39 -0
- package/package.json +1 -1
package/lib/web/server.js
CHANGED
|
@@ -42,6 +42,12 @@ const WEB_TERMINAL_DEFAULT_COLS = 120;
|
|
|
42
42
|
const WEB_TERMINAL_DEFAULT_ROWS = 36;
|
|
43
43
|
const WEB_TERMINAL_MIN_COLS = 40;
|
|
44
44
|
const WEB_TERMINAL_MIN_ROWS = 12;
|
|
45
|
+
// 终端 WebSocket 空闲心跳:纯交互式终端可能长时间没有任何数据,
|
|
46
|
+
// 反向代理 / 移动网络的空闲超时(常见 60s)会悄悄掐断连接,这里定期发 ping
|
|
47
|
+
// 帧制造流量。判死放宽到连续 3 次没回 pong(约 90s),手机切后台导致连接被
|
|
48
|
+
// 系统短暂挂起时不至于被误杀——误杀意味着容器里的 shell 直接没了
|
|
49
|
+
const WEB_TERMINAL_PING_INTERVAL_MS = 30000;
|
|
50
|
+
const WEB_TERMINAL_MAX_MISSED_PONGS = 3;
|
|
45
51
|
const WEB_AGENT_CONTEXT_MAX_MESSAGES = 24;
|
|
46
52
|
const WEB_AGENT_CONTEXT_MAX_CHARS = 6000;
|
|
47
53
|
const WEB_AGENT_CONTEXT_PER_MESSAGE_MAX_CHARS = 600;
|
|
@@ -4406,11 +4412,32 @@ function bindTerminalWebSocket(ctx, state, ws, containerName, cols, rows) {
|
|
|
4406
4412
|
rows
|
|
4407
4413
|
});
|
|
4408
4414
|
|
|
4415
|
+
let missedPongs = 0;
|
|
4416
|
+
ws.on('pong', () => {
|
|
4417
|
+
missedPongs = 0;
|
|
4418
|
+
});
|
|
4419
|
+
const pingTimer = setInterval(() => {
|
|
4420
|
+
if (ws.readyState !== WebSocket.OPEN) {
|
|
4421
|
+
return;
|
|
4422
|
+
}
|
|
4423
|
+
if (missedPongs >= WEB_TERMINAL_MAX_MISSED_PONGS) {
|
|
4424
|
+
ws.terminate();
|
|
4425
|
+
return;
|
|
4426
|
+
}
|
|
4427
|
+
missedPongs += 1;
|
|
4428
|
+
try {
|
|
4429
|
+
ws.ping();
|
|
4430
|
+
} catch (e) {
|
|
4431
|
+
// ping 失败说明链路已经不可用,交给 close/error 事件收尾
|
|
4432
|
+
}
|
|
4433
|
+
}, WEB_TERMINAL_PING_INTERVAL_MS);
|
|
4434
|
+
|
|
4409
4435
|
const cleanup = () => {
|
|
4410
4436
|
if (session.closing) {
|
|
4411
4437
|
return;
|
|
4412
4438
|
}
|
|
4413
4439
|
session.closing = true;
|
|
4440
|
+
clearInterval(pingTimer);
|
|
4414
4441
|
state.terminalSessions.delete(sessionId);
|
|
4415
4442
|
if (ptyProcess && !ptyProcess.killed) {
|
|
4416
4443
|
ptyProcess.kill('SIGTERM');
|
|
@@ -4472,6 +4499,12 @@ function bindTerminalWebSocket(ctx, state, ws, containerName, cols, rows) {
|
|
|
4472
4499
|
return;
|
|
4473
4500
|
}
|
|
4474
4501
|
|
|
4502
|
+
if (payload.type === 'ping') {
|
|
4503
|
+
// 浏览器 JS 发不出 WebSocket ping 帧,前端改用应用层消息保活上行链路
|
|
4504
|
+
sendTerminalEvent(ws, 'pong');
|
|
4505
|
+
return;
|
|
4506
|
+
}
|
|
4507
|
+
|
|
4475
4508
|
if (payload.type === 'close') {
|
|
4476
4509
|
ws.close();
|
|
4477
4510
|
}
|
|
@@ -6061,6 +6094,12 @@ async function startWebServer(options) {
|
|
|
6061
6094
|
url.searchParams.get('rows')
|
|
6062
6095
|
);
|
|
6063
6096
|
|
|
6097
|
+
// 升级成 WebSocket 后这条连接是长连接,不能再受 HTTP 请求的空闲超时约束;
|
|
6098
|
+
// 同时打开 TCP keepalive,避免中间设备(NAT / 代理)回收看起来空闲的连接
|
|
6099
|
+
socket.setTimeout(0);
|
|
6100
|
+
socket.setNoDelay(true);
|
|
6101
|
+
socket.setKeepAlive(true, WEB_TERMINAL_PING_INTERVAL_MS);
|
|
6102
|
+
|
|
6064
6103
|
ensureWebContainer(ctx, state, sessionRef.containerName)
|
|
6065
6104
|
.then(() => {
|
|
6066
6105
|
wsServer.handleUpgrade(req, socket, head, ws => {
|