@replit/river 0.23.12 → 0.23.14
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/{chunk-3AW3IXVD.js → chunk-4PVU7J25.js} +1 -21
- package/dist/chunk-4PVU7J25.js.map +1 -0
- package/dist/{chunk-HDBVL7EF.js → chunk-BEALFLCB.js} +2 -2
- package/dist/chunk-D2DHRRBN.js +476 -0
- package/dist/chunk-D2DHRRBN.js.map +1 -0
- package/dist/{chunk-7RUKEUKE.js → chunk-GCCRVSMR.js} +33 -4
- package/dist/chunk-GCCRVSMR.js.map +1 -0
- package/dist/{chunk-XZ6IOBM5.js → chunk-GN4YEXT7.js} +2 -2
- package/dist/chunk-GN4YEXT7.js.map +1 -0
- package/dist/chunk-O2AVDJCQ.js +335 -0
- package/dist/chunk-O2AVDJCQ.js.map +1 -0
- package/dist/chunk-OTVTKAN6.js +451 -0
- package/dist/chunk-OTVTKAN6.js.map +1 -0
- package/dist/chunk-WUL63FR6.js +335 -0
- package/dist/chunk-WUL63FR6.js.map +1 -0
- package/dist/{chunk-H6KTH6W6.js → chunk-YCLZWES2.js} +2 -2
- package/dist/client-e13979ac.d.ts +52 -0
- package/dist/codec/index.js +20 -2
- package/dist/codec/index.js.map +1 -1
- package/dist/{connection-8debd45f.d.ts → connection-5d0978ce.d.ts} +1 -1
- package/dist/{connection-581558f8.d.ts → connection-e57e98ea.d.ts} +1 -1
- package/dist/{transport-47af1c81.d.ts → handshake-5665ffd3.d.ts} +101 -153
- package/dist/{index-60f03cb7.d.ts → index-ea74cdbb.d.ts} +1 -1
- package/dist/logging/index.d.cts +1 -1
- package/dist/logging/index.d.ts +1 -1
- package/dist/router/index.cjs +16 -1
- package/dist/router/index.cjs.map +1 -1
- package/dist/router/index.d.cts +8 -6
- package/dist/router/index.d.ts +8 -6
- package/dist/router/index.js +2 -2
- package/dist/server-1cfc88d1.d.ts +24 -0
- package/dist/{services-ca72c9f8.d.ts → services-86c4d10d.d.ts} +3 -2
- package/dist/transport/impls/uds/client.cjs +303 -180
- package/dist/transport/impls/uds/client.cjs.map +1 -1
- package/dist/transport/impls/uds/client.d.cts +6 -5
- package/dist/transport/impls/uds/client.d.ts +6 -5
- package/dist/transport/impls/uds/client.js +6 -4
- package/dist/transport/impls/uds/client.js.map +1 -1
- package/dist/transport/impls/uds/server.cjs +396 -234
- package/dist/transport/impls/uds/server.cjs.map +1 -1
- package/dist/transport/impls/uds/server.d.cts +6 -5
- package/dist/transport/impls/uds/server.d.ts +6 -5
- package/dist/transport/impls/uds/server.js +8 -6
- package/dist/transport/impls/uds/server.js.map +1 -1
- package/dist/transport/impls/ws/client.cjs +305 -182
- package/dist/transport/impls/ws/client.cjs.map +1 -1
- package/dist/transport/impls/ws/client.d.cts +6 -5
- package/dist/transport/impls/ws/client.d.ts +6 -5
- package/dist/transport/impls/ws/client.js +6 -4
- package/dist/transport/impls/ws/client.js.map +1 -1
- package/dist/transport/impls/ws/server.cjs +350 -188
- package/dist/transport/impls/ws/server.cjs.map +1 -1
- package/dist/transport/impls/ws/server.d.cts +4 -3
- package/dist/transport/impls/ws/server.d.ts +4 -3
- package/dist/transport/impls/ws/server.js +8 -6
- package/dist/transport/impls/ws/server.js.map +1 -1
- package/dist/transport/index.cjs +338 -142
- package/dist/transport/index.cjs.map +1 -1
- package/dist/transport/index.d.cts +4 -2
- package/dist/transport/index.d.ts +4 -2
- package/dist/transport/index.js +14 -8
- package/dist/util/testHelpers.cjs +10 -6
- package/dist/util/testHelpers.cjs.map +1 -1
- package/dist/util/testHelpers.d.cts +5 -4
- package/dist/util/testHelpers.d.ts +5 -4
- package/dist/util/testHelpers.js +4 -5
- package/dist/util/testHelpers.js.map +1 -1
- package/package.json +13 -14
- package/dist/chunk-3AW3IXVD.js.map +0 -1
- package/dist/chunk-7RUKEUKE.js.map +0 -1
- package/dist/chunk-VRU4IKRT.js +0 -1392
- package/dist/chunk-VRU4IKRT.js.map +0 -1
- package/dist/chunk-XZ6IOBM5.js.map +0 -1
- /package/dist/{chunk-HDBVL7EF.js.map → chunk-BEALFLCB.js.map} +0 -0
- /package/dist/{chunk-H6KTH6W6.js.map → chunk-YCLZWES2.js.map} +0 -0
package/dist/chunk-VRU4IKRT.js
DELETED
|
@@ -1,1392 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
ControlMessageHandshakeRequestSchema,
|
|
3
|
-
ControlMessageHandshakeResponseSchema,
|
|
4
|
-
OpaqueTransportMessageSchema,
|
|
5
|
-
PROTOCOL_VERSION,
|
|
6
|
-
coerceErrorString,
|
|
7
|
-
createConnectionTelemetryInfo,
|
|
8
|
-
createSessionTelemetryInfo,
|
|
9
|
-
getPropagationContext,
|
|
10
|
-
handshakeRequestMessage,
|
|
11
|
-
handshakeResponseMessage,
|
|
12
|
-
isAck,
|
|
13
|
-
tracing_default
|
|
14
|
-
} from "./chunk-7RUKEUKE.js";
|
|
15
|
-
import {
|
|
16
|
-
BaseLogger,
|
|
17
|
-
createLogProxy
|
|
18
|
-
} from "./chunk-6LCL2ZZF.js";
|
|
19
|
-
import {
|
|
20
|
-
NaiveJsonCodec
|
|
21
|
-
} from "./chunk-3AW3IXVD.js";
|
|
22
|
-
|
|
23
|
-
// transport/session.ts
|
|
24
|
-
import { customAlphabet } from "nanoid";
|
|
25
|
-
import { SpanStatusCode } from "@opentelemetry/api";
|
|
26
|
-
var nanoid = customAlphabet("1234567890abcdefghijklmnopqrstuvxyz", 6);
|
|
27
|
-
var unsafeId = () => nanoid();
|
|
28
|
-
var Connection = class {
|
|
29
|
-
id;
|
|
30
|
-
telemetry;
|
|
31
|
-
constructor() {
|
|
32
|
-
this.id = `conn-${nanoid(12)}`;
|
|
33
|
-
}
|
|
34
|
-
get loggingMetadata() {
|
|
35
|
-
const metadata = { connId: this.id };
|
|
36
|
-
const spanContext = this.telemetry?.span.spanContext();
|
|
37
|
-
if (this.telemetry?.span.isRecording() && spanContext) {
|
|
38
|
-
metadata.telemetry = {
|
|
39
|
-
traceId: spanContext.traceId,
|
|
40
|
-
spanId: spanContext.spanId
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
return metadata;
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
var Session = class {
|
|
47
|
-
codec;
|
|
48
|
-
options;
|
|
49
|
-
telemetry;
|
|
50
|
-
/**
|
|
51
|
-
* The buffer of messages that have been sent but not yet acknowledged.
|
|
52
|
-
*/
|
|
53
|
-
sendBuffer = [];
|
|
54
|
-
/**
|
|
55
|
-
* The active connection associated with this session
|
|
56
|
-
*/
|
|
57
|
-
connection;
|
|
58
|
-
/**
|
|
59
|
-
* A connection that is currently undergoing handshaking. Used to distinguish between the active
|
|
60
|
-
* connection, but still be able to close it if needed.
|
|
61
|
-
*/
|
|
62
|
-
handshakingConnection;
|
|
63
|
-
from;
|
|
64
|
-
to;
|
|
65
|
-
/**
|
|
66
|
-
* The unique ID of this session.
|
|
67
|
-
*/
|
|
68
|
-
id;
|
|
69
|
-
/**
|
|
70
|
-
* What the other side advertised as their session ID
|
|
71
|
-
* for this session.
|
|
72
|
-
*/
|
|
73
|
-
advertisedSessionId;
|
|
74
|
-
/**
|
|
75
|
-
* Number of messages we've sent along this session (excluding handshake and acks)
|
|
76
|
-
*/
|
|
77
|
-
seq = 0;
|
|
78
|
-
/**
|
|
79
|
-
* Number of unique messages we've received this session (excluding handshake and acks)
|
|
80
|
-
*/
|
|
81
|
-
ack = 0;
|
|
82
|
-
/**
|
|
83
|
-
* The grace period between when the inner connection is disconnected
|
|
84
|
-
* and when we should consider the entire session disconnected.
|
|
85
|
-
*/
|
|
86
|
-
disconnectionGrace;
|
|
87
|
-
/**
|
|
88
|
-
* Number of heartbeats we've sent without a response.
|
|
89
|
-
*/
|
|
90
|
-
heartbeatMisses;
|
|
91
|
-
/**
|
|
92
|
-
* The interval for sending heartbeats.
|
|
93
|
-
*/
|
|
94
|
-
heartbeat;
|
|
95
|
-
log;
|
|
96
|
-
constructor(conn, from, to, options, propagationCtx) {
|
|
97
|
-
this.id = `session-${nanoid(12)}`;
|
|
98
|
-
this.options = options;
|
|
99
|
-
this.from = from;
|
|
100
|
-
this.to = to;
|
|
101
|
-
this.connection = conn;
|
|
102
|
-
this.codec = options.codec;
|
|
103
|
-
this.heartbeatMisses = 0;
|
|
104
|
-
this.heartbeat = setInterval(
|
|
105
|
-
() => this.sendHeartbeat(),
|
|
106
|
-
options.heartbeatIntervalMs
|
|
107
|
-
);
|
|
108
|
-
this.telemetry = createSessionTelemetryInfo(this, propagationCtx);
|
|
109
|
-
}
|
|
110
|
-
bindLogger(log) {
|
|
111
|
-
this.log = log;
|
|
112
|
-
}
|
|
113
|
-
get loggingMetadata() {
|
|
114
|
-
const spanContext = this.telemetry.span.spanContext();
|
|
115
|
-
return {
|
|
116
|
-
clientId: this.from,
|
|
117
|
-
connectedTo: this.to,
|
|
118
|
-
sessionId: this.id,
|
|
119
|
-
connId: this.connection?.id,
|
|
120
|
-
telemetry: {
|
|
121
|
-
traceId: spanContext.traceId,
|
|
122
|
-
spanId: spanContext.spanId
|
|
123
|
-
}
|
|
124
|
-
};
|
|
125
|
-
}
|
|
126
|
-
/**
|
|
127
|
-
* Sends a message over the session's connection.
|
|
128
|
-
* If the connection is not ready or the message fails to send, the message can be buffered for retry unless skipped.
|
|
129
|
-
*
|
|
130
|
-
* @param msg The partial message to be sent, which will be constructed into a full message.
|
|
131
|
-
* @param addToSendBuff Whether to add the message to the send buffer for retry.
|
|
132
|
-
* @returns The full transport ID of the message that was attempted to be sent.
|
|
133
|
-
*/
|
|
134
|
-
send(msg) {
|
|
135
|
-
const fullMsg = this.constructMsg(msg);
|
|
136
|
-
this.log?.debug(`sending msg`, {
|
|
137
|
-
...this.loggingMetadata,
|
|
138
|
-
transportMessage: fullMsg
|
|
139
|
-
});
|
|
140
|
-
if (this.connection) {
|
|
141
|
-
const ok = this.connection.send(this.codec.toBuffer(fullMsg));
|
|
142
|
-
if (ok)
|
|
143
|
-
return fullMsg.id;
|
|
144
|
-
this.log?.info(
|
|
145
|
-
`failed to send msg to ${fullMsg.to}, connection is probably dead`,
|
|
146
|
-
{
|
|
147
|
-
...this.loggingMetadata,
|
|
148
|
-
transportMessage: fullMsg
|
|
149
|
-
}
|
|
150
|
-
);
|
|
151
|
-
} else {
|
|
152
|
-
this.log?.debug(
|
|
153
|
-
`buffering msg to ${fullMsg.to}, connection not ready yet`,
|
|
154
|
-
{ ...this.loggingMetadata, transportMessage: fullMsg }
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
return fullMsg.id;
|
|
158
|
-
}
|
|
159
|
-
sendHeartbeat() {
|
|
160
|
-
const misses = this.heartbeatMisses;
|
|
161
|
-
const missDuration = misses * this.options.heartbeatIntervalMs;
|
|
162
|
-
if (misses > this.options.heartbeatsUntilDead) {
|
|
163
|
-
if (this.connection) {
|
|
164
|
-
this.log?.info(
|
|
165
|
-
`closing connection to ${this.to} due to inactivity (missed ${misses} heartbeats which is ${missDuration}ms)`,
|
|
166
|
-
this.loggingMetadata
|
|
167
|
-
);
|
|
168
|
-
this.telemetry.span.addEvent("closing connection due to inactivity");
|
|
169
|
-
this.closeStaleConnection();
|
|
170
|
-
}
|
|
171
|
-
return;
|
|
172
|
-
}
|
|
173
|
-
this.send({
|
|
174
|
-
streamId: "heartbeat",
|
|
175
|
-
controlFlags: 1 /* AckBit */,
|
|
176
|
-
payload: {
|
|
177
|
-
type: "ACK"
|
|
178
|
-
}
|
|
179
|
-
});
|
|
180
|
-
this.heartbeatMisses++;
|
|
181
|
-
}
|
|
182
|
-
resetBufferedMessages() {
|
|
183
|
-
this.sendBuffer = [];
|
|
184
|
-
this.seq = 0;
|
|
185
|
-
this.ack = 0;
|
|
186
|
-
}
|
|
187
|
-
sendBufferedMessages(conn) {
|
|
188
|
-
this.log?.info(`resending ${this.sendBuffer.length} buffered messages`, {
|
|
189
|
-
...this.loggingMetadata,
|
|
190
|
-
connId: conn.id
|
|
191
|
-
});
|
|
192
|
-
for (const msg of this.sendBuffer) {
|
|
193
|
-
this.log?.debug(`resending msg`, {
|
|
194
|
-
...this.loggingMetadata,
|
|
195
|
-
transportMessage: msg,
|
|
196
|
-
connId: conn.id
|
|
197
|
-
});
|
|
198
|
-
const ok = conn.send(this.codec.toBuffer(msg));
|
|
199
|
-
if (!ok) {
|
|
200
|
-
const errMsg = `failed to send buffered message to ${this.to} (sus, this is a fresh connection)`;
|
|
201
|
-
conn.telemetry?.span.setStatus({
|
|
202
|
-
code: SpanStatusCode.ERROR,
|
|
203
|
-
message: errMsg
|
|
204
|
-
});
|
|
205
|
-
this.log?.error(errMsg, {
|
|
206
|
-
...this.loggingMetadata,
|
|
207
|
-
transportMessage: msg,
|
|
208
|
-
connId: conn.id,
|
|
209
|
-
tags: ["invariant-violation"]
|
|
210
|
-
});
|
|
211
|
-
conn.close();
|
|
212
|
-
return;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
updateBookkeeping(ack, seq) {
|
|
217
|
-
if (seq + 1 < this.ack) {
|
|
218
|
-
this.log?.error(`received stale seq ${seq} + 1 < ${this.ack}`, {
|
|
219
|
-
...this.loggingMetadata,
|
|
220
|
-
tags: ["invariant-violation"]
|
|
221
|
-
});
|
|
222
|
-
return;
|
|
223
|
-
}
|
|
224
|
-
this.sendBuffer = this.sendBuffer.filter((unacked) => unacked.seq >= ack);
|
|
225
|
-
this.ack = seq + 1;
|
|
226
|
-
}
|
|
227
|
-
closeStaleConnection(conn) {
|
|
228
|
-
if (this.connection === void 0 || this.connection === conn)
|
|
229
|
-
return;
|
|
230
|
-
this.log?.info(
|
|
231
|
-
`closing old inner connection from session to ${this.to}`,
|
|
232
|
-
this.loggingMetadata
|
|
233
|
-
);
|
|
234
|
-
this.connection.close();
|
|
235
|
-
this.connection = void 0;
|
|
236
|
-
}
|
|
237
|
-
replaceWithNewConnection(newConn, isTransparentReconnect) {
|
|
238
|
-
this.closeStaleConnection(newConn);
|
|
239
|
-
this.cancelGrace();
|
|
240
|
-
if (isTransparentReconnect) {
|
|
241
|
-
this.sendBufferedMessages(newConn);
|
|
242
|
-
}
|
|
243
|
-
this.connection = newConn;
|
|
244
|
-
this.handshakingConnection = void 0;
|
|
245
|
-
}
|
|
246
|
-
replaceWithNewHandshakingConnection(newConn) {
|
|
247
|
-
this.handshakingConnection = newConn;
|
|
248
|
-
}
|
|
249
|
-
beginGrace(cb) {
|
|
250
|
-
this.log?.info(
|
|
251
|
-
`starting ${this.options.sessionDisconnectGraceMs}ms grace period until session to ${this.to} is closed`,
|
|
252
|
-
this.loggingMetadata
|
|
253
|
-
);
|
|
254
|
-
this.cancelGrace();
|
|
255
|
-
this.disconnectionGrace = setTimeout(() => {
|
|
256
|
-
this.log?.info(
|
|
257
|
-
`grace period for ${this.to} elapsed`,
|
|
258
|
-
this.loggingMetadata
|
|
259
|
-
);
|
|
260
|
-
cb();
|
|
261
|
-
}, this.options.sessionDisconnectGraceMs);
|
|
262
|
-
}
|
|
263
|
-
// called on reconnect of the underlying session
|
|
264
|
-
cancelGrace() {
|
|
265
|
-
this.heartbeatMisses = 0;
|
|
266
|
-
clearTimeout(this.disconnectionGrace);
|
|
267
|
-
this.disconnectionGrace = void 0;
|
|
268
|
-
}
|
|
269
|
-
/**
|
|
270
|
-
* Used to close the handshaking connection, if set.
|
|
271
|
-
*/
|
|
272
|
-
closeHandshakingConnection(expectedHandshakingConn) {
|
|
273
|
-
if (this.handshakingConnection === void 0)
|
|
274
|
-
return;
|
|
275
|
-
if (expectedHandshakingConn !== void 0 && this.handshakingConnection === expectedHandshakingConn) {
|
|
276
|
-
return;
|
|
277
|
-
}
|
|
278
|
-
this.handshakingConnection.close();
|
|
279
|
-
this.handshakingConnection = void 0;
|
|
280
|
-
}
|
|
281
|
-
// closed when we want to discard the whole session
|
|
282
|
-
// (i.e. shutdown or session disconnect)
|
|
283
|
-
close() {
|
|
284
|
-
this.closeStaleConnection();
|
|
285
|
-
this.cancelGrace();
|
|
286
|
-
this.resetBufferedMessages();
|
|
287
|
-
clearInterval(this.heartbeat);
|
|
288
|
-
}
|
|
289
|
-
get connected() {
|
|
290
|
-
return this.connection !== void 0;
|
|
291
|
-
}
|
|
292
|
-
get nextExpectedSeq() {
|
|
293
|
-
return this.ack;
|
|
294
|
-
}
|
|
295
|
-
constructMsg(partialMsg) {
|
|
296
|
-
const msg = {
|
|
297
|
-
...partialMsg,
|
|
298
|
-
id: unsafeId(),
|
|
299
|
-
to: this.to,
|
|
300
|
-
from: this.from,
|
|
301
|
-
seq: this.seq,
|
|
302
|
-
ack: this.ack
|
|
303
|
-
};
|
|
304
|
-
this.seq++;
|
|
305
|
-
this.sendBuffer.push(msg);
|
|
306
|
-
return msg;
|
|
307
|
-
}
|
|
308
|
-
inspectSendBuffer() {
|
|
309
|
-
return this.sendBuffer;
|
|
310
|
-
}
|
|
311
|
-
};
|
|
312
|
-
|
|
313
|
-
// transport/events.ts
|
|
314
|
-
var ProtocolError = {
|
|
315
|
-
RetriesExceeded: "conn_retry_exceeded",
|
|
316
|
-
HandshakeFailed: "handshake_failed",
|
|
317
|
-
MessageOrderingViolated: "message_ordering_violated"
|
|
318
|
-
};
|
|
319
|
-
var EventDispatcher = class {
|
|
320
|
-
eventListeners = {};
|
|
321
|
-
removeAllListeners() {
|
|
322
|
-
this.eventListeners = {};
|
|
323
|
-
}
|
|
324
|
-
numberOfListeners(eventType) {
|
|
325
|
-
return this.eventListeners[eventType]?.size ?? 0;
|
|
326
|
-
}
|
|
327
|
-
addEventListener(eventType, handler) {
|
|
328
|
-
if (!this.eventListeners[eventType]) {
|
|
329
|
-
this.eventListeners[eventType] = /* @__PURE__ */ new Set();
|
|
330
|
-
}
|
|
331
|
-
this.eventListeners[eventType]?.add(handler);
|
|
332
|
-
}
|
|
333
|
-
removeEventListener(eventType, handler) {
|
|
334
|
-
const handlers = this.eventListeners[eventType];
|
|
335
|
-
if (handlers) {
|
|
336
|
-
this.eventListeners[eventType]?.delete(handler);
|
|
337
|
-
}
|
|
338
|
-
}
|
|
339
|
-
dispatchEvent(eventType, event) {
|
|
340
|
-
const handlers = this.eventListeners[eventType];
|
|
341
|
-
if (handlers) {
|
|
342
|
-
const copy = [...handlers];
|
|
343
|
-
for (const handler of copy) {
|
|
344
|
-
handler(event);
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
};
|
|
349
|
-
|
|
350
|
-
// transport/transport.ts
|
|
351
|
-
import { Value } from "@sinclair/typebox/value";
|
|
352
|
-
|
|
353
|
-
// transport/rateLimit.ts
|
|
354
|
-
var LeakyBucketRateLimit = class {
|
|
355
|
-
budgetConsumed;
|
|
356
|
-
intervalHandles;
|
|
357
|
-
options;
|
|
358
|
-
constructor(options) {
|
|
359
|
-
this.options = options;
|
|
360
|
-
this.budgetConsumed = /* @__PURE__ */ new Map();
|
|
361
|
-
this.intervalHandles = /* @__PURE__ */ new Map();
|
|
362
|
-
}
|
|
363
|
-
getBackoffMs(user) {
|
|
364
|
-
if (!this.budgetConsumed.has(user))
|
|
365
|
-
return 0;
|
|
366
|
-
const exponent = Math.max(0, this.getBudgetConsumed(user) - 1);
|
|
367
|
-
const jitter = Math.floor(Math.random() * this.options.maxJitterMs);
|
|
368
|
-
const backoffMs = Math.min(
|
|
369
|
-
this.options.baseIntervalMs * 2 ** exponent,
|
|
370
|
-
this.options.maxBackoffMs
|
|
371
|
-
);
|
|
372
|
-
return backoffMs + jitter;
|
|
373
|
-
}
|
|
374
|
-
get totalBudgetRestoreTime() {
|
|
375
|
-
return this.options.budgetRestoreIntervalMs * this.options.attemptBudgetCapacity;
|
|
376
|
-
}
|
|
377
|
-
consumeBudget(user) {
|
|
378
|
-
this.stopLeak(user);
|
|
379
|
-
this.budgetConsumed.set(user, this.getBudgetConsumed(user) + 1);
|
|
380
|
-
}
|
|
381
|
-
getBudgetConsumed(user) {
|
|
382
|
-
return this.budgetConsumed.get(user) ?? 0;
|
|
383
|
-
}
|
|
384
|
-
hasBudget(user) {
|
|
385
|
-
return this.getBudgetConsumed(user) < this.options.attemptBudgetCapacity;
|
|
386
|
-
}
|
|
387
|
-
startRestoringBudget(user) {
|
|
388
|
-
if (this.intervalHandles.has(user)) {
|
|
389
|
-
return;
|
|
390
|
-
}
|
|
391
|
-
const restoreBudgetForUser = () => {
|
|
392
|
-
const currentBudget = this.budgetConsumed.get(user);
|
|
393
|
-
if (!currentBudget) {
|
|
394
|
-
this.stopLeak(user);
|
|
395
|
-
return;
|
|
396
|
-
}
|
|
397
|
-
const newBudget = currentBudget - 1;
|
|
398
|
-
if (newBudget === 0) {
|
|
399
|
-
this.budgetConsumed.delete(user);
|
|
400
|
-
return;
|
|
401
|
-
}
|
|
402
|
-
this.budgetConsumed.set(user, newBudget);
|
|
403
|
-
};
|
|
404
|
-
const intervalHandle = setInterval(
|
|
405
|
-
restoreBudgetForUser,
|
|
406
|
-
this.options.budgetRestoreIntervalMs
|
|
407
|
-
);
|
|
408
|
-
this.intervalHandles.set(user, intervalHandle);
|
|
409
|
-
}
|
|
410
|
-
stopLeak(user) {
|
|
411
|
-
if (!this.intervalHandles.has(user)) {
|
|
412
|
-
return;
|
|
413
|
-
}
|
|
414
|
-
clearInterval(this.intervalHandles.get(user));
|
|
415
|
-
this.intervalHandles.delete(user);
|
|
416
|
-
}
|
|
417
|
-
close() {
|
|
418
|
-
for (const user of this.intervalHandles.keys()) {
|
|
419
|
-
this.stopLeak(user);
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
};
|
|
423
|
-
|
|
424
|
-
// transport/transport.ts
|
|
425
|
-
import { SpanStatusCode as SpanStatusCode2 } from "@opentelemetry/api";
|
|
426
|
-
var defaultTransportOptions = {
|
|
427
|
-
heartbeatIntervalMs: 1e3,
|
|
428
|
-
heartbeatsUntilDead: 2,
|
|
429
|
-
sessionDisconnectGraceMs: 5e3,
|
|
430
|
-
codec: NaiveJsonCodec
|
|
431
|
-
};
|
|
432
|
-
var defaultConnectionRetryOptions = {
|
|
433
|
-
baseIntervalMs: 250,
|
|
434
|
-
maxJitterMs: 200,
|
|
435
|
-
maxBackoffMs: 32e3,
|
|
436
|
-
attemptBudgetCapacity: 5,
|
|
437
|
-
budgetRestoreIntervalMs: 200
|
|
438
|
-
};
|
|
439
|
-
var defaultClientTransportOptions = {
|
|
440
|
-
...defaultTransportOptions,
|
|
441
|
-
...defaultConnectionRetryOptions
|
|
442
|
-
};
|
|
443
|
-
var defaultServerTransportOptions = {
|
|
444
|
-
...defaultTransportOptions
|
|
445
|
-
};
|
|
446
|
-
var Transport = class {
|
|
447
|
-
/**
|
|
448
|
-
* The status of the transport.
|
|
449
|
-
*/
|
|
450
|
-
status;
|
|
451
|
-
/**
|
|
452
|
-
* The {@link Codec} used to encode and decode messages.
|
|
453
|
-
*/
|
|
454
|
-
codec;
|
|
455
|
-
/**
|
|
456
|
-
* The client ID of this transport.
|
|
457
|
-
*/
|
|
458
|
-
clientId;
|
|
459
|
-
/**
|
|
460
|
-
* The map of {@link Session}s managed by this transport.
|
|
461
|
-
*/
|
|
462
|
-
sessions;
|
|
463
|
-
/**
|
|
464
|
-
* The map of {@link Connection}s managed by this transport.
|
|
465
|
-
*/
|
|
466
|
-
get connections() {
|
|
467
|
-
return new Map(
|
|
468
|
-
[...this.sessions].map(([client, session]) => [client, session.connection]).filter((entry) => entry[1] !== void 0)
|
|
469
|
-
);
|
|
470
|
-
}
|
|
471
|
-
/**
|
|
472
|
-
* The event dispatcher for handling events of type EventTypes.
|
|
473
|
-
*/
|
|
474
|
-
eventDispatcher;
|
|
475
|
-
/**
|
|
476
|
-
* The options for this transport.
|
|
477
|
-
*/
|
|
478
|
-
options;
|
|
479
|
-
log;
|
|
480
|
-
/**
|
|
481
|
-
* Creates a new Transport instance.
|
|
482
|
-
* This should also set up {@link onConnect}, and {@link onDisconnect} listeners.
|
|
483
|
-
* @param codec The codec used to encode and decode messages.
|
|
484
|
-
* @param clientId The client ID of this transport.
|
|
485
|
-
*/
|
|
486
|
-
constructor(clientId, providedOptions) {
|
|
487
|
-
this.options = { ...defaultTransportOptions, ...providedOptions };
|
|
488
|
-
this.eventDispatcher = new EventDispatcher();
|
|
489
|
-
this.sessions = /* @__PURE__ */ new Map();
|
|
490
|
-
this.codec = this.options.codec;
|
|
491
|
-
this.clientId = clientId;
|
|
492
|
-
this.status = "open";
|
|
493
|
-
}
|
|
494
|
-
bindLogger(fn, level) {
|
|
495
|
-
if (typeof fn === "function") {
|
|
496
|
-
this.log = createLogProxy(new BaseLogger(fn, level));
|
|
497
|
-
return;
|
|
498
|
-
}
|
|
499
|
-
this.log = createLogProxy(fn);
|
|
500
|
-
}
|
|
501
|
-
/**
|
|
502
|
-
* Called when a new connection is established
|
|
503
|
-
* and we know the identity of the connected client.
|
|
504
|
-
* @param conn The connection object.
|
|
505
|
-
*/
|
|
506
|
-
onConnect(conn, session, isTransparentReconnect) {
|
|
507
|
-
this.eventDispatcher.dispatchEvent("connectionStatus", {
|
|
508
|
-
status: "connect",
|
|
509
|
-
conn
|
|
510
|
-
});
|
|
511
|
-
conn.telemetry = createConnectionTelemetryInfo(conn, session.telemetry);
|
|
512
|
-
session.replaceWithNewConnection(conn, isTransparentReconnect);
|
|
513
|
-
this.log?.info(`connected to ${session.to}`, {
|
|
514
|
-
...conn.loggingMetadata,
|
|
515
|
-
...session.loggingMetadata
|
|
516
|
-
});
|
|
517
|
-
}
|
|
518
|
-
createSession(to, conn, propagationCtx) {
|
|
519
|
-
const session = new Session(
|
|
520
|
-
conn,
|
|
521
|
-
this.clientId,
|
|
522
|
-
to,
|
|
523
|
-
this.options,
|
|
524
|
-
propagationCtx
|
|
525
|
-
);
|
|
526
|
-
if (this.log) {
|
|
527
|
-
session.bindLogger(this.log);
|
|
528
|
-
}
|
|
529
|
-
this.sessions.set(session.to, session);
|
|
530
|
-
this.eventDispatcher.dispatchEvent("sessionStatus", {
|
|
531
|
-
status: "connect",
|
|
532
|
-
session
|
|
533
|
-
});
|
|
534
|
-
return session;
|
|
535
|
-
}
|
|
536
|
-
getOrCreateSession({
|
|
537
|
-
to,
|
|
538
|
-
conn,
|
|
539
|
-
handshakingConn,
|
|
540
|
-
sessionId,
|
|
541
|
-
propagationCtx
|
|
542
|
-
}) {
|
|
543
|
-
let session = this.sessions.get(to);
|
|
544
|
-
const isReconnect = session !== void 0;
|
|
545
|
-
let isTransparentReconnect = isReconnect;
|
|
546
|
-
if (session?.advertisedSessionId !== void 0 && sessionId !== void 0 && session.advertisedSessionId !== sessionId) {
|
|
547
|
-
this.log?.info(
|
|
548
|
-
`session for ${to} already exists but has a different session id (expected: ${session.advertisedSessionId}, got: ${sessionId}), creating a new one`,
|
|
549
|
-
session.loggingMetadata
|
|
550
|
-
);
|
|
551
|
-
this.deleteSession({
|
|
552
|
-
session,
|
|
553
|
-
closeHandshakingConnection: handshakingConn !== void 0,
|
|
554
|
-
handshakingConn
|
|
555
|
-
});
|
|
556
|
-
isTransparentReconnect = false;
|
|
557
|
-
session = void 0;
|
|
558
|
-
}
|
|
559
|
-
if (!session) {
|
|
560
|
-
session = this.createSession(to, conn, propagationCtx);
|
|
561
|
-
this.log?.info(
|
|
562
|
-
`no session for ${to}, created a new one`,
|
|
563
|
-
session.loggingMetadata
|
|
564
|
-
);
|
|
565
|
-
}
|
|
566
|
-
if (sessionId !== void 0) {
|
|
567
|
-
session.advertisedSessionId = sessionId;
|
|
568
|
-
}
|
|
569
|
-
if (handshakingConn !== void 0) {
|
|
570
|
-
session.replaceWithNewHandshakingConnection(handshakingConn);
|
|
571
|
-
}
|
|
572
|
-
return { session, isReconnect, isTransparentReconnect };
|
|
573
|
-
}
|
|
574
|
-
deleteSession({
|
|
575
|
-
session,
|
|
576
|
-
closeHandshakingConnection,
|
|
577
|
-
handshakingConn
|
|
578
|
-
}) {
|
|
579
|
-
if (closeHandshakingConnection) {
|
|
580
|
-
session.closeHandshakingConnection(handshakingConn);
|
|
581
|
-
}
|
|
582
|
-
session.close();
|
|
583
|
-
session.telemetry.span.end();
|
|
584
|
-
this.sessions.delete(session.to);
|
|
585
|
-
this.log?.info(
|
|
586
|
-
`session ${session.id} disconnect from ${session.to}`,
|
|
587
|
-
session.loggingMetadata
|
|
588
|
-
);
|
|
589
|
-
this.eventDispatcher.dispatchEvent("sessionStatus", {
|
|
590
|
-
status: "disconnect",
|
|
591
|
-
session
|
|
592
|
-
});
|
|
593
|
-
}
|
|
594
|
-
/**
|
|
595
|
-
* The downstream implementation needs to call this when a connection is closed.
|
|
596
|
-
* @param conn The connection object.
|
|
597
|
-
* @param connectedTo The peer we are connected to.
|
|
598
|
-
*/
|
|
599
|
-
onDisconnect(conn, session) {
|
|
600
|
-
conn.telemetry?.span.end();
|
|
601
|
-
this.eventDispatcher.dispatchEvent("connectionStatus", {
|
|
602
|
-
status: "disconnect",
|
|
603
|
-
conn
|
|
604
|
-
});
|
|
605
|
-
session.connection = void 0;
|
|
606
|
-
session.beginGrace(() => {
|
|
607
|
-
session.telemetry.span.addEvent("session grace period expired");
|
|
608
|
-
this.deleteSession({
|
|
609
|
-
session,
|
|
610
|
-
closeHandshakingConnection: true,
|
|
611
|
-
handshakingConn: conn
|
|
612
|
-
});
|
|
613
|
-
});
|
|
614
|
-
}
|
|
615
|
-
/**
|
|
616
|
-
* Parses a message from a Uint8Array into a {@link OpaqueTransportMessage}.
|
|
617
|
-
* @param msg The message to parse.
|
|
618
|
-
* @returns The parsed message, or null if the message is malformed or invalid.
|
|
619
|
-
*/
|
|
620
|
-
parseMsg(msg, conn) {
|
|
621
|
-
const parsedMsg = this.codec.fromBuffer(msg);
|
|
622
|
-
if (parsedMsg === null) {
|
|
623
|
-
const decodedBuffer = new TextDecoder().decode(Buffer.from(msg));
|
|
624
|
-
this.log?.error(
|
|
625
|
-
`received malformed msg, killing conn: ${decodedBuffer}`,
|
|
626
|
-
{
|
|
627
|
-
clientId: this.clientId,
|
|
628
|
-
...conn.loggingMetadata
|
|
629
|
-
}
|
|
630
|
-
);
|
|
631
|
-
return null;
|
|
632
|
-
}
|
|
633
|
-
if (!Value.Check(OpaqueTransportMessageSchema, parsedMsg)) {
|
|
634
|
-
this.log?.error(`received invalid msg: ${JSON.stringify(parsedMsg)}`, {
|
|
635
|
-
clientId: this.clientId,
|
|
636
|
-
...conn.loggingMetadata,
|
|
637
|
-
validationErrors: [
|
|
638
|
-
...Value.Errors(OpaqueTransportMessageSchema, parsedMsg)
|
|
639
|
-
]
|
|
640
|
-
});
|
|
641
|
-
return null;
|
|
642
|
-
}
|
|
643
|
-
return parsedMsg;
|
|
644
|
-
}
|
|
645
|
-
/**
|
|
646
|
-
* Called when a message is received by this transport.
|
|
647
|
-
* You generally shouldn't need to override this in downstream transport implementations.
|
|
648
|
-
* @param msg The received message.
|
|
649
|
-
*/
|
|
650
|
-
handleMsg(msg, conn) {
|
|
651
|
-
if (this.getStatus() !== "open")
|
|
652
|
-
return;
|
|
653
|
-
const session = this.sessions.get(msg.from);
|
|
654
|
-
if (!session) {
|
|
655
|
-
this.log?.error(`received message for unknown session from ${msg.from}`, {
|
|
656
|
-
clientId: this.clientId,
|
|
657
|
-
transportMessage: msg,
|
|
658
|
-
...conn.loggingMetadata,
|
|
659
|
-
tags: ["invariant-violation"]
|
|
660
|
-
});
|
|
661
|
-
return;
|
|
662
|
-
}
|
|
663
|
-
session.cancelGrace();
|
|
664
|
-
this.log?.debug(`received msg`, {
|
|
665
|
-
clientId: this.clientId,
|
|
666
|
-
transportMessage: msg,
|
|
667
|
-
...conn.loggingMetadata
|
|
668
|
-
});
|
|
669
|
-
if (msg.seq !== session.nextExpectedSeq) {
|
|
670
|
-
if (msg.seq < session.nextExpectedSeq) {
|
|
671
|
-
this.log?.debug(
|
|
672
|
-
`received duplicate msg (got seq: ${msg.seq}, wanted seq: ${session.nextExpectedSeq}), discarding`,
|
|
673
|
-
{
|
|
674
|
-
clientId: this.clientId,
|
|
675
|
-
transportMessage: msg,
|
|
676
|
-
...conn.loggingMetadata
|
|
677
|
-
}
|
|
678
|
-
);
|
|
679
|
-
} else {
|
|
680
|
-
const errMsg = `received out-of-order msg (got seq: ${msg.seq}, wanted seq: ${session.nextExpectedSeq})`;
|
|
681
|
-
this.log?.error(`${errMsg}, marking connection as dead`, {
|
|
682
|
-
clientId: this.clientId,
|
|
683
|
-
transportMessage: msg,
|
|
684
|
-
...conn.loggingMetadata,
|
|
685
|
-
tags: ["invariant-violation"]
|
|
686
|
-
});
|
|
687
|
-
this.protocolError(ProtocolError.MessageOrderingViolated, errMsg);
|
|
688
|
-
session.telemetry.span.setStatus({
|
|
689
|
-
code: SpanStatusCode2.ERROR,
|
|
690
|
-
message: "message order violated"
|
|
691
|
-
});
|
|
692
|
-
this.deleteSession({ session, closeHandshakingConnection: true });
|
|
693
|
-
}
|
|
694
|
-
return;
|
|
695
|
-
}
|
|
696
|
-
session.updateBookkeeping(msg.ack, msg.seq);
|
|
697
|
-
if (!isAck(msg.controlFlags)) {
|
|
698
|
-
this.eventDispatcher.dispatchEvent("message", msg);
|
|
699
|
-
} else {
|
|
700
|
-
this.log?.debug(`discarding msg (ack bit set)`, {
|
|
701
|
-
clientId: this.clientId,
|
|
702
|
-
transportMessage: msg,
|
|
703
|
-
...conn.loggingMetadata
|
|
704
|
-
});
|
|
705
|
-
}
|
|
706
|
-
}
|
|
707
|
-
/**
|
|
708
|
-
* Adds a listener to this transport.
|
|
709
|
-
* @param the type of event to listen for
|
|
710
|
-
* @param handler The message handler to add.
|
|
711
|
-
*/
|
|
712
|
-
addEventListener(type, handler) {
|
|
713
|
-
this.eventDispatcher.addEventListener(type, handler);
|
|
714
|
-
}
|
|
715
|
-
/**
|
|
716
|
-
* Removes a listener from this transport.
|
|
717
|
-
* @param the type of event to un-listen on
|
|
718
|
-
* @param handler The message handler to remove.
|
|
719
|
-
*/
|
|
720
|
-
removeEventListener(type, handler) {
|
|
721
|
-
this.eventDispatcher.removeEventListener(type, handler);
|
|
722
|
-
}
|
|
723
|
-
/**
|
|
724
|
-
* Sends a message over this transport, delegating to the appropriate connection to actually
|
|
725
|
-
* send the message.
|
|
726
|
-
* @param msg The message to send.
|
|
727
|
-
* @returns The ID of the sent message or undefined if it wasn't sent
|
|
728
|
-
*/
|
|
729
|
-
send(to, msg) {
|
|
730
|
-
if (this.getStatus() === "closed") {
|
|
731
|
-
const err = "transport is closed, cant send";
|
|
732
|
-
this.log?.error(err, {
|
|
733
|
-
clientId: this.clientId,
|
|
734
|
-
transportMessage: msg,
|
|
735
|
-
tags: ["invariant-violation"]
|
|
736
|
-
});
|
|
737
|
-
throw new Error(err);
|
|
738
|
-
}
|
|
739
|
-
return this.getOrCreateSession({ to }).session.send(msg);
|
|
740
|
-
}
|
|
741
|
-
// control helpers
|
|
742
|
-
sendCloseStream(to, streamId) {
|
|
743
|
-
return this.send(to, {
|
|
744
|
-
streamId,
|
|
745
|
-
controlFlags: 4 /* StreamClosedBit */,
|
|
746
|
-
payload: {
|
|
747
|
-
type: "CLOSE"
|
|
748
|
-
}
|
|
749
|
-
});
|
|
750
|
-
}
|
|
751
|
-
protocolError(type, message) {
|
|
752
|
-
this.eventDispatcher.dispatchEvent("protocolError", { type, message });
|
|
753
|
-
}
|
|
754
|
-
/**
|
|
755
|
-
* Default close implementation for transports. You should override this in the downstream
|
|
756
|
-
* implementation if you need to do any additional cleanup and call super.close() at the end.
|
|
757
|
-
* Closes the transport. Any messages sent while the transport is closed will be silently discarded.
|
|
758
|
-
*/
|
|
759
|
-
close() {
|
|
760
|
-
this.status = "closed";
|
|
761
|
-
for (const session of this.sessions.values()) {
|
|
762
|
-
this.deleteSession({ session, closeHandshakingConnection: true });
|
|
763
|
-
}
|
|
764
|
-
this.eventDispatcher.dispatchEvent("transportStatus", {
|
|
765
|
-
status: this.status
|
|
766
|
-
});
|
|
767
|
-
this.eventDispatcher.removeAllListeners();
|
|
768
|
-
this.log?.info(`manually closed transport`, { clientId: this.clientId });
|
|
769
|
-
}
|
|
770
|
-
getStatus() {
|
|
771
|
-
return this.status;
|
|
772
|
-
}
|
|
773
|
-
};
|
|
774
|
-
var ClientTransport = class extends Transport {
|
|
775
|
-
/**
|
|
776
|
-
* The options for this transport.
|
|
777
|
-
*/
|
|
778
|
-
options;
|
|
779
|
-
/**
|
|
780
|
-
* The map of reconnect promises for each client ID.
|
|
781
|
-
*/
|
|
782
|
-
inflightConnectionPromises;
|
|
783
|
-
retryBudget;
|
|
784
|
-
/**
|
|
785
|
-
* A flag indicating whether the transport should automatically reconnect
|
|
786
|
-
* when a connection is dropped.
|
|
787
|
-
* Realistically, this should always be true for clients unless you are writing
|
|
788
|
-
* tests or a special case where you don't want to reconnect.
|
|
789
|
-
*/
|
|
790
|
-
reconnectOnConnectionDrop = true;
|
|
791
|
-
/**
|
|
792
|
-
* Optional handshake options for this client.
|
|
793
|
-
*/
|
|
794
|
-
handshakeExtensions;
|
|
795
|
-
constructor(clientId, providedOptions) {
|
|
796
|
-
super(clientId, providedOptions);
|
|
797
|
-
this.options = {
|
|
798
|
-
...defaultClientTransportOptions,
|
|
799
|
-
...providedOptions
|
|
800
|
-
};
|
|
801
|
-
this.inflightConnectionPromises = /* @__PURE__ */ new Map();
|
|
802
|
-
this.retryBudget = new LeakyBucketRateLimit(this.options);
|
|
803
|
-
}
|
|
804
|
-
extendHandshake(options) {
|
|
805
|
-
this.handshakeExtensions = options;
|
|
806
|
-
}
|
|
807
|
-
handleConnection(conn, to) {
|
|
808
|
-
if (this.getStatus() !== "open")
|
|
809
|
-
return;
|
|
810
|
-
let session = void 0;
|
|
811
|
-
const handshakeTimeout = setTimeout(() => {
|
|
812
|
-
if (session)
|
|
813
|
-
return;
|
|
814
|
-
this.log?.warn(
|
|
815
|
-
`connection to ${to} timed out waiting for handshake, closing`,
|
|
816
|
-
{ ...conn.loggingMetadata, clientId: this.clientId, connectedTo: to }
|
|
817
|
-
);
|
|
818
|
-
conn.close();
|
|
819
|
-
}, this.options.sessionDisconnectGraceMs);
|
|
820
|
-
const handshakeHandler = (data) => {
|
|
821
|
-
const maybeSession = this.receiveHandshakeResponseMessage(data, conn);
|
|
822
|
-
clearTimeout(handshakeTimeout);
|
|
823
|
-
if (!maybeSession) {
|
|
824
|
-
conn.close();
|
|
825
|
-
return;
|
|
826
|
-
} else {
|
|
827
|
-
session = maybeSession;
|
|
828
|
-
}
|
|
829
|
-
conn.removeDataListener(handshakeHandler);
|
|
830
|
-
conn.addDataListener((data2) => {
|
|
831
|
-
const parsed = this.parseMsg(data2, conn);
|
|
832
|
-
if (!parsed) {
|
|
833
|
-
conn.telemetry?.span.setStatus({
|
|
834
|
-
code: SpanStatusCode2.ERROR,
|
|
835
|
-
message: "message parse failure"
|
|
836
|
-
});
|
|
837
|
-
conn.close();
|
|
838
|
-
return;
|
|
839
|
-
}
|
|
840
|
-
this.handleMsg(parsed, conn);
|
|
841
|
-
});
|
|
842
|
-
};
|
|
843
|
-
conn.addDataListener(handshakeHandler);
|
|
844
|
-
conn.addCloseListener(() => {
|
|
845
|
-
if (session) {
|
|
846
|
-
this.onDisconnect(conn, session);
|
|
847
|
-
}
|
|
848
|
-
const willReconnect = this.reconnectOnConnectionDrop && this.getStatus() === "open";
|
|
849
|
-
this.log?.info(
|
|
850
|
-
`connection to ${to} disconnected` + (willReconnect ? ", reconnecting" : ""),
|
|
851
|
-
{
|
|
852
|
-
...conn.loggingMetadata,
|
|
853
|
-
...session?.loggingMetadata,
|
|
854
|
-
clientId: this.clientId,
|
|
855
|
-
connectedTo: to
|
|
856
|
-
}
|
|
857
|
-
);
|
|
858
|
-
this.inflightConnectionPromises.delete(to);
|
|
859
|
-
if (this.reconnectOnConnectionDrop) {
|
|
860
|
-
void this.connect(to);
|
|
861
|
-
}
|
|
862
|
-
});
|
|
863
|
-
conn.addErrorListener((err) => {
|
|
864
|
-
conn.telemetry?.span.setStatus({
|
|
865
|
-
code: SpanStatusCode2.ERROR,
|
|
866
|
-
message: "connection error"
|
|
867
|
-
});
|
|
868
|
-
this.log?.warn(
|
|
869
|
-
`error in connection to ${to}: ${coerceErrorString(err)}`,
|
|
870
|
-
{
|
|
871
|
-
...conn.loggingMetadata,
|
|
872
|
-
...session?.loggingMetadata,
|
|
873
|
-
clientId: this.clientId,
|
|
874
|
-
connectedTo: to
|
|
875
|
-
}
|
|
876
|
-
);
|
|
877
|
-
});
|
|
878
|
-
}
|
|
879
|
-
receiveHandshakeResponseMessage(data, conn) {
|
|
880
|
-
const parsed = this.parseMsg(data, conn);
|
|
881
|
-
if (!parsed) {
|
|
882
|
-
conn.telemetry?.span.setStatus({
|
|
883
|
-
code: SpanStatusCode2.ERROR,
|
|
884
|
-
message: "non-transport message"
|
|
885
|
-
});
|
|
886
|
-
this.protocolError(
|
|
887
|
-
ProtocolError.HandshakeFailed,
|
|
888
|
-
"received non-transport message"
|
|
889
|
-
);
|
|
890
|
-
return false;
|
|
891
|
-
}
|
|
892
|
-
if (!Value.Check(ControlMessageHandshakeResponseSchema, parsed.payload)) {
|
|
893
|
-
conn.telemetry?.span.setStatus({
|
|
894
|
-
code: SpanStatusCode2.ERROR,
|
|
895
|
-
message: "invalid handshake response"
|
|
896
|
-
});
|
|
897
|
-
this.log?.warn(`received invalid handshake resp`, {
|
|
898
|
-
...conn.loggingMetadata,
|
|
899
|
-
clientId: this.clientId,
|
|
900
|
-
connectedTo: parsed.from,
|
|
901
|
-
transportMessage: parsed,
|
|
902
|
-
validationErrors: [
|
|
903
|
-
...Value.Errors(
|
|
904
|
-
ControlMessageHandshakeResponseSchema,
|
|
905
|
-
parsed.payload
|
|
906
|
-
)
|
|
907
|
-
]
|
|
908
|
-
});
|
|
909
|
-
this.protocolError(
|
|
910
|
-
ProtocolError.HandshakeFailed,
|
|
911
|
-
"invalid handshake resp"
|
|
912
|
-
);
|
|
913
|
-
return false;
|
|
914
|
-
}
|
|
915
|
-
if (!parsed.payload.status.ok) {
|
|
916
|
-
conn.telemetry?.span.setStatus({
|
|
917
|
-
code: SpanStatusCode2.ERROR,
|
|
918
|
-
message: "handshake rejected"
|
|
919
|
-
});
|
|
920
|
-
this.log?.warn(`received handshake rejection`, {
|
|
921
|
-
...conn.loggingMetadata,
|
|
922
|
-
clientId: this.clientId,
|
|
923
|
-
connectedTo: parsed.from,
|
|
924
|
-
transportMessage: parsed
|
|
925
|
-
});
|
|
926
|
-
this.protocolError(
|
|
927
|
-
ProtocolError.HandshakeFailed,
|
|
928
|
-
parsed.payload.status.reason
|
|
929
|
-
);
|
|
930
|
-
return false;
|
|
931
|
-
}
|
|
932
|
-
const previousSession = this.sessions.get(parsed.from);
|
|
933
|
-
if (previousSession?.advertisedSessionId && previousSession.advertisedSessionId !== parsed.payload.status.sessionId) {
|
|
934
|
-
this.deleteSession({
|
|
935
|
-
session: previousSession,
|
|
936
|
-
closeHandshakingConnection: true
|
|
937
|
-
});
|
|
938
|
-
conn.telemetry?.span.setStatus({
|
|
939
|
-
code: SpanStatusCode2.ERROR,
|
|
940
|
-
message: "session id mismatch"
|
|
941
|
-
});
|
|
942
|
-
this.log?.warn(`handshake from ${parsed.from} session id mismatch`, {
|
|
943
|
-
...conn.loggingMetadata,
|
|
944
|
-
clientId: this.clientId,
|
|
945
|
-
connectedTo: parsed.from,
|
|
946
|
-
transportMessage: parsed
|
|
947
|
-
});
|
|
948
|
-
this.protocolError(ProtocolError.HandshakeFailed, "session id mismatch");
|
|
949
|
-
return false;
|
|
950
|
-
}
|
|
951
|
-
this.log?.debug(`handshake from ${parsed.from} ok`, {
|
|
952
|
-
...conn.loggingMetadata,
|
|
953
|
-
clientId: this.clientId,
|
|
954
|
-
connectedTo: parsed.from,
|
|
955
|
-
transportMessage: parsed
|
|
956
|
-
});
|
|
957
|
-
const { session, isTransparentReconnect } = this.getOrCreateSession({
|
|
958
|
-
to: parsed.from,
|
|
959
|
-
conn,
|
|
960
|
-
sessionId: parsed.payload.status.sessionId
|
|
961
|
-
});
|
|
962
|
-
this.onConnect(conn, session, isTransparentReconnect);
|
|
963
|
-
this.retryBudget.startRestoringBudget(session.to);
|
|
964
|
-
return session;
|
|
965
|
-
}
|
|
966
|
-
/**
|
|
967
|
-
* Manually attempts to connect to a client.
|
|
968
|
-
* @param to The client ID of the node to connect to.
|
|
969
|
-
*/
|
|
970
|
-
async connect(to) {
|
|
971
|
-
if (this.connections.has(to)) {
|
|
972
|
-
this.log?.info(`already connected to ${to}, skipping connect attempt`, {
|
|
973
|
-
clientId: this.clientId,
|
|
974
|
-
connectedTo: to
|
|
975
|
-
});
|
|
976
|
-
return;
|
|
977
|
-
}
|
|
978
|
-
const canProceedWithConnection = () => this.getStatus() === "open";
|
|
979
|
-
if (!canProceedWithConnection()) {
|
|
980
|
-
this.log?.info(
|
|
981
|
-
`transport state is no longer open, cancelling attempt to connect to ${to}`,
|
|
982
|
-
{ clientId: this.clientId, connectedTo: to }
|
|
983
|
-
);
|
|
984
|
-
return;
|
|
985
|
-
}
|
|
986
|
-
let reconnectPromise = this.inflightConnectionPromises.get(to);
|
|
987
|
-
if (!reconnectPromise) {
|
|
988
|
-
if (!this.retryBudget.hasBudget(to)) {
|
|
989
|
-
const budgetConsumed = this.retryBudget.getBudgetConsumed(to);
|
|
990
|
-
const errMsg = `tried to connect to ${to} but retry budget exceeded (more than ${budgetConsumed} attempts in the last ${this.retryBudget.totalBudgetRestoreTime}ms)`;
|
|
991
|
-
this.log?.error(errMsg, { clientId: this.clientId, connectedTo: to });
|
|
992
|
-
this.protocolError(ProtocolError.RetriesExceeded, errMsg);
|
|
993
|
-
return;
|
|
994
|
-
}
|
|
995
|
-
let sleep = Promise.resolve();
|
|
996
|
-
const backoffMs = this.retryBudget.getBackoffMs(to);
|
|
997
|
-
if (backoffMs > 0) {
|
|
998
|
-
sleep = new Promise((resolve) => setTimeout(resolve, backoffMs));
|
|
999
|
-
}
|
|
1000
|
-
this.log?.info(
|
|
1001
|
-
`attempting connection to ${to} (${backoffMs}ms backoff)`,
|
|
1002
|
-
{
|
|
1003
|
-
clientId: this.clientId,
|
|
1004
|
-
connectedTo: to
|
|
1005
|
-
}
|
|
1006
|
-
);
|
|
1007
|
-
this.retryBudget.consumeBudget(to);
|
|
1008
|
-
reconnectPromise = tracing_default.startActiveSpan("connect", async (span) => {
|
|
1009
|
-
try {
|
|
1010
|
-
span.addEvent("backoff", { backoffMs });
|
|
1011
|
-
await sleep;
|
|
1012
|
-
if (!canProceedWithConnection()) {
|
|
1013
|
-
throw new Error("transport state is no longer open");
|
|
1014
|
-
}
|
|
1015
|
-
span.addEvent("connecting");
|
|
1016
|
-
const conn = await this.createNewOutgoingConnection(to);
|
|
1017
|
-
if (!canProceedWithConnection()) {
|
|
1018
|
-
this.log?.info(
|
|
1019
|
-
`transport state is no longer open, closing pre-handshake connection to ${to}`,
|
|
1020
|
-
{
|
|
1021
|
-
...conn.loggingMetadata,
|
|
1022
|
-
clientId: this.clientId,
|
|
1023
|
-
connectedTo: to
|
|
1024
|
-
}
|
|
1025
|
-
);
|
|
1026
|
-
conn.close();
|
|
1027
|
-
throw new Error("transport state is no longer open");
|
|
1028
|
-
}
|
|
1029
|
-
span.addEvent("sending handshake");
|
|
1030
|
-
const ok = await this.sendHandshake(to, conn);
|
|
1031
|
-
if (!ok) {
|
|
1032
|
-
conn.close();
|
|
1033
|
-
throw new Error("failed to send handshake");
|
|
1034
|
-
}
|
|
1035
|
-
return conn;
|
|
1036
|
-
} catch (err) {
|
|
1037
|
-
const errStr = coerceErrorString(err);
|
|
1038
|
-
span.recordException(errStr);
|
|
1039
|
-
span.setStatus({ code: SpanStatusCode2.ERROR });
|
|
1040
|
-
throw err;
|
|
1041
|
-
} finally {
|
|
1042
|
-
span.end();
|
|
1043
|
-
}
|
|
1044
|
-
});
|
|
1045
|
-
this.inflightConnectionPromises.set(to, reconnectPromise);
|
|
1046
|
-
} else {
|
|
1047
|
-
this.log?.info(
|
|
1048
|
-
`attempting connection to ${to} (reusing previous attempt)`,
|
|
1049
|
-
{
|
|
1050
|
-
clientId: this.clientId,
|
|
1051
|
-
connectedTo: to
|
|
1052
|
-
}
|
|
1053
|
-
);
|
|
1054
|
-
}
|
|
1055
|
-
try {
|
|
1056
|
-
await reconnectPromise;
|
|
1057
|
-
} catch (error) {
|
|
1058
|
-
this.inflightConnectionPromises.delete(to);
|
|
1059
|
-
const errStr = coerceErrorString(error);
|
|
1060
|
-
if (!this.reconnectOnConnectionDrop || !canProceedWithConnection()) {
|
|
1061
|
-
this.log?.warn(`connection to ${to} failed (${errStr})`, {
|
|
1062
|
-
clientId: this.clientId,
|
|
1063
|
-
connectedTo: to
|
|
1064
|
-
});
|
|
1065
|
-
} else {
|
|
1066
|
-
this.log?.warn(`connection to ${to} failed (${errStr}), retrying`, {
|
|
1067
|
-
clientId: this.clientId,
|
|
1068
|
-
connectedTo: to
|
|
1069
|
-
});
|
|
1070
|
-
await this.connect(to);
|
|
1071
|
-
}
|
|
1072
|
-
}
|
|
1073
|
-
}
|
|
1074
|
-
deleteSession({
|
|
1075
|
-
session,
|
|
1076
|
-
closeHandshakingConnection,
|
|
1077
|
-
handshakingConn
|
|
1078
|
-
}) {
|
|
1079
|
-
this.inflightConnectionPromises.delete(session.to);
|
|
1080
|
-
super.deleteSession({
|
|
1081
|
-
session,
|
|
1082
|
-
closeHandshakingConnection,
|
|
1083
|
-
handshakingConn
|
|
1084
|
-
});
|
|
1085
|
-
}
|
|
1086
|
-
async sendHandshake(to, conn) {
|
|
1087
|
-
let metadata = void 0;
|
|
1088
|
-
if (this.handshakeExtensions) {
|
|
1089
|
-
metadata = await this.handshakeExtensions.construct();
|
|
1090
|
-
if (!Value.Check(this.handshakeExtensions.schema, metadata)) {
|
|
1091
|
-
this.log?.error(`constructed handshake metadata did not match schema`, {
|
|
1092
|
-
...conn.loggingMetadata,
|
|
1093
|
-
clientId: this.clientId,
|
|
1094
|
-
connectedTo: to,
|
|
1095
|
-
validationErrors: [
|
|
1096
|
-
...Value.Errors(this.handshakeExtensions.schema, metadata)
|
|
1097
|
-
],
|
|
1098
|
-
tags: ["invariant-violation"]
|
|
1099
|
-
});
|
|
1100
|
-
this.protocolError(
|
|
1101
|
-
ProtocolError.HandshakeFailed,
|
|
1102
|
-
"handshake metadata did not match schema"
|
|
1103
|
-
);
|
|
1104
|
-
conn.telemetry?.span.setStatus({
|
|
1105
|
-
code: SpanStatusCode2.ERROR,
|
|
1106
|
-
message: "handshake meta mismatch"
|
|
1107
|
-
});
|
|
1108
|
-
return false;
|
|
1109
|
-
}
|
|
1110
|
-
}
|
|
1111
|
-
const { session } = this.getOrCreateSession({ to, handshakingConn: conn });
|
|
1112
|
-
const requestMsg = handshakeRequestMessage(
|
|
1113
|
-
this.clientId,
|
|
1114
|
-
to,
|
|
1115
|
-
session.id,
|
|
1116
|
-
metadata,
|
|
1117
|
-
getPropagationContext(session.telemetry.ctx)
|
|
1118
|
-
);
|
|
1119
|
-
this.log?.debug(`sending handshake request to ${to}`, {
|
|
1120
|
-
...conn.loggingMetadata,
|
|
1121
|
-
clientId: this.clientId,
|
|
1122
|
-
connectedTo: to,
|
|
1123
|
-
transportMessage: requestMsg
|
|
1124
|
-
});
|
|
1125
|
-
conn.send(this.codec.toBuffer(requestMsg));
|
|
1126
|
-
return true;
|
|
1127
|
-
}
|
|
1128
|
-
close() {
|
|
1129
|
-
this.retryBudget.close();
|
|
1130
|
-
super.close();
|
|
1131
|
-
}
|
|
1132
|
-
};
|
|
1133
|
-
var ServerTransport = class extends Transport {
|
|
1134
|
-
/**
|
|
1135
|
-
* The options for this transport.
|
|
1136
|
-
*/
|
|
1137
|
-
options;
|
|
1138
|
-
/**
|
|
1139
|
-
* Optional handshake options for the server.
|
|
1140
|
-
*/
|
|
1141
|
-
handshakeExtensions;
|
|
1142
|
-
/**
|
|
1143
|
-
* A map of session handshake data for each session.
|
|
1144
|
-
*/
|
|
1145
|
-
sessionHandshakeMetadata;
|
|
1146
|
-
constructor(clientId, providedOptions) {
|
|
1147
|
-
super(clientId, providedOptions);
|
|
1148
|
-
this.options = {
|
|
1149
|
-
...defaultServerTransportOptions,
|
|
1150
|
-
...providedOptions
|
|
1151
|
-
};
|
|
1152
|
-
this.sessionHandshakeMetadata = /* @__PURE__ */ new WeakMap();
|
|
1153
|
-
this.log?.info(`initiated server transport`, {
|
|
1154
|
-
clientId: this.clientId,
|
|
1155
|
-
protocolVersion: PROTOCOL_VERSION
|
|
1156
|
-
});
|
|
1157
|
-
}
|
|
1158
|
-
extendHandshake(options) {
|
|
1159
|
-
this.handshakeExtensions = options;
|
|
1160
|
-
}
|
|
1161
|
-
handleConnection(conn) {
|
|
1162
|
-
if (this.getStatus() !== "open")
|
|
1163
|
-
return;
|
|
1164
|
-
this.log?.info(`new incoming connection`, {
|
|
1165
|
-
...conn.loggingMetadata,
|
|
1166
|
-
clientId: this.clientId
|
|
1167
|
-
});
|
|
1168
|
-
let session = void 0;
|
|
1169
|
-
const client = () => session?.to ?? "unknown";
|
|
1170
|
-
const handshakeTimeout = setTimeout(() => {
|
|
1171
|
-
if (!session) {
|
|
1172
|
-
this.log?.warn(
|
|
1173
|
-
`connection to ${client()} timed out waiting for handshake, closing`,
|
|
1174
|
-
{
|
|
1175
|
-
...conn.loggingMetadata,
|
|
1176
|
-
clientId: this.clientId,
|
|
1177
|
-
connectedTo: client()
|
|
1178
|
-
}
|
|
1179
|
-
);
|
|
1180
|
-
conn.telemetry?.span.setStatus({
|
|
1181
|
-
code: SpanStatusCode2.ERROR,
|
|
1182
|
-
message: "handshake timeout"
|
|
1183
|
-
});
|
|
1184
|
-
conn.close();
|
|
1185
|
-
}
|
|
1186
|
-
}, this.options.sessionDisconnectGraceMs);
|
|
1187
|
-
const buffer = [];
|
|
1188
|
-
let receivedHandshakeMessage = false;
|
|
1189
|
-
const handshakeHandler = (data) => {
|
|
1190
|
-
if (receivedHandshakeMessage) {
|
|
1191
|
-
buffer.push(data);
|
|
1192
|
-
return;
|
|
1193
|
-
}
|
|
1194
|
-
receivedHandshakeMessage = true;
|
|
1195
|
-
clearTimeout(handshakeTimeout);
|
|
1196
|
-
void this.receiveHandshakeRequestMessage(data, conn).then(
|
|
1197
|
-
(maybeSession) => {
|
|
1198
|
-
if (!maybeSession) {
|
|
1199
|
-
conn.close();
|
|
1200
|
-
return;
|
|
1201
|
-
}
|
|
1202
|
-
session = maybeSession;
|
|
1203
|
-
const dataHandler = (data2) => {
|
|
1204
|
-
const parsed = this.parseMsg(data2, conn);
|
|
1205
|
-
if (!parsed) {
|
|
1206
|
-
conn.close();
|
|
1207
|
-
return;
|
|
1208
|
-
}
|
|
1209
|
-
this.handleMsg(parsed, conn);
|
|
1210
|
-
};
|
|
1211
|
-
for (const data2 of buffer) {
|
|
1212
|
-
dataHandler(data2);
|
|
1213
|
-
}
|
|
1214
|
-
conn.removeDataListener(handshakeHandler);
|
|
1215
|
-
conn.addDataListener(dataHandler);
|
|
1216
|
-
buffer.length = 0;
|
|
1217
|
-
}
|
|
1218
|
-
);
|
|
1219
|
-
};
|
|
1220
|
-
conn.addDataListener(handshakeHandler);
|
|
1221
|
-
conn.addCloseListener(() => {
|
|
1222
|
-
if (!session)
|
|
1223
|
-
return;
|
|
1224
|
-
this.log?.info(`connection to ${client()} disconnected`, {
|
|
1225
|
-
...conn.loggingMetadata,
|
|
1226
|
-
clientId: this.clientId
|
|
1227
|
-
});
|
|
1228
|
-
this.onDisconnect(conn, session);
|
|
1229
|
-
});
|
|
1230
|
-
conn.addErrorListener((err) => {
|
|
1231
|
-
conn.telemetry?.span.setStatus({
|
|
1232
|
-
code: SpanStatusCode2.ERROR,
|
|
1233
|
-
message: "connection error"
|
|
1234
|
-
});
|
|
1235
|
-
if (!session)
|
|
1236
|
-
return;
|
|
1237
|
-
this.log?.warn(
|
|
1238
|
-
`connection to ${client()} got an error: ${coerceErrorString(err)}`,
|
|
1239
|
-
{ ...conn.loggingMetadata, clientId: this.clientId }
|
|
1240
|
-
);
|
|
1241
|
-
});
|
|
1242
|
-
}
|
|
1243
|
-
async validateHandshakeMetadata(conn, session, rawMetadata, from) {
|
|
1244
|
-
let parsedMetadata = {};
|
|
1245
|
-
if (this.handshakeExtensions) {
|
|
1246
|
-
if (!Value.Check(this.handshakeExtensions.schema, rawMetadata)) {
|
|
1247
|
-
conn.telemetry?.span.setStatus({
|
|
1248
|
-
code: SpanStatusCode2.ERROR,
|
|
1249
|
-
message: "malformed handshake meta"
|
|
1250
|
-
});
|
|
1251
|
-
const reason = "received malformed handshake metadata";
|
|
1252
|
-
const responseMsg = handshakeResponseMessage(this.clientId, from, {
|
|
1253
|
-
ok: false,
|
|
1254
|
-
reason
|
|
1255
|
-
});
|
|
1256
|
-
conn.send(this.codec.toBuffer(responseMsg));
|
|
1257
|
-
this.log?.warn(`received malformed handshake metadata from ${from}`, {
|
|
1258
|
-
...conn.loggingMetadata,
|
|
1259
|
-
clientId: this.clientId,
|
|
1260
|
-
validationErrors: [
|
|
1261
|
-
...Value.Errors(this.handshakeExtensions.schema, rawMetadata)
|
|
1262
|
-
]
|
|
1263
|
-
});
|
|
1264
|
-
this.protocolError(ProtocolError.HandshakeFailed, reason);
|
|
1265
|
-
return false;
|
|
1266
|
-
}
|
|
1267
|
-
const previousParsedMetadata = session ? this.sessionHandshakeMetadata.get(session) : void 0;
|
|
1268
|
-
parsedMetadata = await this.handshakeExtensions.validate(
|
|
1269
|
-
rawMetadata,
|
|
1270
|
-
previousParsedMetadata
|
|
1271
|
-
);
|
|
1272
|
-
if (parsedMetadata === false) {
|
|
1273
|
-
const reason = "rejected by handshake handler";
|
|
1274
|
-
conn.telemetry?.span.setStatus({
|
|
1275
|
-
code: SpanStatusCode2.ERROR,
|
|
1276
|
-
message: reason
|
|
1277
|
-
});
|
|
1278
|
-
const responseMsg = handshakeResponseMessage(this.clientId, from, {
|
|
1279
|
-
ok: false,
|
|
1280
|
-
reason
|
|
1281
|
-
});
|
|
1282
|
-
conn.send(this.codec.toBuffer(responseMsg));
|
|
1283
|
-
this.log?.warn(`rejected handshake from ${from}`, {
|
|
1284
|
-
...conn.loggingMetadata,
|
|
1285
|
-
clientId: this.clientId
|
|
1286
|
-
});
|
|
1287
|
-
this.protocolError(ProtocolError.HandshakeFailed, reason);
|
|
1288
|
-
return false;
|
|
1289
|
-
}
|
|
1290
|
-
}
|
|
1291
|
-
return parsedMetadata;
|
|
1292
|
-
}
|
|
1293
|
-
async receiveHandshakeRequestMessage(data, conn) {
|
|
1294
|
-
const parsed = this.parseMsg(data, conn);
|
|
1295
|
-
if (!parsed) {
|
|
1296
|
-
conn.telemetry?.span.setStatus({
|
|
1297
|
-
code: SpanStatusCode2.ERROR,
|
|
1298
|
-
message: "non-transport message"
|
|
1299
|
-
});
|
|
1300
|
-
this.protocolError(
|
|
1301
|
-
ProtocolError.HandshakeFailed,
|
|
1302
|
-
"received non-transport message"
|
|
1303
|
-
);
|
|
1304
|
-
return false;
|
|
1305
|
-
}
|
|
1306
|
-
if (!Value.Check(ControlMessageHandshakeRequestSchema, parsed.payload)) {
|
|
1307
|
-
conn.telemetry?.span.setStatus({
|
|
1308
|
-
code: SpanStatusCode2.ERROR,
|
|
1309
|
-
message: "invalid handshake request"
|
|
1310
|
-
});
|
|
1311
|
-
const reason = "received invalid handshake msg";
|
|
1312
|
-
const responseMsg2 = handshakeResponseMessage(this.clientId, parsed.from, {
|
|
1313
|
-
ok: false,
|
|
1314
|
-
reason
|
|
1315
|
-
});
|
|
1316
|
-
conn.send(this.codec.toBuffer(responseMsg2));
|
|
1317
|
-
this.log?.warn(reason, {
|
|
1318
|
-
...conn.loggingMetadata,
|
|
1319
|
-
clientId: this.clientId,
|
|
1320
|
-
// safe to this.log metadata here as we remove the payload
|
|
1321
|
-
// before passing it to user-land
|
|
1322
|
-
transportMessage: parsed,
|
|
1323
|
-
validationErrors: [
|
|
1324
|
-
...Value.Errors(ControlMessageHandshakeRequestSchema, parsed.payload)
|
|
1325
|
-
]
|
|
1326
|
-
});
|
|
1327
|
-
this.protocolError(
|
|
1328
|
-
ProtocolError.HandshakeFailed,
|
|
1329
|
-
"invalid handshake request"
|
|
1330
|
-
);
|
|
1331
|
-
return false;
|
|
1332
|
-
}
|
|
1333
|
-
const gotVersion = parsed.payload.protocolVersion;
|
|
1334
|
-
if (gotVersion !== PROTOCOL_VERSION) {
|
|
1335
|
-
conn.telemetry?.span.setStatus({
|
|
1336
|
-
code: SpanStatusCode2.ERROR,
|
|
1337
|
-
message: "incorrect protocol version"
|
|
1338
|
-
});
|
|
1339
|
-
const reason = `incorrect version (got: ${gotVersion} wanted ${PROTOCOL_VERSION})`;
|
|
1340
|
-
const responseMsg2 = handshakeResponseMessage(this.clientId, parsed.from, {
|
|
1341
|
-
ok: false,
|
|
1342
|
-
reason
|
|
1343
|
-
});
|
|
1344
|
-
conn.send(this.codec.toBuffer(responseMsg2));
|
|
1345
|
-
this.log?.warn(
|
|
1346
|
-
`received handshake msg with incompatible protocol version (got: ${gotVersion}, expected: ${PROTOCOL_VERSION})`,
|
|
1347
|
-
{ ...conn.loggingMetadata, clientId: this.clientId }
|
|
1348
|
-
);
|
|
1349
|
-
this.protocolError(ProtocolError.HandshakeFailed, reason);
|
|
1350
|
-
return false;
|
|
1351
|
-
}
|
|
1352
|
-
const oldSession = this.sessions.get(parsed.from);
|
|
1353
|
-
const parsedMetadata = await this.validateHandshakeMetadata(
|
|
1354
|
-
conn,
|
|
1355
|
-
oldSession,
|
|
1356
|
-
parsed.payload.metadata,
|
|
1357
|
-
parsed.from
|
|
1358
|
-
);
|
|
1359
|
-
if (parsedMetadata === false) {
|
|
1360
|
-
return false;
|
|
1361
|
-
}
|
|
1362
|
-
const { session, isTransparentReconnect } = this.getOrCreateSession({
|
|
1363
|
-
to: parsed.from,
|
|
1364
|
-
conn,
|
|
1365
|
-
sessionId: parsed.payload.sessionId,
|
|
1366
|
-
propagationCtx: parsed.tracing
|
|
1367
|
-
});
|
|
1368
|
-
this.sessionHandshakeMetadata.set(session, parsedMetadata);
|
|
1369
|
-
this.log?.debug(
|
|
1370
|
-
`handshake from ${parsed.from} ok, responding with handshake success`,
|
|
1371
|
-
conn.loggingMetadata
|
|
1372
|
-
);
|
|
1373
|
-
const responseMsg = handshakeResponseMessage(this.clientId, parsed.from, {
|
|
1374
|
-
ok: true,
|
|
1375
|
-
sessionId: session.id
|
|
1376
|
-
});
|
|
1377
|
-
conn.send(this.codec.toBuffer(responseMsg));
|
|
1378
|
-
this.onConnect(conn, session, isTransparentReconnect);
|
|
1379
|
-
return session;
|
|
1380
|
-
}
|
|
1381
|
-
};
|
|
1382
|
-
|
|
1383
|
-
export {
|
|
1384
|
-
Connection,
|
|
1385
|
-
Session,
|
|
1386
|
-
ProtocolError,
|
|
1387
|
-
defaultTransportOptions,
|
|
1388
|
-
Transport,
|
|
1389
|
-
ClientTransport,
|
|
1390
|
-
ServerTransport
|
|
1391
|
-
};
|
|
1392
|
-
//# sourceMappingURL=chunk-VRU4IKRT.js.map
|