herdr-remote 0.2.11 → 0.2.12
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/dist/tui.mjs +1 -1
- package/herdr-plugin.toml +1 -1
- package/package.json +1 -1
- package/src/host-connector.js +61 -0
package/dist/tui.mjs
CHANGED
|
@@ -4015,7 +4015,7 @@ function About({ ctx }) {
|
|
|
4015
4015
|
children: updateLabel
|
|
4016
4016
|
}
|
|
4017
4017
|
) }),
|
|
4018
|
-
/* @__PURE__ */ jsx10(Row, { label: t("about.version"), children: /* @__PURE__ */ jsx10(Text9, { color: theme.muted, children: "0.2.
|
|
4018
|
+
/* @__PURE__ */ jsx10(Row, { label: t("about.version"), children: /* @__PURE__ */ jsx10(Text9, { color: theme.muted, children: "0.2.12" }) }),
|
|
4019
4019
|
/* @__PURE__ */ jsx10(Row, { label: t("about.configPath"), children: /* @__PURE__ */ jsx10(Text9, { color: theme.muted, children: (0, import_config.configPath)() }) }),
|
|
4020
4020
|
/* @__PURE__ */ jsx10(Row, { label: t("about.statePath"), children: /* @__PURE__ */ jsx10(Text9, { color: theme.muted, children: (0, import_config.stateDir)() }) }),
|
|
4021
4021
|
/* @__PURE__ */ jsx10(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text9, { color: theme.muted, children: t("about.docs") }) }),
|
package/herdr-plugin.toml
CHANGED
package/package.json
CHANGED
package/src/host-connector.js
CHANGED
|
@@ -36,6 +36,19 @@ function closeSocket(ws, reason = 'host connector stopping') {
|
|
|
36
36
|
try { ws.close(1000, reason); } catch {}
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
+
function terminateSocket(ws) {
|
|
40
|
+
if (!ws || ws.readyState === WebSocket.CLOSED) return;
|
|
41
|
+
try {
|
|
42
|
+
if (typeof ws.terminate === 'function') {
|
|
43
|
+
ws.terminate();
|
|
44
|
+
} else if (typeof ws.destroy === 'function') {
|
|
45
|
+
ws.destroy();
|
|
46
|
+
} else if (typeof ws.close === 'function') {
|
|
47
|
+
ws.close();
|
|
48
|
+
}
|
|
49
|
+
} catch {}
|
|
50
|
+
}
|
|
51
|
+
|
|
39
52
|
function pidAlive(pid) {
|
|
40
53
|
if (!Number.isInteger(pid) || pid <= 0) return false;
|
|
41
54
|
try {
|
|
@@ -88,6 +101,7 @@ class HostConnector {
|
|
|
88
101
|
this.fastFailures = 0;
|
|
89
102
|
this.reconnectTimer = null;
|
|
90
103
|
this.heartbeatTimer = null;
|
|
104
|
+
this.keepaliveTimer = null;
|
|
91
105
|
this.reconnectAttempts = 0;
|
|
92
106
|
this.clientCount = 0;
|
|
93
107
|
this.legacyHeartbeat = false;
|
|
@@ -154,6 +168,7 @@ class HostConnector {
|
|
|
154
168
|
this.stopping = true;
|
|
155
169
|
if (this.reconnectTimer) clearTimeout(this.reconnectTimer);
|
|
156
170
|
if (this.heartbeatTimer) clearInterval(this.heartbeatTimer);
|
|
171
|
+
this.stopKeepalive();
|
|
157
172
|
this.reconnectTimer = null;
|
|
158
173
|
this.heartbeatTimer = null;
|
|
159
174
|
sendJson(this.ws, { type: 'host_shutdown' });
|
|
@@ -168,6 +183,7 @@ class HostConnector {
|
|
|
168
183
|
|
|
169
184
|
connect() {
|
|
170
185
|
if (this.stopping || (this.ws && [WebSocket.OPEN, WebSocket.CONNECTING].includes(this.ws.readyState))) return;
|
|
186
|
+
this.stopKeepalive();
|
|
171
187
|
let ws;
|
|
172
188
|
try {
|
|
173
189
|
ws = new WebSocket(this.relayUrl);
|
|
@@ -208,6 +224,7 @@ class HostConnector {
|
|
|
208
224
|
this.ws = null;
|
|
209
225
|
if (this.heartbeatTimer) clearInterval(this.heartbeatTimer);
|
|
210
226
|
this.heartbeatTimer = null;
|
|
227
|
+
this.stopKeepalive();
|
|
211
228
|
this.ready = false;
|
|
212
229
|
this.clientCount = 0;
|
|
213
230
|
this.legacyHeartbeat = false;
|
|
@@ -276,6 +293,7 @@ class HostConnector {
|
|
|
276
293
|
if (message.type === 'host_ready') {
|
|
277
294
|
this.ready = true;
|
|
278
295
|
this.reconnectAttempts = 0;
|
|
296
|
+
this.startKeepalive();
|
|
279
297
|
if (Object.hasOwn(message, 'clientCount')) {
|
|
280
298
|
this.legacyHeartbeat = false;
|
|
281
299
|
this.setClientCount(message.clientCount);
|
|
@@ -460,6 +478,49 @@ class HostConnector {
|
|
|
460
478
|
this.sendHeartbeat();
|
|
461
479
|
}
|
|
462
480
|
|
|
481
|
+
startKeepalive() {
|
|
482
|
+
this.stopKeepalive();
|
|
483
|
+
if (!this.ws || this.stopping) return;
|
|
484
|
+
this.ws.isAlive = true;
|
|
485
|
+
const interval = this.config?.cleanup?.heartbeatIntervalMs || 30_000;
|
|
486
|
+
this.keepaliveTimer = setInterval(() => this.tickKeepalive(), interval);
|
|
487
|
+
}
|
|
488
|
+
|
|
489
|
+
stopKeepalive() {
|
|
490
|
+
if (this.keepaliveTimer) {
|
|
491
|
+
clearInterval(this.keepaliveTimer);
|
|
492
|
+
this.keepaliveTimer = null;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
tickKeepalive() {
|
|
497
|
+
const ws = this.ws;
|
|
498
|
+
if (!ws || this.stopping) return;
|
|
499
|
+
if (ws.readyState === WebSocket.CLOSING) {
|
|
500
|
+
terminateSocket(ws);
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
if (ws.readyState !== WebSocket.OPEN) return;
|
|
504
|
+
|
|
505
|
+
if (!ws.isAlive) {
|
|
506
|
+
terminateSocket(ws);
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
ws.isAlive = false;
|
|
511
|
+
try {
|
|
512
|
+
if (typeof ws.ping === 'function') ws.ping();
|
|
513
|
+
} catch {}
|
|
514
|
+
|
|
515
|
+
if (this.clientCount <= 0 && !this.legacyHeartbeat) {
|
|
516
|
+
sendJson(ws, {
|
|
517
|
+
type: 'heartbeat',
|
|
518
|
+
load: {},
|
|
519
|
+
ptys: [],
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
}
|
|
523
|
+
|
|
463
524
|
setClientCount(value) {
|
|
464
525
|
const next = Number.isInteger(value) ? Math.max(0, value) : 0;
|
|
465
526
|
if (next === this.clientCount && (next === 0 || this.heartbeatTimer)) return;
|