@andrian.yablonskyy/thub-agent 1.1.20 → 1.1.22
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/package.json +1 -1
- package/src/cli.js +12 -1
- package/src/remote.js +16 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@andrian.yablonskyy/thub-agent",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.22",
|
|
4
4
|
"description": "TestHub Agent CLI — the single entry point CI/CD and developers use to submit and follow test jobs",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE.md",
|
|
6
6
|
"author": "Andrian Yablonskyy <andrian.yablonskyy@gmail.com>",
|
package/src/cli.js
CHANGED
|
@@ -514,10 +514,19 @@ program
|
|
|
514
514
|
session.on('status', (s) => {
|
|
515
515
|
until = s.until;
|
|
516
516
|
});
|
|
517
|
+
// The camera's state on the Client (README §5.7): said when it changes.
|
|
518
|
+
const cameraState = (c) => (c ? (c.streaming ? 'streaming' : c.error ? `not streaming — ${c.error}` : 'starting…') : null);
|
|
519
|
+
let lastCamera = null;
|
|
517
520
|
session.on('devices', (devices) => {
|
|
521
|
+
const camera = cameraState(devices.camera);
|
|
518
522
|
if (listening){
|
|
523
|
+
if (camera && camera !== lastCamera){
|
|
524
|
+
log(`Video: ${camera}`);
|
|
525
|
+
}
|
|
526
|
+
lastCamera = camera;
|
|
519
527
|
return;
|
|
520
528
|
}
|
|
529
|
+
lastCamera = camera;
|
|
521
530
|
listening = (async () => {
|
|
522
531
|
const local = await listenLocal(session, devices, {
|
|
523
532
|
host: opts.bind, uartBase: opts.uartPort, gdbBase: opts.gdbPort, target: opts.target, log
|
|
@@ -579,7 +588,9 @@ function printConnection(name, link, until, ports, devices, opts, video){
|
|
|
579
588
|
}
|
|
580
589
|
}
|
|
581
590
|
if (video){
|
|
582
|
-
|
|
591
|
+
const c = devices.camera,
|
|
592
|
+
state = c.streaming === false && c.error ? ` (not streaming — ${c.error})` : c.streaming === false ? ' (starting…)' : '';
|
|
593
|
+
lines.push(`Video ${c.name} H.264 (MPEG-TS) ${video.url}${state}`,
|
|
583
594
|
` vlc ${video.url} · ffplay -fflags nobuffer ${video.url}` +
|
|
584
595
|
(video.udp ? `\n UDP: ${video.udp} (ffplay -fflags nobuffer ${video.udp})` : ' · UDP too: --video-udp 5600'));
|
|
585
596
|
}
|
package/src/remote.js
CHANGED
|
@@ -23,8 +23,13 @@ const net = require('node:net'),
|
|
|
23
23
|
// Without a ping from the Coordinator (every 30 s) for this long, the
|
|
24
24
|
// connection is taken for dead and made again.
|
|
25
25
|
const PING_TIMEOUT_MS = 75_000,
|
|
26
|
-
// HTTP answers to the upgrade that won't change by trying again
|
|
27
|
-
|
|
26
|
+
// HTTP answers to the upgrade that won't change by trying again: a
|
|
27
|
+
// refusal, or — a redirect, 426 — a reverse proxy that doesn't pass
|
|
28
|
+
// WebSocket upgrades on to the Coordinator.
|
|
29
|
+
FINAL_STATUSES = new Set([401, 403, 404, 409, 426]),
|
|
30
|
+
isFinal = (status) => FINAL_STATUSES.has(status) || (status >= 300 && status < 400),
|
|
31
|
+
PROXY_HINT = 'a reverse proxy in front of the Coordinator isn\'t passing WebSocket upgrades on to it ' +
|
|
32
|
+
'(Help → Reserved boards → Client host setup)';
|
|
28
33
|
|
|
29
34
|
// One WebSocket to the reservation's own link (/api/v1/remote/<reservation>,
|
|
30
35
|
// from GET /resources), made again whenever it drops (1 s, 2 s, 4 s … 30 s
|
|
@@ -99,7 +104,14 @@ class RemoteSession extends EventEmitter{
|
|
|
99
104
|
catch {
|
|
100
105
|
error = null;
|
|
101
106
|
}
|
|
102
|
-
|
|
107
|
+
const status = res.statusCode,
|
|
108
|
+
location = res.headers.location ? ` → ${res.headers.location}` : '';
|
|
109
|
+
refused = {
|
|
110
|
+
status,
|
|
111
|
+
error: error || (status >= 300 && status < 400
|
|
112
|
+
? `The Coordinator answered HTTP ${status}${location} instead of opening a WebSocket: ${PROXY_HINT}`
|
|
113
|
+
: `HTTP ${status}`)
|
|
114
|
+
};
|
|
103
115
|
ws.terminate();
|
|
104
116
|
});
|
|
105
117
|
});
|
|
@@ -116,7 +128,7 @@ class RemoteSession extends EventEmitter{
|
|
|
116
128
|
if (this.stopped){
|
|
117
129
|
return;
|
|
118
130
|
}
|
|
119
|
-
if ((refused &&
|
|
131
|
+
if ((refused && isFinal(refused.status)) || code === REMOTE_CLOSE.RESERVATION_ENDED || code === REMOTE_CLOSE.REPLACED){
|
|
120
132
|
this.stopped = true;
|
|
121
133
|
const message = reason || 'The Coordinator ended the connection';
|
|
122
134
|
for (const ch of [...this.channels.keys()]){
|