@andrian.yablonskyy/thub-agent 1.1.20 → 1.1.21

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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. 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.20",
3
+ "version": "1.1.21",
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/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
- FINAL_STATUSES = new Set([401, 403, 404, 409]);
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
- refused = { status: res.statusCode, error: error || `HTTP ${res.statusCode}` };
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 && FINAL_STATUSES.has(refused.status)) || code === REMOTE_CLOSE.RESERVATION_ENDED || code === REMOTE_CLOSE.REPLACED){
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()]){