@limrun/api 0.59.0 → 0.61.0
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/CHANGELOG.md +90 -0
- package/destination-tunnel-dialer.d.mts +15 -0
- package/destination-tunnel-dialer.d.mts.map +1 -1
- package/destination-tunnel-dialer.d.ts +15 -0
- package/destination-tunnel-dialer.d.ts.map +1 -1
- package/destination-tunnel-dialer.js +21 -9
- package/destination-tunnel-dialer.js.map +1 -1
- package/destination-tunnel-dialer.mjs +18 -8
- package/destination-tunnel-dialer.mjs.map +1 -1
- package/destination-tunnel.d.mts +4 -0
- package/destination-tunnel.d.mts.map +1 -1
- package/destination-tunnel.d.ts +4 -0
- package/destination-tunnel.d.ts.map +1 -1
- package/destination-tunnel.js +2 -0
- package/destination-tunnel.js.map +1 -1
- package/destination-tunnel.mjs +2 -0
- package/destination-tunnel.mjs.map +1 -1
- package/index.d.mts +1 -0
- package/index.d.mts.map +1 -1
- package/index.d.ts +1 -0
- package/index.d.ts.map +1 -1
- package/index.js +4 -2
- package/index.js.map +1 -1
- package/index.mjs +1 -0
- package/index.mjs.map +1 -1
- package/internal/destination-tunnel-management.d.mts +2 -0
- package/internal/destination-tunnel-management.d.mts.map +1 -1
- package/internal/destination-tunnel-management.d.ts +2 -0
- package/internal/destination-tunnel-management.d.ts.map +1 -1
- package/internal/destination-tunnel-management.js +5 -0
- package/internal/destination-tunnel-management.js.map +1 -1
- package/internal/destination-tunnel-management.mjs +6 -1
- package/internal/destination-tunnel-management.mjs.map +1 -1
- package/internal/destination-tunnel-url.d.mts +2 -0
- package/internal/destination-tunnel-url.d.mts.map +1 -1
- package/internal/destination-tunnel-url.d.ts +2 -0
- package/internal/destination-tunnel-url.d.ts.map +1 -1
- package/internal/destination-tunnel-url.js +9 -2
- package/internal/destination-tunnel-url.js.map +1 -1
- package/internal/destination-tunnel-url.mjs +8 -2
- package/internal/destination-tunnel-url.mjs.map +1 -1
- package/internal/destination-tunnel-wire-reader.d.mts +2 -0
- package/internal/destination-tunnel-wire-reader.d.mts.map +1 -1
- package/internal/destination-tunnel-wire-reader.d.ts +2 -0
- package/internal/destination-tunnel-wire-reader.d.ts.map +1 -1
- package/internal/destination-tunnel-wire-reader.js +17 -0
- package/internal/destination-tunnel-wire-reader.js.map +1 -1
- package/internal/destination-tunnel-wire-reader.mjs +15 -0
- package/internal/destination-tunnel-wire-reader.mjs.map +1 -1
- package/ios-client.d.mts +6 -4
- package/ios-client.d.mts.map +1 -1
- package/ios-client.d.ts +6 -4
- package/ios-client.d.ts.map +1 -1
- package/ios-client.js +3 -1
- package/ios-client.js.map +1 -1
- package/ios-client.mjs +3 -1
- package/ios-client.mjs.map +1 -1
- package/ios-launch-environment.d.mts +3 -0
- package/ios-launch-environment.d.mts.map +1 -0
- package/ios-launch-environment.d.ts +3 -0
- package/ios-launch-environment.d.ts.map +1 -0
- package/ios-launch-environment.js +14 -0
- package/ios-launch-environment.js.map +1 -0
- package/ios-launch-environment.mjs +11 -0
- package/ios-launch-environment.mjs.map +1 -0
- package/package.json +22 -2
- package/resources/android-instances.d.mts +12 -0
- package/resources/android-instances.d.mts.map +1 -1
- package/resources/android-instances.d.ts +12 -0
- package/resources/android-instances.d.ts.map +1 -1
- package/resources/ios-instances.d.mts +12 -0
- package/resources/ios-instances.d.mts.map +1 -1
- package/resources/ios-instances.d.ts +12 -0
- package/resources/ios-instances.d.ts.map +1 -1
- package/src/destination-tunnel-dialer.ts +24 -8
- package/src/destination-tunnel.ts +6 -0
- package/src/index.ts +6 -0
- package/src/internal/destination-tunnel-management.ts +15 -1
- package/src/internal/destination-tunnel-url.ts +15 -2
- package/src/internal/destination-tunnel-wire-reader.ts +17 -0
- package/src/ios-client.ts +12 -5
- package/src/ios-launch-environment.ts +11 -0
- package/src/resources/android-instances.ts +14 -0
- package/src/resources/ios-instances.ts +14 -0
- package/src/tunnel-connector.ts +767 -0
- package/src/tunnel.ts +8 -6
- package/src/version.ts +1 -1
- package/tunnel-connector.d.mts +88 -0
- package/tunnel-connector.d.mts.map +1 -0
- package/tunnel-connector.d.ts +88 -0
- package/tunnel-connector.d.ts.map +1 -0
- package/tunnel-connector.js +628 -0
- package/tunnel-connector.js.map +1 -0
- package/tunnel-connector.mjs +624 -0
- package/tunnel-connector.mjs.map +1 -0
- package/tunnel.d.mts +2 -0
- package/tunnel.d.mts.map +1 -1
- package/tunnel.d.ts +2 -0
- package/tunnel.d.ts.map +1 -1
- package/tunnel.js +8 -6
- package/tunnel.js.map +1 -1
- package/tunnel.mjs +7 -6
- package/tunnel.mjs.map +1 -1
- package/version.d.mts +1 -1
- package/version.d.ts +1 -1
- package/version.js +1 -1
- package/version.mjs +1 -1
|
@@ -0,0 +1,628 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.runTunnel = runTunnel;
|
|
4
|
+
const tslib_1 = require("./internal/tslib.js");
|
|
5
|
+
const os_1 = tslib_1.__importDefault(require("os"));
|
|
6
|
+
const ws_1 = require("ws");
|
|
7
|
+
const proxy_transport_1 = require("./internal/proxy-transport.js");
|
|
8
|
+
const destination_tunnel_url_1 = require("./internal/destination-tunnel-url.js");
|
|
9
|
+
const destination_tunnel_management_1 = require("./internal/destination-tunnel-management.js");
|
|
10
|
+
const destination_tunnel_wire_reader_1 = require("./internal/destination-tunnel-wire-reader.js");
|
|
11
|
+
const destination_tunnel_dialer_1 = require("./destination-tunnel-dialer.js");
|
|
12
|
+
const destination_tunnel_1 = require("./destination-tunnel.js");
|
|
13
|
+
const tunnel_1 = require("./tunnel.js");
|
|
14
|
+
const version_1 = require("./version.js");
|
|
15
|
+
const CONTROL_PROTOCOL_VERSION = 2;
|
|
16
|
+
const CONTROL_HANDSHAKE_TIMEOUT_MS = 15000;
|
|
17
|
+
const CONTROL_PING_INTERVAL_MS = 15000;
|
|
18
|
+
const CONTROL_DEAD_PEER_MS = 45000;
|
|
19
|
+
const CONTROL_INITIAL_BACKOFF_MS = 500;
|
|
20
|
+
const CONTROL_MAX_BACKOFF_MS = 10000;
|
|
21
|
+
const BYE_GRACE_MS = 1000;
|
|
22
|
+
const ATTACH_INITIAL_BACKOFF_MS = 1000;
|
|
23
|
+
const ATTACH_MAX_BACKOFF_MS = 30000;
|
|
24
|
+
/** The platform deletes an instance whose tunnel has not attached 30s after assignment. */
|
|
25
|
+
const ATTACH_FIRST_MAX_BACKOFF_MS = 2000;
|
|
26
|
+
/** The API explains a refused connection in a short plain-text body. */
|
|
27
|
+
const MAX_REJECTION_REASON_CHARS = 200;
|
|
28
|
+
/** Every tunnel WebSocket counts as instance activity, so retries must end. */
|
|
29
|
+
const ATTACH_GIVE_UP_MS = 5 * 60000;
|
|
30
|
+
const TAKEN_OVER_MESSAGE = 'another connector for this tunnel took the instance over';
|
|
31
|
+
/** A token this close to its expiry is not dialed with; the hub refreshes it at half its life. */
|
|
32
|
+
const TOKEN_EXPIRY_MARGIN_MS = 5000;
|
|
33
|
+
/** How long before its key expires the connector starts warning, and how often. */
|
|
34
|
+
const KEY_WARNING_WINDOW_MS = 14 * 24 * 60 * 60000;
|
|
35
|
+
const KEY_WARNING_EVERY_MS = 24 * 60 * 60000;
|
|
36
|
+
/**
|
|
37
|
+
* Serve a persistent tunnel: hold it through one control WebSocket to the
|
|
38
|
+
* Limrun API and open a destination tunnel to every instance created with
|
|
39
|
+
* `spec.tunnel` set to its name, with a short-lived token the API hands out
|
|
40
|
+
* for each. Instance tunnels stay up while the control channel reconnects,
|
|
41
|
+
* so an API outage never becomes a tunnel outage; one that drops re-dials
|
|
42
|
+
* once the API sends a fresh token.
|
|
43
|
+
*/
|
|
44
|
+
function runTunnel(options) {
|
|
45
|
+
// Reject a bad inspection config now rather than on every attach.
|
|
46
|
+
(0, destination_tunnel_1.normalizeDestinationTunnelInspection)((0, destination_tunnel_dialer_1.destinationTunnelInspection)(options.inspection));
|
|
47
|
+
const controlURL = (0, destination_tunnel_url_1.deriveTunnelConnectURL)(options.baseURL, options.organizationId, options.tunnelId);
|
|
48
|
+
const client = {
|
|
49
|
+
hostname: options.hostname ?? os_1.default.hostname(),
|
|
50
|
+
version: options.clientVersion ?? version_1.VERSION,
|
|
51
|
+
};
|
|
52
|
+
const instances = new Map();
|
|
53
|
+
let ws;
|
|
54
|
+
let stopped = false;
|
|
55
|
+
let reconnectTimer;
|
|
56
|
+
let controlBackoffMs = CONTROL_INITIAL_BACKOFF_MS;
|
|
57
|
+
let sessionId;
|
|
58
|
+
// --replace takes the name over once; afterwards this connector resumes
|
|
59
|
+
// like any holder and never steals the name back.
|
|
60
|
+
let replace = options.replace ?? false;
|
|
61
|
+
// When the last confirmed lease runs out; zero while on standby.
|
|
62
|
+
let leaseExpiresAt = 0;
|
|
63
|
+
// The tunnel's name, from the first active; instances set it in spec.tunnel.
|
|
64
|
+
let tunnelName;
|
|
65
|
+
let lastKeyWarning = 0;
|
|
66
|
+
let announcedSession;
|
|
67
|
+
let announcedHolder;
|
|
68
|
+
let resolveClosed;
|
|
69
|
+
let rejectClosed;
|
|
70
|
+
const closed = new Promise((resolve, reject) => {
|
|
71
|
+
resolveClosed = resolve;
|
|
72
|
+
rejectClosed = reject;
|
|
73
|
+
});
|
|
74
|
+
// Callers that never await `closed` must not crash on a terminal error.
|
|
75
|
+
closed.catch(() => { });
|
|
76
|
+
const emit = (event) => {
|
|
77
|
+
try {
|
|
78
|
+
options.onEvent?.(event);
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
// Event callbacks are isolated from the connector.
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
// Messages sent while the control channel is down are dropped; the hello of
|
|
85
|
+
// the next connection reports which instances are attached.
|
|
86
|
+
const send = (message) => {
|
|
87
|
+
if (ws?.readyState === ws_1.WebSocket.OPEN)
|
|
88
|
+
ws.send(JSON.stringify(message));
|
|
89
|
+
};
|
|
90
|
+
const isConfirmedHolder = () => Date.now() < leaseExpiresAt;
|
|
91
|
+
const forget = (instanceId, attachment) => {
|
|
92
|
+
const tunnel = attachment.tunnel;
|
|
93
|
+
attachment.tunnel = undefined;
|
|
94
|
+
attachment.done = true;
|
|
95
|
+
clearTimeout(attachment.retryTimer);
|
|
96
|
+
tunnel?.close();
|
|
97
|
+
if (instances.get(instanceId) === attachment)
|
|
98
|
+
instances.delete(instanceId);
|
|
99
|
+
};
|
|
100
|
+
// Ends the connector once: no more reconnects, and every instance tunnel closes.
|
|
101
|
+
const shutdown = () => {
|
|
102
|
+
if (stopped)
|
|
103
|
+
return false;
|
|
104
|
+
stopped = true;
|
|
105
|
+
clearTimeout(reconnectTimer);
|
|
106
|
+
for (const [instanceId, attachment] of instances)
|
|
107
|
+
forget(instanceId, attachment);
|
|
108
|
+
return true;
|
|
109
|
+
};
|
|
110
|
+
const fail = (detail) => {
|
|
111
|
+
if (!shutdown())
|
|
112
|
+
return;
|
|
113
|
+
ws?.terminate();
|
|
114
|
+
rejectClosed(new Error(`tunnel ${tunnelName ?? options.tunnelId}: ${detail}`));
|
|
115
|
+
};
|
|
116
|
+
const dialOptions = (attachment) => ({
|
|
117
|
+
...(0, destination_tunnel_dialer_1.destinationTunnelDialOptions)({ selectors: attachment.selectors, ...(options.inspection ? { inspection: options.inspection } : {}) }, options.logLevel ?? 'warn'),
|
|
118
|
+
...(tunnelName === undefined ? {} : { name: tunnelName }),
|
|
119
|
+
});
|
|
120
|
+
const tokenUsable = (attachment) => Date.now() < attachment.tokenExpiresAt - TOKEN_EXPIRY_MARGIN_MS;
|
|
121
|
+
// Tells the platform and the caller that the connector gave up on an instance.
|
|
122
|
+
const reportGivenUp = (instanceId, code, message) => {
|
|
123
|
+
send({ type: 'attachFailed', instanceId, code, message, terminal: true });
|
|
124
|
+
emit({ type: 'attachFailed', instanceId, code, message });
|
|
125
|
+
};
|
|
126
|
+
const giveUp = (instanceId, attachment, code, message) => {
|
|
127
|
+
forget(instanceId, attachment);
|
|
128
|
+
reportGivenUp(instanceId, code, message);
|
|
129
|
+
};
|
|
130
|
+
const scheduleAttachRetry = (instanceId, attachment, reason) => {
|
|
131
|
+
const delayMs = jittered(attachment.backoffMs);
|
|
132
|
+
const maxMs = attachment.lastTunnelId === undefined ? ATTACH_FIRST_MAX_BACKOFF_MS : ATTACH_MAX_BACKOFF_MS;
|
|
133
|
+
attachment.backoffMs = Math.min(attachment.backoffMs * 2, maxMs);
|
|
134
|
+
emit({ type: 'reconnecting', instanceId, delayMs, reason });
|
|
135
|
+
attachment.retryTimer = setTimeout(() => void attach(instanceId, attachment), delayMs);
|
|
136
|
+
};
|
|
137
|
+
const retryAfterFailure = (instanceId, attachment, code, message) => {
|
|
138
|
+
if (Date.now() - attachment.failingSince >= ATTACH_GIVE_UP_MS) {
|
|
139
|
+
giveUp(instanceId, attachment, 'attach_timeout', `could not attach within 5 minutes: ${message}`);
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
send({ type: 'attachFailed', instanceId, code, message, terminal: false });
|
|
143
|
+
scheduleAttachRetry(instanceId, attachment, message);
|
|
144
|
+
};
|
|
145
|
+
// A drop with a same-name tunnel of another ID now active means another
|
|
146
|
+
// holder took the instance over. Yielding keeps two connectors from
|
|
147
|
+
// superseding each other forever. A stopping tunnel is on its way out.
|
|
148
|
+
const takenOver = async (attachment) => {
|
|
149
|
+
try {
|
|
150
|
+
const active = (await (0, destination_tunnel_management_1.getDestinationTunnelStatus)(attachment.url, attachment.token)).active;
|
|
151
|
+
return (active !== undefined &&
|
|
152
|
+
active.name === tunnelName &&
|
|
153
|
+
active.state !== 'stopping' &&
|
|
154
|
+
active.tunnelId !== attachment.lastTunnelId);
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
// The dial that follows surfaces a real failure.
|
|
158
|
+
return false;
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
// A failed stop shows up as the same tunnel on the next attempt.
|
|
162
|
+
const stopQuietly = async (attachment, tunnelId) => {
|
|
163
|
+
try {
|
|
164
|
+
await (0, destination_tunnel_management_1.stopDestinationTunnel)(attachment.url, attachment.token, tunnelId);
|
|
165
|
+
}
|
|
166
|
+
catch {
|
|
167
|
+
// The next attempt reports a tunnel that is still there.
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
const resolveAlreadyActive = async (instanceId, attachment) => {
|
|
171
|
+
let active;
|
|
172
|
+
try {
|
|
173
|
+
active = (await (0, destination_tunnel_management_1.getDestinationTunnelStatus)(attachment.url, attachment.token)).active;
|
|
174
|
+
}
|
|
175
|
+
catch (error) {
|
|
176
|
+
if (!attachment.done)
|
|
177
|
+
retryAfterFailure(instanceId, attachment, 'already_active', errorMessage(error));
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
if (attachment.done)
|
|
181
|
+
return;
|
|
182
|
+
// A stopping tunnel, such as one this connector just stopped, refuses
|
|
183
|
+
// new claims until it is gone; wait it out instead of yielding.
|
|
184
|
+
if (!active || active.state === 'stopping') {
|
|
185
|
+
retryAfterFailure(instanceId, attachment, 'already_active', 'the previous tunnel is still stopping');
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
if (active.name !== tunnelName) {
|
|
189
|
+
giveUp(instanceId, attachment, 'instance_busy', 'the instance already has another tunnel');
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
// This connector's own dropped tunnel lingers until the instance notices
|
|
193
|
+
// the dead socket; stop it instead of waiting. The backoff keeps a failing
|
|
194
|
+
// stop from spinning.
|
|
195
|
+
if (active.tunnelId === attachment.lastTunnelId) {
|
|
196
|
+
await stopQuietly(attachment, active.tunnelId);
|
|
197
|
+
if (!attachment.done) {
|
|
198
|
+
retryAfterFailure(instanceId, attachment, 'already_active', 'stopping the dropped tunnel');
|
|
199
|
+
}
|
|
200
|
+
return;
|
|
201
|
+
}
|
|
202
|
+
// Only the confirmed holder may stop another same-name tunnel, and only
|
|
203
|
+
// once: it can then belong to nobody but a dead predecessor.
|
|
204
|
+
if (attachment.mayReclaim && isConfirmedHolder()) {
|
|
205
|
+
attachment.mayReclaim = false;
|
|
206
|
+
await stopQuietly(attachment, active.tunnelId);
|
|
207
|
+
if (!attachment.done)
|
|
208
|
+
void attach(instanceId, attachment);
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
giveUp(instanceId, attachment, 'taken_over', TAKEN_OVER_MESSAGE);
|
|
212
|
+
};
|
|
213
|
+
const attach = async (instanceId, attachment) => {
|
|
214
|
+
attachment.retryTimer = undefined;
|
|
215
|
+
// Only the confirmed holder dials, so a connector that lost the name
|
|
216
|
+
// never pushes the holder's tunnel off. The instance waits until a
|
|
217
|
+
// renewal confirms the lease again or the attach deadline passes.
|
|
218
|
+
if (!isConfirmedHolder()) {
|
|
219
|
+
retryAfterFailure(instanceId, attachment, 'not_holder', 'this connector does not hold the tunnel');
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
// A token past its life is refused; the API sends a fresh one at half
|
|
223
|
+
// life, so this only waits while the control channel is down.
|
|
224
|
+
if (!tokenUsable(attachment)) {
|
|
225
|
+
retryAfterFailure(instanceId, attachment, 'token_expired', 'waiting for a fresh tunnel token');
|
|
226
|
+
return;
|
|
227
|
+
}
|
|
228
|
+
let tunnel;
|
|
229
|
+
try {
|
|
230
|
+
if (attachment.lastTunnelId !== undefined && (await takenOver(attachment))) {
|
|
231
|
+
if (!attachment.done) {
|
|
232
|
+
giveUp(instanceId, attachment, 'taken_over', TAKEN_OVER_MESSAGE);
|
|
233
|
+
}
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
if (attachment.done)
|
|
237
|
+
return;
|
|
238
|
+
tunnel = await (0, destination_tunnel_dialer_1.startDestinationTcpTunnel)((0, destination_tunnel_url_1.deriveDestinationTunnelURL)(attachment.url), attachment.token, dialOptions(attachment));
|
|
239
|
+
}
|
|
240
|
+
catch (error) {
|
|
241
|
+
if (attachment.done)
|
|
242
|
+
return;
|
|
243
|
+
if ((0, tunnel_1.upgradeStatus)(errorMessage(error)) === 404) {
|
|
244
|
+
giveUp(instanceId, attachment, 'instance_gone', 'the instance is gone or terminating');
|
|
245
|
+
}
|
|
246
|
+
else if (!(error instanceof destination_tunnel_dialer_1.DestinationTunnelSessionError)) {
|
|
247
|
+
retryAfterFailure(instanceId, attachment, 'connect_failed', errorMessage(error));
|
|
248
|
+
}
|
|
249
|
+
else if (error.code === 'already_active') {
|
|
250
|
+
await resolveAlreadyActive(instanceId, attachment);
|
|
251
|
+
}
|
|
252
|
+
else if (error.code === 'unavailable' || error.code === 'internal') {
|
|
253
|
+
// The instance cannot start a tunnel right now, such as while its
|
|
254
|
+
// inspection helper restarts.
|
|
255
|
+
retryAfterFailure(instanceId, attachment, error.code, `the instance could not start the tunnel: ${error.code}`);
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
giveUp(instanceId, attachment, error.code, `the instance rejected the tunnel: ${error.code}`);
|
|
259
|
+
}
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
if (attachment.done) {
|
|
263
|
+
tunnel.close();
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
attachment.tunnel = tunnel;
|
|
267
|
+
attachment.lastTunnelId = tunnel.tunnelId;
|
|
268
|
+
attachment.mayReclaim = false;
|
|
269
|
+
attachment.backoffMs = ATTACH_INITIAL_BACKOFF_MS;
|
|
270
|
+
const dropped = () => {
|
|
271
|
+
attachment.tunnel = undefined;
|
|
272
|
+
attachment.failingSince = Date.now();
|
|
273
|
+
scheduleAttachRetry(instanceId, attachment, 'the instance tunnel disconnected');
|
|
274
|
+
};
|
|
275
|
+
tunnel.onConnectionStateChange((state) => {
|
|
276
|
+
if (state === 'disconnected' && attachment.tunnel === tunnel)
|
|
277
|
+
dropped();
|
|
278
|
+
});
|
|
279
|
+
// A drop between the dial resolving and the listener above fires no event.
|
|
280
|
+
if (tunnel.getConnectionState() === 'disconnected') {
|
|
281
|
+
dropped();
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
send({ type: 'attached', instanceId, tunnelId: tunnel.tunnelId });
|
|
285
|
+
emit({ type: 'attached', instanceId, tunnelId: tunnel.tunnelId });
|
|
286
|
+
};
|
|
287
|
+
const handleMessage = (message) => {
|
|
288
|
+
// close() already let every instance go; a late attach must not dial.
|
|
289
|
+
if (stopped)
|
|
290
|
+
return;
|
|
291
|
+
switch (message.type) {
|
|
292
|
+
case 'active': {
|
|
293
|
+
replace = false;
|
|
294
|
+
leaseExpiresAt = Date.now() + message.leaseSeconds * 1000;
|
|
295
|
+
controlBackoffMs = CONTROL_INITIAL_BACKOFF_MS;
|
|
296
|
+
sessionId = message.sessionId;
|
|
297
|
+
tunnelName = message.name;
|
|
298
|
+
announcedHolder = undefined;
|
|
299
|
+
if (announcedSession !== message.sessionId) {
|
|
300
|
+
announcedSession = message.sessionId;
|
|
301
|
+
emit({ type: 'active', sessionId: message.sessionId, name: message.name });
|
|
302
|
+
}
|
|
303
|
+
const now = Date.now();
|
|
304
|
+
if (message.keyExpiresAt !== undefined &&
|
|
305
|
+
Date.parse(message.keyExpiresAt) - now < KEY_WARNING_WINDOW_MS &&
|
|
306
|
+
now - lastKeyWarning >= KEY_WARNING_EVERY_MS) {
|
|
307
|
+
lastKeyWarning = now;
|
|
308
|
+
emit({ type: 'keyExpiring', expiresAt: message.keyExpiresAt });
|
|
309
|
+
}
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
case 'standby': {
|
|
313
|
+
leaseExpiresAt = 0;
|
|
314
|
+
controlBackoffMs = CONTROL_INITIAL_BACKOFF_MS;
|
|
315
|
+
sessionId = undefined;
|
|
316
|
+
announcedSession = undefined;
|
|
317
|
+
const holder = `${message.holder.hostname}\0${message.holder.since ?? ''}`;
|
|
318
|
+
if (announcedHolder !== holder) {
|
|
319
|
+
announcedHolder = holder;
|
|
320
|
+
emit({ type: 'standby', holder: message.holder });
|
|
321
|
+
}
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
case 'token': {
|
|
325
|
+
// A fresh token at half its life, or after a resume. An instance this
|
|
326
|
+
// connector gave up on stays given up.
|
|
327
|
+
const attachment = instances.get(message.instanceId);
|
|
328
|
+
if (attachment) {
|
|
329
|
+
attachment.token = message.token;
|
|
330
|
+
attachment.tokenExpiresAt = Date.now() + message.expiresInSeconds * 1000;
|
|
331
|
+
}
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
case 'attach': {
|
|
335
|
+
// Expiry is relative, so this host's clock never matters.
|
|
336
|
+
const tokenExpiresAt = Date.now() + message.expiresInSeconds * 1000;
|
|
337
|
+
const existing = instances.get(message.instanceId);
|
|
338
|
+
if (existing) {
|
|
339
|
+
// A new holder session re-attaches every instance, including ones
|
|
340
|
+
// this connector still serves; a live tunnel only needs confirming.
|
|
341
|
+
// The instance keeps the selectors it first got.
|
|
342
|
+
existing.url = message.url;
|
|
343
|
+
existing.token = message.token;
|
|
344
|
+
existing.tokenExpiresAt = tokenExpiresAt;
|
|
345
|
+
if (existing.tunnel) {
|
|
346
|
+
send({ type: 'attached', instanceId: message.instanceId, tunnelId: existing.tunnel.tunnelId });
|
|
347
|
+
}
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
// The instance itself refuses what its platform cannot route, such
|
|
351
|
+
// as Android routes below port 1024.
|
|
352
|
+
let selectors;
|
|
353
|
+
try {
|
|
354
|
+
selectors = (0, destination_tunnel_1.validateDestinationTunnelSelectors)(message.selectors);
|
|
355
|
+
}
|
|
356
|
+
catch (error) {
|
|
357
|
+
reportGivenUp(message.instanceId, 'invalid_selectors', errorMessage(error));
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
const attachment = {
|
|
361
|
+
url: message.url,
|
|
362
|
+
token: message.token,
|
|
363
|
+
tokenExpiresAt,
|
|
364
|
+
selectors,
|
|
365
|
+
mayReclaim: true,
|
|
366
|
+
failingSince: Date.now(),
|
|
367
|
+
backoffMs: ATTACH_INITIAL_BACKOFF_MS,
|
|
368
|
+
done: false,
|
|
369
|
+
};
|
|
370
|
+
instances.set(message.instanceId, attachment);
|
|
371
|
+
void attach(message.instanceId, attachment);
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
case 'detach': {
|
|
375
|
+
const attachment = instances.get(message.instanceId);
|
|
376
|
+
if (!attachment)
|
|
377
|
+
return;
|
|
378
|
+
forget(message.instanceId, attachment);
|
|
379
|
+
emit({ type: 'detached', instanceId: message.instanceId, reason: message.reason });
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
case 'notice':
|
|
383
|
+
emit(message);
|
|
384
|
+
return;
|
|
385
|
+
case 'revoked':
|
|
386
|
+
fail(revokedMessage(message.reason));
|
|
387
|
+
}
|
|
388
|
+
};
|
|
389
|
+
const scheduleReconnect = (reason, prompt) => {
|
|
390
|
+
if (stopped)
|
|
391
|
+
return;
|
|
392
|
+
const delayMs = jittered(prompt ? CONTROL_INITIAL_BACKOFF_MS : controlBackoffMs);
|
|
393
|
+
if (!prompt)
|
|
394
|
+
controlBackoffMs = Math.min(controlBackoffMs * 2, CONTROL_MAX_BACKOFF_MS);
|
|
395
|
+
emit({ type: 'reconnecting', delayMs, reason });
|
|
396
|
+
reconnectTimer = setTimeout(connectControl, delayMs);
|
|
397
|
+
};
|
|
398
|
+
const handleClose = (code, reason) => {
|
|
399
|
+
const detail = reason ? `: ${reason}` : '';
|
|
400
|
+
switch (code) {
|
|
401
|
+
case 1000:
|
|
402
|
+
fail(`the server ended the session${detail}`);
|
|
403
|
+
return;
|
|
404
|
+
case 1012:
|
|
405
|
+
case 1013:
|
|
406
|
+
scheduleReconnect(`the server asked to reconnect (${code})`, true);
|
|
407
|
+
return;
|
|
408
|
+
case 4400:
|
|
409
|
+
fail(`the server rejected the connector${detail}`);
|
|
410
|
+
return;
|
|
411
|
+
case 4404:
|
|
412
|
+
fail('the tunnel was deleted');
|
|
413
|
+
return;
|
|
414
|
+
case 4409:
|
|
415
|
+
fail(`the tunnel was revoked${detail}`);
|
|
416
|
+
return;
|
|
417
|
+
default:
|
|
418
|
+
scheduleReconnect(`the control connection closed (${code}${detail})`, false);
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
const connectControl = () => {
|
|
422
|
+
reconnectTimer = undefined;
|
|
423
|
+
if (stopped)
|
|
424
|
+
return;
|
|
425
|
+
const proxyAgent = proxy_transport_1.nodeProxyTransport.getWebSocketAgent(controlURL);
|
|
426
|
+
const socket = new ws_1.WebSocket(controlURL, {
|
|
427
|
+
headers: { Authorization: `Bearer ${options.apiKey}` },
|
|
428
|
+
...(proxyAgent ? { agent: proxyAgent } : {}),
|
|
429
|
+
perMessageDeflate: false,
|
|
430
|
+
// A stalled upgrade, such as after a laptop wakes, would otherwise
|
|
431
|
+
// never reconnect.
|
|
432
|
+
handshakeTimeout: CONTROL_HANDSHAKE_TIMEOUT_MS,
|
|
433
|
+
});
|
|
434
|
+
ws = socket;
|
|
435
|
+
announcedSession = undefined;
|
|
436
|
+
let pingInterval;
|
|
437
|
+
let livenessTimer;
|
|
438
|
+
let rejectedStatus;
|
|
439
|
+
let rejectedReason = '';
|
|
440
|
+
let lastError;
|
|
441
|
+
const armLiveness = () => {
|
|
442
|
+
clearTimeout(livenessTimer);
|
|
443
|
+
livenessTimer = setTimeout(() => {
|
|
444
|
+
lastError = `no frames for ${CONTROL_DEAD_PEER_MS}ms`;
|
|
445
|
+
socket.terminate();
|
|
446
|
+
}, CONTROL_DEAD_PEER_MS);
|
|
447
|
+
livenessTimer.unref();
|
|
448
|
+
};
|
|
449
|
+
socket.on('open', () => {
|
|
450
|
+
armLiveness();
|
|
451
|
+
pingInterval = setInterval(() => {
|
|
452
|
+
if (socket.readyState === ws_1.WebSocket.OPEN)
|
|
453
|
+
socket.ping();
|
|
454
|
+
}, CONTROL_PING_INTERVAL_MS);
|
|
455
|
+
pingInterval.unref();
|
|
456
|
+
send({
|
|
457
|
+
type: 'hello',
|
|
458
|
+
version: CONTROL_PROTOCOL_VERSION,
|
|
459
|
+
replace,
|
|
460
|
+
...(sessionId === undefined ? {} : { sessionId }),
|
|
461
|
+
attached: Array.from(instances)
|
|
462
|
+
.filter(([, attachment]) => attachment.tunnel)
|
|
463
|
+
.map(([instanceId]) => instanceId),
|
|
464
|
+
client,
|
|
465
|
+
});
|
|
466
|
+
});
|
|
467
|
+
socket.on('message', (data, isBinary) => {
|
|
468
|
+
armLiveness();
|
|
469
|
+
let message;
|
|
470
|
+
try {
|
|
471
|
+
if (isBinary)
|
|
472
|
+
throw new destination_tunnel_wire_reader_1.DestinationTunnelProtocolError('unexpected binary control frame');
|
|
473
|
+
message = decodeControlServerMessage(JSON.parse((0, destination_tunnel_wire_reader_1.toBuffer)(data).toString('utf8')));
|
|
474
|
+
}
|
|
475
|
+
catch (error) {
|
|
476
|
+
lastError = `invalid control message: ${errorMessage(error)}`;
|
|
477
|
+
socket.terminate();
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
if (message)
|
|
481
|
+
handleMessage(message);
|
|
482
|
+
});
|
|
483
|
+
socket.on('ping', armLiveness);
|
|
484
|
+
socket.on('pong', armLiveness);
|
|
485
|
+
socket.on('unexpected-response', (_request, response) => {
|
|
486
|
+
rejectedStatus = response.statusCode ?? 0;
|
|
487
|
+
// Anything but the API's plain-text reason, such as a proxy's HTML
|
|
488
|
+
// error page, is left out.
|
|
489
|
+
if (!String(response.headers['content-type'] ?? '').startsWith('text/plain')) {
|
|
490
|
+
socket.terminate();
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
493
|
+
response.setEncoding('utf8');
|
|
494
|
+
response.on('data', (chunk) => {
|
|
495
|
+
rejectedReason = (rejectedReason + chunk).slice(0, MAX_REJECTION_REASON_CHARS);
|
|
496
|
+
});
|
|
497
|
+
response.once('end', () => socket.terminate());
|
|
498
|
+
response.once('error', () => socket.terminate());
|
|
499
|
+
});
|
|
500
|
+
socket.on('error', (error) => {
|
|
501
|
+
lastError ?? (lastError = error.message);
|
|
502
|
+
});
|
|
503
|
+
socket.once('close', (code, reason) => {
|
|
504
|
+
clearInterval(pingInterval);
|
|
505
|
+
clearTimeout(livenessTimer);
|
|
506
|
+
if (ws === socket)
|
|
507
|
+
ws = undefined;
|
|
508
|
+
if (stopped)
|
|
509
|
+
return;
|
|
510
|
+
if (rejectedStatus !== undefined) {
|
|
511
|
+
const reason = rejectedReason.trim();
|
|
512
|
+
const detail = reason ? `HTTP ${rejectedStatus}: ${reason}` : `HTTP ${rejectedStatus}`;
|
|
513
|
+
// A refused upgrade with a 4xx status never succeeds on retry, except
|
|
514
|
+
// a rate limit.
|
|
515
|
+
if (rejectedStatus >= 400 && rejectedStatus < 500 && rejectedStatus !== 429) {
|
|
516
|
+
fail(`the server refused the connection (${detail})`);
|
|
517
|
+
}
|
|
518
|
+
else {
|
|
519
|
+
scheduleReconnect(`the server answered ${detail}`, false);
|
|
520
|
+
}
|
|
521
|
+
return;
|
|
522
|
+
}
|
|
523
|
+
if (code === 1006 && lastError) {
|
|
524
|
+
scheduleReconnect(lastError, false);
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
handleClose(code, reason.toString());
|
|
528
|
+
});
|
|
529
|
+
};
|
|
530
|
+
const close = async () => {
|
|
531
|
+
if (!shutdown())
|
|
532
|
+
return;
|
|
533
|
+
const socket = ws;
|
|
534
|
+
if (socket?.readyState === ws_1.WebSocket.OPEN) {
|
|
535
|
+
// bye releases the name at once instead of after the lease expires.
|
|
536
|
+
send({ type: 'bye' });
|
|
537
|
+
await new Promise((resolve) => {
|
|
538
|
+
const grace = setTimeout(() => socket.terminate(), BYE_GRACE_MS);
|
|
539
|
+
socket.once('close', () => {
|
|
540
|
+
clearTimeout(grace);
|
|
541
|
+
resolve();
|
|
542
|
+
});
|
|
543
|
+
socket.close(1000, 'bye');
|
|
544
|
+
});
|
|
545
|
+
}
|
|
546
|
+
else {
|
|
547
|
+
socket?.terminate();
|
|
548
|
+
}
|
|
549
|
+
resolveClosed();
|
|
550
|
+
};
|
|
551
|
+
connectControl();
|
|
552
|
+
return { closed, close };
|
|
553
|
+
}
|
|
554
|
+
function decodeControlServerMessage(value) {
|
|
555
|
+
const message = (0, destination_tunnel_wire_reader_1.readRecord)(value, 'tunnel control message');
|
|
556
|
+
const type = (0, destination_tunnel_wire_reader_1.readString)(message, 'type');
|
|
557
|
+
switch (type) {
|
|
558
|
+
case 'active': {
|
|
559
|
+
return {
|
|
560
|
+
type,
|
|
561
|
+
sessionId: (0, destination_tunnel_wire_reader_1.readNonEmptyString)(message, 'sessionId'),
|
|
562
|
+
leaseSeconds: (0, destination_tunnel_wire_reader_1.readPositiveInteger)(message, 'leaseSeconds'),
|
|
563
|
+
name: (0, destination_tunnel_wire_reader_1.readNonEmptyString)(message, 'name'),
|
|
564
|
+
...(0, destination_tunnel_wire_reader_1.readOptionalString)(message, 'keyExpiresAt'),
|
|
565
|
+
};
|
|
566
|
+
}
|
|
567
|
+
case 'standby': {
|
|
568
|
+
const holder = (0, destination_tunnel_wire_reader_1.readRecord)(message['holder'], 'holder');
|
|
569
|
+
return {
|
|
570
|
+
type,
|
|
571
|
+
holder: { hostname: (0, destination_tunnel_wire_reader_1.readString)(holder, 'hostname'), ...(0, destination_tunnel_wire_reader_1.readOptionalString)(holder, 'since') },
|
|
572
|
+
};
|
|
573
|
+
}
|
|
574
|
+
case 'attach':
|
|
575
|
+
return {
|
|
576
|
+
type,
|
|
577
|
+
instanceId: (0, destination_tunnel_wire_reader_1.readNonEmptyString)(message, 'instanceId'),
|
|
578
|
+
url: (0, destination_tunnel_wire_reader_1.readNonEmptyString)(message, 'url'),
|
|
579
|
+
selectors: (0, destination_tunnel_wire_reader_1.readStringArray)(message, 'selectors'),
|
|
580
|
+
token: (0, destination_tunnel_wire_reader_1.readNonEmptyString)(message, 'token'),
|
|
581
|
+
expiresInSeconds: (0, destination_tunnel_wire_reader_1.readPositiveInteger)(message, 'expiresInSeconds'),
|
|
582
|
+
};
|
|
583
|
+
case 'token':
|
|
584
|
+
return {
|
|
585
|
+
type,
|
|
586
|
+
instanceId: (0, destination_tunnel_wire_reader_1.readNonEmptyString)(message, 'instanceId'),
|
|
587
|
+
token: (0, destination_tunnel_wire_reader_1.readNonEmptyString)(message, 'token'),
|
|
588
|
+
expiresInSeconds: (0, destination_tunnel_wire_reader_1.readPositiveInteger)(message, 'expiresInSeconds'),
|
|
589
|
+
};
|
|
590
|
+
case 'detach':
|
|
591
|
+
return {
|
|
592
|
+
type,
|
|
593
|
+
instanceId: (0, destination_tunnel_wire_reader_1.readNonEmptyString)(message, 'instanceId'),
|
|
594
|
+
reason: (0, destination_tunnel_wire_reader_1.readString)(message, 'reason'),
|
|
595
|
+
};
|
|
596
|
+
case 'notice':
|
|
597
|
+
return {
|
|
598
|
+
type,
|
|
599
|
+
code: (0, destination_tunnel_wire_reader_1.readString)(message, 'code'),
|
|
600
|
+
message: (0, destination_tunnel_wire_reader_1.readString)(message, 'message'),
|
|
601
|
+
...(0, destination_tunnel_wire_reader_1.readOptionalString)(message, 'instanceId'),
|
|
602
|
+
};
|
|
603
|
+
case 'revoked':
|
|
604
|
+
return { type, reason: (0, destination_tunnel_wire_reader_1.readString)(message, 'reason') };
|
|
605
|
+
default:
|
|
606
|
+
// Newer servers may add message types that this connector does not need.
|
|
607
|
+
return undefined;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
function revokedMessage(reason) {
|
|
611
|
+
switch (reason) {
|
|
612
|
+
case 'replaced':
|
|
613
|
+
return 'another connector replaced this one';
|
|
614
|
+
case 'deleted':
|
|
615
|
+
return 'the tunnel was deleted';
|
|
616
|
+
case 'credential':
|
|
617
|
+
return 'the API key was revoked';
|
|
618
|
+
default:
|
|
619
|
+
return `the tunnel was revoked (${reason})`;
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
function errorMessage(error) {
|
|
623
|
+
return error instanceof Error ? error.message : String(error);
|
|
624
|
+
}
|
|
625
|
+
function jittered(delayMs) {
|
|
626
|
+
return Math.round(delayMs * (0.75 + Math.random() * 0.5));
|
|
627
|
+
}
|
|
628
|
+
//# sourceMappingURL=tunnel-connector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tunnel-connector.js","sourceRoot":"","sources":["src/tunnel-connector.ts"],"names":[],"mappings":"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"}
|