@replit/river 0.207.2 → 0.208.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/dist/adapter-ChksXKVN.d.ts +46 -0
- package/dist/adapter-Cuc4JtfV.d.cts +46 -0
- package/dist/chunk-2JNVDUMN.js +2238 -0
- package/dist/chunk-2JNVDUMN.js.map +1 -0
- package/dist/{chunk-4HE7UYRL.js → chunk-DKW3GC3M.js} +6 -5
- package/dist/{chunk-4HE7UYRL.js.map → chunk-DKW3GC3M.js.map} +1 -1
- package/dist/{chunk-46IVOKJU.js → chunk-ETZAHFGQ.js} +80 -61
- package/dist/chunk-ETZAHFGQ.js.map +1 -0
- package/dist/codec/index.cjs +157 -23
- package/dist/codec/index.cjs.map +1 -1
- package/dist/codec/index.d.cts +5 -1
- package/dist/codec/index.d.ts +5 -1
- package/dist/codec/index.js +6 -20
- package/dist/codec/index.js.map +1 -1
- package/dist/connection-BF4zg6Qv.d.cts +35 -0
- package/dist/{connection-a18e31d5.d.ts → connection-Donr3JRB.d.ts} +4 -3
- package/dist/index-C9tpZjBN.d.cts +37 -0
- package/dist/index-D8IOd3LG.d.ts +37 -0
- package/dist/logging/index.d.cts +2 -1
- package/dist/logging/index.d.ts +2 -1
- package/dist/{message-ffacb98a.d.ts → message-Di94OL80.d.cts} +1 -35
- package/dist/message-Di94OL80.d.ts +108 -0
- package/dist/router/index.cjs +62 -43
- package/dist/router/index.cjs.map +1 -1
- package/dist/router/index.d.cts +27 -7
- package/dist/router/index.d.ts +27 -7
- package/dist/router/index.js +1 -1
- package/dist/testUtil/index.cjs +828 -725
- package/dist/testUtil/index.cjs.map +1 -1
- package/dist/testUtil/index.d.cts +5 -4
- package/dist/testUtil/index.d.ts +5 -4
- package/dist/testUtil/index.js +23 -25
- package/dist/testUtil/index.js.map +1 -1
- package/dist/transport/impls/ws/client.cjs +293 -233
- 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 +5 -7
- package/dist/transport/impls/ws/client.js.map +1 -1
- package/dist/transport/impls/ws/server.cjs +269 -200
- package/dist/transport/impls/ws/server.cjs.map +1 -1
- package/dist/transport/impls/ws/server.d.cts +6 -5
- package/dist/transport/impls/ws/server.d.ts +6 -5
- package/dist/transport/impls/ws/server.js +5 -7
- package/dist/transport/impls/ws/server.js.map +1 -1
- package/dist/transport/index.cjs +438 -342
- package/dist/transport/index.cjs.map +1 -1
- package/dist/transport/index.d.cts +7 -6
- package/dist/transport/index.d.ts +7 -6
- package/dist/transport/index.js +5 -10
- package/dist/transport-CCaWx1Rb.d.cts +1566 -0
- package/dist/{services-43528f4b.d.ts → transport-CZb3vdB4.d.ts} +294 -293
- package/dist/{wslike-e0b32dd5.d.ts → wslike-Dng9H1C7.d.cts} +1 -1
- package/dist/wslike-Dng9H1C7.d.ts +40 -0
- package/package.json +3 -3
- package/dist/chunk-24EWYOGK.js +0 -1287
- package/dist/chunk-24EWYOGK.js.map +0 -1
- package/dist/chunk-46IVOKJU.js.map +0 -1
- package/dist/chunk-A7RGOVRV.js +0 -438
- package/dist/chunk-A7RGOVRV.js.map +0 -1
- package/dist/chunk-AJGIY2UB.js +0 -56
- package/dist/chunk-AJGIY2UB.js.map +0 -1
- package/dist/chunk-XV4RQ62N.js +0 -377
- package/dist/chunk-XV4RQ62N.js.map +0 -1
- package/dist/types-3e5768ec.d.ts +0 -20
package/dist/testUtil/index.cjs
CHANGED
|
@@ -235,23 +235,20 @@ var NaiveJsonCodec = {
|
|
|
235
235
|
);
|
|
236
236
|
},
|
|
237
237
|
fromBuffer: (buff) => {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
return val;
|
|
246
|
-
}
|
|
238
|
+
const parsed = JSON.parse(
|
|
239
|
+
decoder.decode(buff),
|
|
240
|
+
function reviver(_key, val) {
|
|
241
|
+
if (val?.$t) {
|
|
242
|
+
return base64ToUint8Array(val.$t);
|
|
243
|
+
} else {
|
|
244
|
+
return val;
|
|
247
245
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
} catch {
|
|
253
|
-
return null;
|
|
246
|
+
}
|
|
247
|
+
);
|
|
248
|
+
if (typeof parsed !== "object" || parsed === null) {
|
|
249
|
+
throw new Error("unpacked msg is not an object");
|
|
254
250
|
}
|
|
251
|
+
return parsed;
|
|
255
252
|
}
|
|
256
253
|
};
|
|
257
254
|
|
|
@@ -281,7 +278,6 @@ var defaultServerTransportOptions = {
|
|
|
281
278
|
};
|
|
282
279
|
|
|
283
280
|
// transport/sessionStateMachine/common.ts
|
|
284
|
-
var import_value = require("@sinclair/typebox/value");
|
|
285
281
|
var ERR_CONSUMED = `session state has been consumed and is no longer valid`;
|
|
286
282
|
var StateMachineState = class {
|
|
287
283
|
/*
|
|
@@ -341,34 +337,16 @@ var StateMachineState = class {
|
|
|
341
337
|
var CommonSession = class extends StateMachineState {
|
|
342
338
|
from;
|
|
343
339
|
options;
|
|
340
|
+
codec;
|
|
344
341
|
tracer;
|
|
345
342
|
log;
|
|
346
|
-
constructor({ from, options, log, tracer }) {
|
|
343
|
+
constructor({ from, options, log, tracer, codec }) {
|
|
347
344
|
super();
|
|
348
345
|
this.from = from;
|
|
349
346
|
this.options = options;
|
|
350
347
|
this.log = log;
|
|
351
348
|
this.tracer = tracer;
|
|
352
|
-
|
|
353
|
-
parseMsg(msg) {
|
|
354
|
-
const parsedMsg = this.options.codec.fromBuffer(msg);
|
|
355
|
-
if (parsedMsg === null) {
|
|
356
|
-
this.log?.error(
|
|
357
|
-
`received malformed msg: ${Buffer.from(msg).toString("base64")}`,
|
|
358
|
-
this.loggingMetadata
|
|
359
|
-
);
|
|
360
|
-
return null;
|
|
361
|
-
}
|
|
362
|
-
if (!import_value.Value.Check(OpaqueTransportMessageSchema, parsedMsg)) {
|
|
363
|
-
this.log?.error(`received invalid msg: ${JSON.stringify(parsedMsg)}`, {
|
|
364
|
-
...this.loggingMetadata,
|
|
365
|
-
validationErrors: [
|
|
366
|
-
...import_value.Value.Errors(OpaqueTransportMessageSchema, parsedMsg)
|
|
367
|
-
]
|
|
368
|
-
});
|
|
369
|
-
return null;
|
|
370
|
-
}
|
|
371
|
-
return parsedMsg;
|
|
349
|
+
this.codec = codec;
|
|
372
350
|
}
|
|
373
351
|
};
|
|
374
352
|
var IdentifiedSession = class extends CommonSession {
|
|
@@ -428,9 +406,6 @@ var IdentifiedSession = class extends CommonSession {
|
|
|
428
406
|
return metadata;
|
|
429
407
|
}
|
|
430
408
|
constructMsg(partialMsg) {
|
|
431
|
-
if (this._isConsumed) {
|
|
432
|
-
throw new Error(ERR_CONSUMED);
|
|
433
|
-
}
|
|
434
409
|
const msg = {
|
|
435
410
|
...partialMsg,
|
|
436
411
|
id: generateId(),
|
|
@@ -448,7 +423,10 @@ var IdentifiedSession = class extends CommonSession {
|
|
|
448
423
|
send(msg) {
|
|
449
424
|
const constructedMsg = this.constructMsg(msg);
|
|
450
425
|
this.sendBuffer.push(constructedMsg);
|
|
451
|
-
return
|
|
426
|
+
return {
|
|
427
|
+
ok: true,
|
|
428
|
+
value: constructedMsg.id
|
|
429
|
+
};
|
|
452
430
|
}
|
|
453
431
|
_handleStateExit() {
|
|
454
432
|
}
|
|
@@ -480,6 +458,23 @@ var IdentifiedSessionWithGracePeriod = class extends IdentifiedSession {
|
|
|
480
458
|
super._handleClose();
|
|
481
459
|
}
|
|
482
460
|
};
|
|
461
|
+
function sendMessage(conn, codec, msg) {
|
|
462
|
+
const buff = codec.toBuffer(msg);
|
|
463
|
+
if (!buff.ok) {
|
|
464
|
+
return buff;
|
|
465
|
+
}
|
|
466
|
+
const sent = conn.send(buff.value);
|
|
467
|
+
if (!sent) {
|
|
468
|
+
return {
|
|
469
|
+
ok: false,
|
|
470
|
+
reason: "failed to send message"
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
return {
|
|
474
|
+
ok: true,
|
|
475
|
+
value: msg.id
|
|
476
|
+
};
|
|
477
|
+
}
|
|
483
478
|
|
|
484
479
|
// transport/sessionStateMachine/SessionConnecting.ts
|
|
485
480
|
var SessionConnecting = class extends IdentifiedSessionWithGracePeriod {
|
|
@@ -493,13 +488,11 @@ var SessionConnecting = class extends IdentifiedSessionWithGracePeriod {
|
|
|
493
488
|
this.listeners = props.listeners;
|
|
494
489
|
this.connPromise.then(
|
|
495
490
|
(conn) => {
|
|
496
|
-
if (this._isConsumed)
|
|
497
|
-
return;
|
|
491
|
+
if (this._isConsumed) return;
|
|
498
492
|
this.listeners.onConnectionEstablished(conn);
|
|
499
493
|
},
|
|
500
494
|
(err) => {
|
|
501
|
-
if (this._isConsumed)
|
|
502
|
-
return;
|
|
495
|
+
if (this._isConsumed) return;
|
|
503
496
|
this.listeners.onConnectionFailed(err);
|
|
504
497
|
}
|
|
505
498
|
);
|
|
@@ -532,8 +525,8 @@ var SessionConnecting = class extends IdentifiedSessionWithGracePeriod {
|
|
|
532
525
|
}
|
|
533
526
|
}
|
|
534
527
|
_handleClose() {
|
|
535
|
-
this.bestEffortClose();
|
|
536
528
|
super._handleClose();
|
|
529
|
+
this.bestEffortClose();
|
|
537
530
|
}
|
|
538
531
|
};
|
|
539
532
|
|
|
@@ -560,7 +553,7 @@ function coerceErrorString(err) {
|
|
|
560
553
|
}
|
|
561
554
|
|
|
562
555
|
// package.json
|
|
563
|
-
var version = "0.
|
|
556
|
+
var version = "0.208.0";
|
|
564
557
|
|
|
565
558
|
// tracing/index.ts
|
|
566
559
|
function getPropagationContext(ctx) {
|
|
@@ -574,7 +567,7 @@ function getPropagationContext(ctx) {
|
|
|
574
567
|
function createSessionTelemetryInfo(tracer, sessionId, to, from, propagationCtx) {
|
|
575
568
|
const parentCtx = propagationCtx ? import_api.propagation.extract(import_api.context.active(), propagationCtx) : import_api.context.active();
|
|
576
569
|
const span = tracer.startSpan(
|
|
577
|
-
`river.session
|
|
570
|
+
`river.session`,
|
|
578
571
|
{
|
|
579
572
|
attributes: {
|
|
580
573
|
component: "river",
|
|
@@ -590,7 +583,7 @@ function createSessionTelemetryInfo(tracer, sessionId, to, from, propagationCtx)
|
|
|
590
583
|
}
|
|
591
584
|
function createConnectionTelemetryInfo(tracer, connection, info) {
|
|
592
585
|
const span = tracer.startSpan(
|
|
593
|
-
`connection
|
|
586
|
+
`river.connection`,
|
|
594
587
|
{
|
|
595
588
|
attributes: {
|
|
596
589
|
component: "river",
|
|
@@ -620,9 +613,9 @@ var SessionWaitingForHandshake = class extends CommonSession {
|
|
|
620
613
|
this.handshakeTimeout = setTimeout(() => {
|
|
621
614
|
this.listeners.onHandshakeTimeout();
|
|
622
615
|
}, this.options.handshakeTimeoutMs);
|
|
623
|
-
this.conn.
|
|
624
|
-
this.conn.
|
|
625
|
-
this.conn.
|
|
616
|
+
this.conn.setDataListener(this.onHandshakeData);
|
|
617
|
+
this.conn.setErrorListener(this.listeners.onConnectionErrored);
|
|
618
|
+
this.conn.setCloseListener(this.listeners.onConnectionClosed);
|
|
626
619
|
}
|
|
627
620
|
get loggingMetadata() {
|
|
628
621
|
return {
|
|
@@ -632,23 +625,23 @@ var SessionWaitingForHandshake = class extends CommonSession {
|
|
|
632
625
|
};
|
|
633
626
|
}
|
|
634
627
|
onHandshakeData = (msg) => {
|
|
635
|
-
const
|
|
636
|
-
if (
|
|
628
|
+
const parsedMsgRes = this.codec.fromBuffer(msg);
|
|
629
|
+
if (!parsedMsgRes.ok) {
|
|
637
630
|
this.listeners.onInvalidHandshake(
|
|
638
|
-
|
|
631
|
+
`could not parse handshake message: ${parsedMsgRes.reason}`,
|
|
639
632
|
"MALFORMED_HANDSHAKE"
|
|
640
633
|
);
|
|
641
634
|
return;
|
|
642
635
|
}
|
|
643
|
-
this.listeners.onHandshake(
|
|
636
|
+
this.listeners.onHandshake(parsedMsgRes.value);
|
|
644
637
|
};
|
|
645
638
|
sendHandshake(msg) {
|
|
646
|
-
return this.conn
|
|
639
|
+
return sendMessage(this.conn, this.codec, msg);
|
|
647
640
|
}
|
|
648
641
|
_handleStateExit() {
|
|
649
|
-
this.conn.removeDataListener(
|
|
650
|
-
this.conn.removeErrorListener(
|
|
651
|
-
this.conn.removeCloseListener(
|
|
642
|
+
this.conn.removeDataListener();
|
|
643
|
+
this.conn.removeErrorListener();
|
|
644
|
+
this.conn.removeCloseListener();
|
|
652
645
|
clearTimeout(this.handshakeTimeout);
|
|
653
646
|
this.handshakeTimeout = void 0;
|
|
654
647
|
}
|
|
@@ -670,9 +663,9 @@ var SessionHandshaking = class extends IdentifiedSessionWithGracePeriod {
|
|
|
670
663
|
this.handshakeTimeout = setTimeout(() => {
|
|
671
664
|
this.listeners.onHandshakeTimeout();
|
|
672
665
|
}, this.options.handshakeTimeoutMs);
|
|
673
|
-
this.conn.
|
|
674
|
-
this.conn.
|
|
675
|
-
this.conn.
|
|
666
|
+
this.conn.setDataListener(this.onHandshakeData);
|
|
667
|
+
this.conn.setErrorListener(this.listeners.onConnectionErrored);
|
|
668
|
+
this.conn.setCloseListener(this.listeners.onConnectionClosed);
|
|
676
669
|
}
|
|
677
670
|
get loggingMetadata() {
|
|
678
671
|
return {
|
|
@@ -681,24 +674,24 @@ var SessionHandshaking = class extends IdentifiedSessionWithGracePeriod {
|
|
|
681
674
|
};
|
|
682
675
|
}
|
|
683
676
|
onHandshakeData = (msg) => {
|
|
684
|
-
const
|
|
685
|
-
if (
|
|
677
|
+
const parsedMsgRes = this.codec.fromBuffer(msg);
|
|
678
|
+
if (!parsedMsgRes.ok) {
|
|
686
679
|
this.listeners.onInvalidHandshake(
|
|
687
|
-
|
|
680
|
+
`could not parse handshake message: ${parsedMsgRes.reason}`,
|
|
688
681
|
"MALFORMED_HANDSHAKE"
|
|
689
682
|
);
|
|
690
683
|
return;
|
|
691
684
|
}
|
|
692
|
-
this.listeners.onHandshake(
|
|
685
|
+
this.listeners.onHandshake(parsedMsgRes.value);
|
|
693
686
|
};
|
|
694
687
|
sendHandshake(msg) {
|
|
695
|
-
return this.conn
|
|
688
|
+
return sendMessage(this.conn, this.codec, msg);
|
|
696
689
|
}
|
|
697
690
|
_handleStateExit() {
|
|
698
691
|
super._handleStateExit();
|
|
699
|
-
this.conn.removeDataListener(
|
|
700
|
-
this.conn.removeErrorListener(
|
|
701
|
-
this.conn.removeCloseListener(
|
|
692
|
+
this.conn.removeDataListener();
|
|
693
|
+
this.conn.removeErrorListener();
|
|
694
|
+
this.conn.removeCloseListener();
|
|
702
695
|
if (this.handshakeTimeout) {
|
|
703
696
|
clearTimeout(this.handshakeTimeout);
|
|
704
697
|
this.handshakeTimeout = void 0;
|
|
@@ -717,25 +710,15 @@ var SessionConnected = class extends IdentifiedSession {
|
|
|
717
710
|
conn;
|
|
718
711
|
listeners;
|
|
719
712
|
heartbeatHandle;
|
|
720
|
-
|
|
721
|
-
isActivelyHeartbeating;
|
|
722
|
-
lastConstructedMsgs = [];
|
|
723
|
-
pushLastConstructedMsgs = (msg) => {
|
|
724
|
-
const trackedMsg = {
|
|
725
|
-
id: msg.id,
|
|
726
|
-
seq: msg.seq,
|
|
727
|
-
streamId: msg.streamId,
|
|
728
|
-
stack: new Error().stack
|
|
729
|
-
};
|
|
730
|
-
this.lastConstructedMsgs.push(trackedMsg);
|
|
731
|
-
if (this.lastConstructedMsgs.length > 10) {
|
|
732
|
-
this.lastConstructedMsgs.shift();
|
|
733
|
-
}
|
|
734
|
-
};
|
|
713
|
+
heartbeatMissTimeout;
|
|
714
|
+
isActivelyHeartbeating = false;
|
|
735
715
|
updateBookkeeping(ack, seq) {
|
|
736
716
|
this.sendBuffer = this.sendBuffer.filter((unacked) => unacked.seq >= ack);
|
|
737
717
|
this.ack = seq + 1;
|
|
738
|
-
this.
|
|
718
|
+
if (this.heartbeatMissTimeout) {
|
|
719
|
+
clearTimeout(this.heartbeatMissTimeout);
|
|
720
|
+
}
|
|
721
|
+
this.startMissingHeartbeatTimeout();
|
|
739
722
|
}
|
|
740
723
|
assertSendOrdering(constructedMsg) {
|
|
741
724
|
if (constructedMsg.seq > this.seqSent + 1) {
|
|
@@ -743,30 +726,32 @@ var SessionConnected = class extends IdentifiedSession {
|
|
|
743
726
|
this.log?.error(msg, {
|
|
744
727
|
...this.loggingMetadata,
|
|
745
728
|
transportMessage: constructedMsg,
|
|
746
|
-
tags: ["invariant-violation"]
|
|
747
|
-
extras: {
|
|
748
|
-
lastConstructedMsgs: this.lastConstructedMsgs
|
|
749
|
-
}
|
|
729
|
+
tags: ["invariant-violation"]
|
|
750
730
|
});
|
|
751
731
|
throw new Error(msg);
|
|
752
732
|
}
|
|
753
733
|
}
|
|
754
734
|
send(msg) {
|
|
755
735
|
const constructedMsg = this.constructMsg(msg);
|
|
756
|
-
this.pushLastConstructedMsgs(constructedMsg);
|
|
757
736
|
this.assertSendOrdering(constructedMsg);
|
|
758
737
|
this.sendBuffer.push(constructedMsg);
|
|
759
|
-
this.conn
|
|
738
|
+
const res = sendMessage(this.conn, this.codec, constructedMsg);
|
|
739
|
+
if (!res.ok) {
|
|
740
|
+
this.listeners.onMessageSendFailure(constructedMsg, res.reason);
|
|
741
|
+
return res;
|
|
742
|
+
}
|
|
760
743
|
this.seqSent = constructedMsg.seq;
|
|
761
|
-
return
|
|
744
|
+
return res;
|
|
762
745
|
}
|
|
763
746
|
constructor(props) {
|
|
764
747
|
super(props);
|
|
765
748
|
this.conn = props.conn;
|
|
766
749
|
this.listeners = props.listeners;
|
|
767
|
-
this.conn.
|
|
768
|
-
this.conn.
|
|
769
|
-
this.conn.
|
|
750
|
+
this.conn.setDataListener(this.onMessageData);
|
|
751
|
+
this.conn.setCloseListener(this.listeners.onConnectionClosed);
|
|
752
|
+
this.conn.setErrorListener(this.listeners.onConnectionErrored);
|
|
753
|
+
}
|
|
754
|
+
sendBufferedMessages() {
|
|
770
755
|
if (this.sendBuffer.length > 0) {
|
|
771
756
|
this.log?.info(
|
|
772
757
|
`sending ${this.sendBuffer.length} buffered messages, starting at seq ${this.nextSeq()}`,
|
|
@@ -774,30 +759,15 @@ var SessionConnected = class extends IdentifiedSession {
|
|
|
774
759
|
);
|
|
775
760
|
for (const msg of this.sendBuffer) {
|
|
776
761
|
this.assertSendOrdering(msg);
|
|
777
|
-
this.conn
|
|
762
|
+
const res = sendMessage(this.conn, this.codec, msg);
|
|
763
|
+
if (!res.ok) {
|
|
764
|
+
this.listeners.onMessageSendFailure(msg, res.reason);
|
|
765
|
+
return res;
|
|
766
|
+
}
|
|
778
767
|
this.seqSent = msg.seq;
|
|
779
768
|
}
|
|
780
769
|
}
|
|
781
|
-
|
|
782
|
-
this.heartbeatHandle = setInterval(() => {
|
|
783
|
-
const misses = this.heartbeatMisses;
|
|
784
|
-
const missDuration = misses * this.options.heartbeatIntervalMs;
|
|
785
|
-
if (misses >= this.options.heartbeatsUntilDead) {
|
|
786
|
-
this.log?.info(
|
|
787
|
-
`closing connection to ${this.to} due to inactivity (missed ${misses} heartbeats which is ${missDuration}ms)`,
|
|
788
|
-
this.loggingMetadata
|
|
789
|
-
);
|
|
790
|
-
this.telemetry.span.addEvent("closing connection due to inactivity");
|
|
791
|
-
this.conn.close();
|
|
792
|
-
clearInterval(this.heartbeatHandle);
|
|
793
|
-
this.heartbeatHandle = void 0;
|
|
794
|
-
return;
|
|
795
|
-
}
|
|
796
|
-
if (this.isActivelyHeartbeating) {
|
|
797
|
-
this.sendHeartbeat();
|
|
798
|
-
}
|
|
799
|
-
this.heartbeatMisses++;
|
|
800
|
-
}, this.options.heartbeatIntervalMs);
|
|
770
|
+
return { ok: true, value: void 0 };
|
|
801
771
|
}
|
|
802
772
|
get loggingMetadata() {
|
|
803
773
|
return {
|
|
@@ -805,25 +775,46 @@ var SessionConnected = class extends IdentifiedSession {
|
|
|
805
775
|
...this.conn.loggingMetadata
|
|
806
776
|
};
|
|
807
777
|
}
|
|
778
|
+
startMissingHeartbeatTimeout() {
|
|
779
|
+
const maxMisses = this.options.heartbeatsUntilDead;
|
|
780
|
+
const missDuration = maxMisses * this.options.heartbeatIntervalMs;
|
|
781
|
+
this.heartbeatMissTimeout = setTimeout(() => {
|
|
782
|
+
this.log?.info(
|
|
783
|
+
`closing connection to ${this.to} due to inactivity (missed ${maxMisses} heartbeats which is ${missDuration}ms)`,
|
|
784
|
+
this.loggingMetadata
|
|
785
|
+
);
|
|
786
|
+
this.telemetry.span.addEvent(
|
|
787
|
+
"closing connection due to missing heartbeat"
|
|
788
|
+
);
|
|
789
|
+
this.conn.close();
|
|
790
|
+
}, missDuration);
|
|
791
|
+
}
|
|
808
792
|
startActiveHeartbeat() {
|
|
809
793
|
this.isActivelyHeartbeating = true;
|
|
794
|
+
this.heartbeatHandle = setInterval(() => {
|
|
795
|
+
this.sendHeartbeat();
|
|
796
|
+
}, this.options.heartbeatIntervalMs);
|
|
810
797
|
}
|
|
811
798
|
sendHeartbeat() {
|
|
812
799
|
this.log?.debug("sending heartbeat", this.loggingMetadata);
|
|
813
|
-
|
|
800
|
+
const heartbeat = {
|
|
814
801
|
streamId: "heartbeat",
|
|
815
802
|
controlFlags: 1 /* AckBit */,
|
|
816
803
|
payload: {
|
|
817
804
|
type: "ACK"
|
|
818
805
|
}
|
|
819
|
-
}
|
|
806
|
+
};
|
|
807
|
+
this.send(heartbeat);
|
|
820
808
|
}
|
|
821
809
|
onMessageData = (msg) => {
|
|
822
|
-
const
|
|
823
|
-
if (
|
|
824
|
-
this.listeners.onInvalidMessage(
|
|
810
|
+
const parsedMsgRes = this.codec.fromBuffer(msg);
|
|
811
|
+
if (!parsedMsgRes.ok) {
|
|
812
|
+
this.listeners.onInvalidMessage(
|
|
813
|
+
`could not parse message: ${parsedMsgRes.reason}`
|
|
814
|
+
);
|
|
825
815
|
return;
|
|
826
816
|
}
|
|
817
|
+
const parsedMsg = parsedMsgRes.value;
|
|
827
818
|
if (parsedMsg.seq !== this.ack) {
|
|
828
819
|
if (parsedMsg.seq < this.ack) {
|
|
829
820
|
this.log?.debug(
|
|
@@ -862,20 +853,22 @@ var SessionConnected = class extends IdentifiedSession {
|
|
|
862
853
|
transportMessage: parsedMsg
|
|
863
854
|
});
|
|
864
855
|
if (!this.isActivelyHeartbeating) {
|
|
865
|
-
|
|
866
|
-
this.sendHeartbeat();
|
|
867
|
-
});
|
|
856
|
+
this.sendHeartbeat();
|
|
868
857
|
}
|
|
869
858
|
};
|
|
870
859
|
_handleStateExit() {
|
|
871
860
|
super._handleStateExit();
|
|
872
|
-
this.conn.removeDataListener(
|
|
873
|
-
this.conn.removeCloseListener(
|
|
874
|
-
this.conn.removeErrorListener(
|
|
861
|
+
this.conn.removeDataListener();
|
|
862
|
+
this.conn.removeCloseListener();
|
|
863
|
+
this.conn.removeErrorListener();
|
|
875
864
|
if (this.heartbeatHandle) {
|
|
876
865
|
clearInterval(this.heartbeatHandle);
|
|
877
866
|
this.heartbeatHandle = void 0;
|
|
878
867
|
}
|
|
868
|
+
if (this.heartbeatMissTimeout) {
|
|
869
|
+
clearTimeout(this.heartbeatMissTimeout);
|
|
870
|
+
this.heartbeatMissTimeout = void 0;
|
|
871
|
+
}
|
|
879
872
|
}
|
|
880
873
|
_handleClose() {
|
|
881
874
|
super._handleClose();
|
|
@@ -907,425 +900,47 @@ var SessionBackingOff = class extends IdentifiedSessionWithGracePeriod {
|
|
|
907
900
|
}
|
|
908
901
|
};
|
|
909
902
|
|
|
910
|
-
//
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
903
|
+
// codec/adapter.ts
|
|
904
|
+
var import_value3 = require("@sinclair/typebox/value");
|
|
905
|
+
|
|
906
|
+
// logging/log.ts
|
|
907
|
+
var import_api3 = require("@opentelemetry/api");
|
|
908
|
+
var LoggingLevels = {
|
|
909
|
+
debug: -1,
|
|
910
|
+
info: 0,
|
|
911
|
+
warn: 1,
|
|
912
|
+
error: 2
|
|
913
|
+
};
|
|
914
|
+
var cleanedLogFn = (log) => {
|
|
915
|
+
return (msg, metadata) => {
|
|
916
|
+
if (metadata && !metadata.telemetry) {
|
|
917
|
+
const span = import_api3.trace.getSpan(import_api3.context.active());
|
|
918
|
+
if (span) {
|
|
919
|
+
metadata.telemetry = {
|
|
920
|
+
traceId: span.spanContext().traceId,
|
|
921
|
+
spanId: span.spanContext().spanId
|
|
922
|
+
};
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
if (!metadata?.transportMessage) {
|
|
926
|
+
log(msg, metadata);
|
|
927
|
+
return;
|
|
928
|
+
}
|
|
929
|
+
const { payload, ...rest } = metadata.transportMessage;
|
|
930
|
+
metadata.transportMessage = rest;
|
|
931
|
+
log(msg, metadata);
|
|
931
932
|
};
|
|
932
|
-
}
|
|
933
|
-
var
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
to,
|
|
944
|
-
seq: 0,
|
|
945
|
-
ack: 0,
|
|
946
|
-
seqSent: 0,
|
|
947
|
-
graceExpiryTime: Date.now() + options.sessionDisconnectGraceMs,
|
|
948
|
-
sendBuffer,
|
|
949
|
-
telemetry,
|
|
950
|
-
options,
|
|
951
|
-
protocolVersion,
|
|
952
|
-
tracer,
|
|
953
|
-
log
|
|
954
|
-
});
|
|
955
|
-
session.log?.info(`session ${session.id} created in NoConnection state`, {
|
|
956
|
-
...session.loggingMetadata,
|
|
957
|
-
tags: ["state-transition"]
|
|
958
|
-
});
|
|
959
|
-
return session;
|
|
960
|
-
},
|
|
961
|
-
WaitingForHandshake: (from, conn, listeners, options, tracer, log) => {
|
|
962
|
-
const session = new SessionWaitingForHandshake({
|
|
963
|
-
conn,
|
|
964
|
-
listeners,
|
|
965
|
-
from,
|
|
966
|
-
options,
|
|
967
|
-
tracer,
|
|
968
|
-
log
|
|
969
|
-
});
|
|
970
|
-
session.log?.info(`session created in WaitingForHandshake state`, {
|
|
971
|
-
...session.loggingMetadata,
|
|
972
|
-
tags: ["state-transition"]
|
|
973
|
-
});
|
|
974
|
-
return session;
|
|
975
|
-
}
|
|
976
|
-
},
|
|
977
|
-
// All of the transitions 'move'/'consume' the old session and return a new one.
|
|
978
|
-
// After a session is transitioned, any usage of the old session will throw.
|
|
979
|
-
transition: {
|
|
980
|
-
// happy path transitions
|
|
981
|
-
NoConnectionToBackingOff: (oldSession, backoffMs, listeners) => {
|
|
982
|
-
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
983
|
-
oldSession._handleStateExit();
|
|
984
|
-
const session = new SessionBackingOff({
|
|
985
|
-
backoffMs,
|
|
986
|
-
listeners,
|
|
987
|
-
...carriedState
|
|
988
|
-
});
|
|
989
|
-
session.log?.info(
|
|
990
|
-
`session ${session.id} transition from NoConnection to BackingOff`,
|
|
991
|
-
{
|
|
992
|
-
...session.loggingMetadata,
|
|
993
|
-
tags: ["state-transition"]
|
|
994
|
-
}
|
|
995
|
-
);
|
|
996
|
-
return session;
|
|
997
|
-
},
|
|
998
|
-
BackingOffToConnecting: (oldSession, connPromise, listeners) => {
|
|
999
|
-
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
1000
|
-
oldSession._handleStateExit();
|
|
1001
|
-
const session = new SessionConnecting({
|
|
1002
|
-
connPromise,
|
|
1003
|
-
listeners,
|
|
1004
|
-
...carriedState
|
|
1005
|
-
});
|
|
1006
|
-
session.log?.info(
|
|
1007
|
-
`session ${session.id} transition from BackingOff to Connecting`,
|
|
1008
|
-
{
|
|
1009
|
-
...session.loggingMetadata,
|
|
1010
|
-
tags: ["state-transition"]
|
|
1011
|
-
}
|
|
1012
|
-
);
|
|
1013
|
-
return session;
|
|
1014
|
-
},
|
|
1015
|
-
ConnectingToHandshaking: (oldSession, conn, listeners) => {
|
|
1016
|
-
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
1017
|
-
oldSession._handleStateExit();
|
|
1018
|
-
const session = new SessionHandshaking({
|
|
1019
|
-
conn,
|
|
1020
|
-
listeners,
|
|
1021
|
-
...carriedState
|
|
1022
|
-
});
|
|
1023
|
-
conn.telemetry = createConnectionTelemetryInfo(
|
|
1024
|
-
session.tracer,
|
|
1025
|
-
conn,
|
|
1026
|
-
session.telemetry
|
|
1027
|
-
);
|
|
1028
|
-
session.log?.info(
|
|
1029
|
-
`session ${session.id} transition from Connecting to Handshaking`,
|
|
1030
|
-
{
|
|
1031
|
-
...session.loggingMetadata,
|
|
1032
|
-
tags: ["state-transition"]
|
|
1033
|
-
}
|
|
1034
|
-
);
|
|
1035
|
-
return session;
|
|
1036
|
-
},
|
|
1037
|
-
HandshakingToConnected: (oldSession, listeners) => {
|
|
1038
|
-
const carriedState = inheritSharedSession(oldSession);
|
|
1039
|
-
const conn = oldSession.conn;
|
|
1040
|
-
oldSession._handleStateExit();
|
|
1041
|
-
const session = new SessionConnected({
|
|
1042
|
-
conn,
|
|
1043
|
-
listeners,
|
|
1044
|
-
...carriedState
|
|
1045
|
-
});
|
|
1046
|
-
session.log?.info(
|
|
1047
|
-
`session ${session.id} transition from Handshaking to Connected`,
|
|
1048
|
-
{
|
|
1049
|
-
...session.loggingMetadata,
|
|
1050
|
-
tags: ["state-transition"]
|
|
1051
|
-
}
|
|
1052
|
-
);
|
|
1053
|
-
return session;
|
|
1054
|
-
},
|
|
1055
|
-
WaitingForHandshakeToConnected: (pendingSession, oldSession, sessionId, to, propagationCtx, listeners, protocolVersion) => {
|
|
1056
|
-
const conn = pendingSession.conn;
|
|
1057
|
-
const { from, options } = pendingSession;
|
|
1058
|
-
const carriedState = oldSession ? (
|
|
1059
|
-
// old session exists, inherit state
|
|
1060
|
-
inheritSharedSession(oldSession)
|
|
1061
|
-
) : (
|
|
1062
|
-
// old session does not exist, create new state
|
|
1063
|
-
{
|
|
1064
|
-
id: sessionId,
|
|
1065
|
-
from,
|
|
1066
|
-
to,
|
|
1067
|
-
seq: 0,
|
|
1068
|
-
ack: 0,
|
|
1069
|
-
seqSent: 0,
|
|
1070
|
-
sendBuffer: [],
|
|
1071
|
-
telemetry: createSessionTelemetryInfo(
|
|
1072
|
-
pendingSession.tracer,
|
|
1073
|
-
sessionId,
|
|
1074
|
-
to,
|
|
1075
|
-
from,
|
|
1076
|
-
propagationCtx
|
|
1077
|
-
),
|
|
1078
|
-
options,
|
|
1079
|
-
tracer: pendingSession.tracer,
|
|
1080
|
-
log: pendingSession.log,
|
|
1081
|
-
protocolVersion
|
|
1082
|
-
}
|
|
1083
|
-
);
|
|
1084
|
-
pendingSession._handleStateExit();
|
|
1085
|
-
oldSession?._handleStateExit();
|
|
1086
|
-
const session = new SessionConnected({
|
|
1087
|
-
conn,
|
|
1088
|
-
listeners,
|
|
1089
|
-
...carriedState
|
|
1090
|
-
});
|
|
1091
|
-
conn.telemetry = createConnectionTelemetryInfo(
|
|
1092
|
-
session.tracer,
|
|
1093
|
-
conn,
|
|
1094
|
-
session.telemetry
|
|
1095
|
-
);
|
|
1096
|
-
session.log?.info(
|
|
1097
|
-
`session ${session.id} transition from WaitingForHandshake to Connected`,
|
|
1098
|
-
{
|
|
1099
|
-
...session.loggingMetadata,
|
|
1100
|
-
tags: ["state-transition"]
|
|
1101
|
-
}
|
|
1102
|
-
);
|
|
1103
|
-
return session;
|
|
1104
|
-
},
|
|
1105
|
-
// disconnect paths
|
|
1106
|
-
BackingOffToNoConnection: (oldSession, listeners) => {
|
|
1107
|
-
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
1108
|
-
oldSession._handleStateExit();
|
|
1109
|
-
const session = new SessionNoConnection({
|
|
1110
|
-
listeners,
|
|
1111
|
-
...carriedState
|
|
1112
|
-
});
|
|
1113
|
-
session.log?.info(
|
|
1114
|
-
`session ${session.id} transition from BackingOff to NoConnection`,
|
|
1115
|
-
{
|
|
1116
|
-
...session.loggingMetadata,
|
|
1117
|
-
tags: ["state-transition"]
|
|
1118
|
-
}
|
|
1119
|
-
);
|
|
1120
|
-
return session;
|
|
1121
|
-
},
|
|
1122
|
-
ConnectingToNoConnection: (oldSession, listeners) => {
|
|
1123
|
-
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
1124
|
-
oldSession.bestEffortClose();
|
|
1125
|
-
oldSession._handleStateExit();
|
|
1126
|
-
const session = new SessionNoConnection({
|
|
1127
|
-
listeners,
|
|
1128
|
-
...carriedState
|
|
1129
|
-
});
|
|
1130
|
-
session.log?.info(
|
|
1131
|
-
`session ${session.id} transition from Connecting to NoConnection`,
|
|
1132
|
-
{
|
|
1133
|
-
...session.loggingMetadata,
|
|
1134
|
-
tags: ["state-transition"]
|
|
1135
|
-
}
|
|
1136
|
-
);
|
|
1137
|
-
return session;
|
|
1138
|
-
},
|
|
1139
|
-
HandshakingToNoConnection: (oldSession, listeners) => {
|
|
1140
|
-
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
1141
|
-
oldSession.conn.close();
|
|
1142
|
-
oldSession._handleStateExit();
|
|
1143
|
-
const session = new SessionNoConnection({
|
|
1144
|
-
listeners,
|
|
1145
|
-
...carriedState
|
|
1146
|
-
});
|
|
1147
|
-
session.log?.info(
|
|
1148
|
-
`session ${session.id} transition from Handshaking to NoConnection`,
|
|
1149
|
-
{
|
|
1150
|
-
...session.loggingMetadata,
|
|
1151
|
-
tags: ["state-transition"]
|
|
1152
|
-
}
|
|
1153
|
-
);
|
|
1154
|
-
return session;
|
|
1155
|
-
},
|
|
1156
|
-
ConnectedToNoConnection: (oldSession, listeners) => {
|
|
1157
|
-
const carriedState = inheritSharedSession(oldSession);
|
|
1158
|
-
const graceExpiryTime = Date.now() + oldSession.options.sessionDisconnectGraceMs;
|
|
1159
|
-
oldSession.conn.close();
|
|
1160
|
-
oldSession._handleStateExit();
|
|
1161
|
-
const session = new SessionNoConnection({
|
|
1162
|
-
listeners,
|
|
1163
|
-
graceExpiryTime,
|
|
1164
|
-
...carriedState
|
|
1165
|
-
});
|
|
1166
|
-
session.log?.info(
|
|
1167
|
-
`session ${session.id} transition from Connected to NoConnection`,
|
|
1168
|
-
{
|
|
1169
|
-
...session.loggingMetadata,
|
|
1170
|
-
tags: ["state-transition"]
|
|
1171
|
-
}
|
|
1172
|
-
);
|
|
1173
|
-
return session;
|
|
1174
|
-
}
|
|
1175
|
-
}
|
|
1176
|
-
};
|
|
1177
|
-
var transitions = SessionStateGraph.transition;
|
|
1178
|
-
var ClientSessionStateGraph = {
|
|
1179
|
-
entrypoint: SessionStateGraph.entrypoints.NoConnection,
|
|
1180
|
-
transition: {
|
|
1181
|
-
// happy paths
|
|
1182
|
-
// NoConnection -> BackingOff: attempt to connect
|
|
1183
|
-
NoConnectionToBackingOff: transitions.NoConnectionToBackingOff,
|
|
1184
|
-
// BackingOff -> Connecting: backoff period elapsed, start connection
|
|
1185
|
-
BackingOffToConnecting: transitions.BackingOffToConnecting,
|
|
1186
|
-
// Connecting -> Handshaking: connection established, start handshake
|
|
1187
|
-
ConnectingToHandshaking: transitions.ConnectingToHandshaking,
|
|
1188
|
-
// Handshaking -> Connected: handshake complete, session ready
|
|
1189
|
-
HandshakingToConnected: transitions.HandshakingToConnected,
|
|
1190
|
-
// disconnect paths
|
|
1191
|
-
// BackingOff -> NoConnection: unused
|
|
1192
|
-
BackingOffToNoConnection: transitions.BackingOffToNoConnection,
|
|
1193
|
-
// Connecting -> NoConnection: connection failed or connection timeout
|
|
1194
|
-
ConnectingToNoConnection: transitions.ConnectingToNoConnection,
|
|
1195
|
-
// Handshaking -> NoConnection: connection closed or handshake timeout
|
|
1196
|
-
HandshakingToNoConnection: transitions.HandshakingToNoConnection,
|
|
1197
|
-
// Connected -> NoConnection: connection closed
|
|
1198
|
-
ConnectedToNoConnection: transitions.ConnectedToNoConnection
|
|
1199
|
-
// destroy/close paths
|
|
1200
|
-
// NoConnection -> x: grace period elapsed
|
|
1201
|
-
// BackingOff -> x: grace period elapsed
|
|
1202
|
-
// Connecting -> x: grace period elapsed
|
|
1203
|
-
// Handshaking -> x: grace period elapsed or invalid handshake message or handshake rejection
|
|
1204
|
-
// Connected -> x: grace period elapsed or invalid message
|
|
1205
|
-
}
|
|
1206
|
-
};
|
|
1207
|
-
var ServerSessionStateGraph = {
|
|
1208
|
-
entrypoint: SessionStateGraph.entrypoints.WaitingForHandshake,
|
|
1209
|
-
transition: {
|
|
1210
|
-
// happy paths
|
|
1211
|
-
// WaitingForHandshake -> Connected: handshake complete, session ready
|
|
1212
|
-
WaitingForHandshakeToConnected: transitions.WaitingForHandshakeToConnected,
|
|
1213
|
-
// disconnect paths
|
|
1214
|
-
// Connected -> NoConnection: connection closed
|
|
1215
|
-
ConnectedToNoConnection: transitions.ConnectedToNoConnection
|
|
1216
|
-
// destroy/close paths
|
|
1217
|
-
// WaitingForHandshake -> x: handshake timeout elapsed or invalid handshake message or handshake rejection or connection closed
|
|
1218
|
-
}
|
|
1219
|
-
};
|
|
1220
|
-
|
|
1221
|
-
// transport/client.ts
|
|
1222
|
-
var import_api4 = require("@opentelemetry/api");
|
|
1223
|
-
|
|
1224
|
-
// transport/rateLimit.ts
|
|
1225
|
-
var LeakyBucketRateLimit = class {
|
|
1226
|
-
budgetConsumed;
|
|
1227
|
-
intervalHandle;
|
|
1228
|
-
options;
|
|
1229
|
-
constructor(options) {
|
|
1230
|
-
this.options = options;
|
|
1231
|
-
this.budgetConsumed = 0;
|
|
1232
|
-
}
|
|
1233
|
-
getBackoffMs() {
|
|
1234
|
-
if (this.getBudgetConsumed() === 0) {
|
|
1235
|
-
return 0;
|
|
1236
|
-
}
|
|
1237
|
-
const exponent = Math.max(0, this.getBudgetConsumed() - 1);
|
|
1238
|
-
const jitter = Math.floor(Math.random() * this.options.maxJitterMs);
|
|
1239
|
-
const backoffMs = Math.min(
|
|
1240
|
-
this.options.baseIntervalMs * 2 ** exponent,
|
|
1241
|
-
this.options.maxBackoffMs
|
|
1242
|
-
);
|
|
1243
|
-
return backoffMs + jitter;
|
|
1244
|
-
}
|
|
1245
|
-
get totalBudgetRestoreTime() {
|
|
1246
|
-
return this.options.budgetRestoreIntervalMs * this.options.attemptBudgetCapacity;
|
|
1247
|
-
}
|
|
1248
|
-
consumeBudget() {
|
|
1249
|
-
this.stopLeak();
|
|
1250
|
-
this.budgetConsumed = this.getBudgetConsumed() + 1;
|
|
1251
|
-
}
|
|
1252
|
-
getBudgetConsumed() {
|
|
1253
|
-
return this.budgetConsumed;
|
|
1254
|
-
}
|
|
1255
|
-
hasBudget() {
|
|
1256
|
-
return this.getBudgetConsumed() < this.options.attemptBudgetCapacity;
|
|
1257
|
-
}
|
|
1258
|
-
startRestoringBudget() {
|
|
1259
|
-
if (this.intervalHandle) {
|
|
1260
|
-
return;
|
|
1261
|
-
}
|
|
1262
|
-
const restoreBudgetForUser = () => {
|
|
1263
|
-
const currentBudget = this.budgetConsumed;
|
|
1264
|
-
if (!currentBudget) {
|
|
1265
|
-
this.stopLeak();
|
|
1266
|
-
return;
|
|
1267
|
-
}
|
|
1268
|
-
const newBudget = currentBudget - 1;
|
|
1269
|
-
if (newBudget === 0) {
|
|
1270
|
-
return;
|
|
1271
|
-
}
|
|
1272
|
-
this.budgetConsumed = newBudget;
|
|
1273
|
-
};
|
|
1274
|
-
this.intervalHandle = setInterval(
|
|
1275
|
-
restoreBudgetForUser,
|
|
1276
|
-
this.options.budgetRestoreIntervalMs
|
|
1277
|
-
);
|
|
1278
|
-
}
|
|
1279
|
-
stopLeak() {
|
|
1280
|
-
if (!this.intervalHandle) {
|
|
1281
|
-
return;
|
|
1282
|
-
}
|
|
1283
|
-
clearInterval(this.intervalHandle);
|
|
1284
|
-
this.intervalHandle = void 0;
|
|
1285
|
-
}
|
|
1286
|
-
close() {
|
|
1287
|
-
this.stopLeak();
|
|
1288
|
-
}
|
|
1289
|
-
};
|
|
1290
|
-
|
|
1291
|
-
// logging/log.ts
|
|
1292
|
-
var import_api3 = require("@opentelemetry/api");
|
|
1293
|
-
var LoggingLevels = {
|
|
1294
|
-
debug: -1,
|
|
1295
|
-
info: 0,
|
|
1296
|
-
warn: 1,
|
|
1297
|
-
error: 2
|
|
1298
|
-
};
|
|
1299
|
-
var cleanedLogFn = (log) => {
|
|
1300
|
-
return (msg, metadata) => {
|
|
1301
|
-
if (metadata && !metadata.telemetry) {
|
|
1302
|
-
const span = import_api3.trace.getSpan(import_api3.context.active());
|
|
1303
|
-
if (span) {
|
|
1304
|
-
metadata.telemetry = {
|
|
1305
|
-
traceId: span.spanContext().traceId,
|
|
1306
|
-
spanId: span.spanContext().spanId
|
|
1307
|
-
};
|
|
1308
|
-
}
|
|
1309
|
-
}
|
|
1310
|
-
if (!metadata?.transportMessage) {
|
|
1311
|
-
log(msg, metadata);
|
|
1312
|
-
return;
|
|
1313
|
-
}
|
|
1314
|
-
const { payload, ...rest } = metadata.transportMessage;
|
|
1315
|
-
metadata.transportMessage = rest;
|
|
1316
|
-
log(msg, metadata);
|
|
1317
|
-
};
|
|
1318
|
-
};
|
|
1319
|
-
var BaseLogger = class {
|
|
1320
|
-
minLevel;
|
|
1321
|
-
output;
|
|
1322
|
-
constructor(output, minLevel = "info") {
|
|
1323
|
-
this.minLevel = minLevel;
|
|
1324
|
-
this.output = output;
|
|
1325
|
-
}
|
|
1326
|
-
debug(msg, metadata) {
|
|
1327
|
-
if (LoggingLevels[this.minLevel] <= LoggingLevels.debug) {
|
|
1328
|
-
this.output(msg, metadata ?? {}, "debug");
|
|
933
|
+
};
|
|
934
|
+
var BaseLogger = class {
|
|
935
|
+
minLevel;
|
|
936
|
+
output;
|
|
937
|
+
constructor(output, minLevel = "info") {
|
|
938
|
+
this.minLevel = minLevel;
|
|
939
|
+
this.output = output;
|
|
940
|
+
}
|
|
941
|
+
debug(msg, metadata) {
|
|
942
|
+
if (LoggingLevels[this.minLevel] <= LoggingLevels.debug) {
|
|
943
|
+
this.output(msg, metadata ?? {}, "debug");
|
|
1329
944
|
}
|
|
1330
945
|
}
|
|
1331
946
|
info(msg, metadata) {
|
|
@@ -1356,7 +971,8 @@ var ProtocolError = {
|
|
|
1356
971
|
RetriesExceeded: "conn_retry_exceeded",
|
|
1357
972
|
HandshakeFailed: "handshake_failed",
|
|
1358
973
|
MessageOrderingViolated: "message_ordering_violated",
|
|
1359
|
-
InvalidMessage: "invalid_message"
|
|
974
|
+
InvalidMessage: "invalid_message",
|
|
975
|
+
MessageSendFailure: "message_send_failure"
|
|
1360
976
|
};
|
|
1361
977
|
var EventDispatcher = class {
|
|
1362
978
|
eventListeners = {};
|
|
@@ -1436,8 +1052,7 @@ var Transport = class {
|
|
|
1436
1052
|
* @param message The received message.
|
|
1437
1053
|
*/
|
|
1438
1054
|
handleMsg(message) {
|
|
1439
|
-
if (this.getStatus() !== "open")
|
|
1440
|
-
return;
|
|
1055
|
+
if (this.getStatus() !== "open") return;
|
|
1441
1056
|
this.eventDispatcher.dispatchEvent("message", message);
|
|
1442
1057
|
}
|
|
1443
1058
|
/**
|
|
@@ -1525,8 +1140,7 @@ var Transport = class {
|
|
|
1525
1140
|
});
|
|
1526
1141
|
}
|
|
1527
1142
|
deleteSession(session, options) {
|
|
1528
|
-
if (session._isConsumed)
|
|
1529
|
-
return;
|
|
1143
|
+
if (session._isConsumed) return;
|
|
1530
1144
|
const loggingMetadata = session.loggingMetadata;
|
|
1531
1145
|
if (loggingMetadata.tags && options?.unhealthy) {
|
|
1532
1146
|
loggingMetadata.tags.push("unhealthy-session");
|
|
@@ -1546,7 +1160,7 @@ var Transport = class {
|
|
|
1546
1160
|
}
|
|
1547
1161
|
// common listeners
|
|
1548
1162
|
onSessionGracePeriodElapsed(session) {
|
|
1549
|
-
this.log?.
|
|
1163
|
+
this.log?.info(
|
|
1550
1164
|
`session to ${session.to} grace period elapsed, closing`,
|
|
1551
1165
|
session.loggingMetadata
|
|
1552
1166
|
);
|
|
@@ -1599,18 +1213,92 @@ var Transport = class {
|
|
|
1599
1213
|
);
|
|
1600
1214
|
}
|
|
1601
1215
|
const sameSession = session.id === sessionId;
|
|
1602
|
-
if (!sameSession) {
|
|
1216
|
+
if (!sameSession || session._isConsumed) {
|
|
1603
1217
|
throw new Error(
|
|
1604
1218
|
`session scope for ${sessionId} has ended (transition), can't send`
|
|
1605
1219
|
);
|
|
1606
1220
|
}
|
|
1607
|
-
|
|
1221
|
+
const res = session.send(msg);
|
|
1222
|
+
if (!res.ok) {
|
|
1223
|
+
throw new Error(res.reason);
|
|
1224
|
+
}
|
|
1225
|
+
return res.value;
|
|
1608
1226
|
};
|
|
1609
1227
|
}
|
|
1610
1228
|
};
|
|
1611
1229
|
|
|
1612
1230
|
// transport/client.ts
|
|
1613
|
-
var
|
|
1231
|
+
var import_api4 = require("@opentelemetry/api");
|
|
1232
|
+
|
|
1233
|
+
// transport/rateLimit.ts
|
|
1234
|
+
var LeakyBucketRateLimit = class {
|
|
1235
|
+
budgetConsumed;
|
|
1236
|
+
intervalHandle;
|
|
1237
|
+
options;
|
|
1238
|
+
constructor(options) {
|
|
1239
|
+
this.options = options;
|
|
1240
|
+
this.budgetConsumed = 0;
|
|
1241
|
+
}
|
|
1242
|
+
getBackoffMs() {
|
|
1243
|
+
if (this.getBudgetConsumed() === 0) {
|
|
1244
|
+
return 0;
|
|
1245
|
+
}
|
|
1246
|
+
const exponent = Math.max(0, this.getBudgetConsumed() - 1);
|
|
1247
|
+
const jitter = Math.floor(Math.random() * this.options.maxJitterMs);
|
|
1248
|
+
const backoffMs = Math.min(
|
|
1249
|
+
this.options.baseIntervalMs * 2 ** exponent,
|
|
1250
|
+
this.options.maxBackoffMs
|
|
1251
|
+
);
|
|
1252
|
+
return backoffMs + jitter;
|
|
1253
|
+
}
|
|
1254
|
+
get totalBudgetRestoreTime() {
|
|
1255
|
+
return this.options.budgetRestoreIntervalMs * this.options.attemptBudgetCapacity;
|
|
1256
|
+
}
|
|
1257
|
+
consumeBudget() {
|
|
1258
|
+
this.stopLeak();
|
|
1259
|
+
this.budgetConsumed = this.getBudgetConsumed() + 1;
|
|
1260
|
+
}
|
|
1261
|
+
getBudgetConsumed() {
|
|
1262
|
+
return this.budgetConsumed;
|
|
1263
|
+
}
|
|
1264
|
+
hasBudget() {
|
|
1265
|
+
return this.getBudgetConsumed() < this.options.attemptBudgetCapacity;
|
|
1266
|
+
}
|
|
1267
|
+
startRestoringBudget() {
|
|
1268
|
+
if (this.intervalHandle) {
|
|
1269
|
+
return;
|
|
1270
|
+
}
|
|
1271
|
+
const restoreBudgetForUser = () => {
|
|
1272
|
+
const currentBudget = this.budgetConsumed;
|
|
1273
|
+
if (!currentBudget) {
|
|
1274
|
+
this.stopLeak();
|
|
1275
|
+
return;
|
|
1276
|
+
}
|
|
1277
|
+
const newBudget = currentBudget - 1;
|
|
1278
|
+
if (newBudget === 0) {
|
|
1279
|
+
return;
|
|
1280
|
+
}
|
|
1281
|
+
this.budgetConsumed = newBudget;
|
|
1282
|
+
};
|
|
1283
|
+
this.intervalHandle = setInterval(
|
|
1284
|
+
restoreBudgetForUser,
|
|
1285
|
+
this.options.budgetRestoreIntervalMs
|
|
1286
|
+
);
|
|
1287
|
+
}
|
|
1288
|
+
stopLeak() {
|
|
1289
|
+
if (!this.intervalHandle) {
|
|
1290
|
+
return;
|
|
1291
|
+
}
|
|
1292
|
+
clearInterval(this.intervalHandle);
|
|
1293
|
+
this.intervalHandle = void 0;
|
|
1294
|
+
}
|
|
1295
|
+
close() {
|
|
1296
|
+
this.stopLeak();
|
|
1297
|
+
}
|
|
1298
|
+
};
|
|
1299
|
+
|
|
1300
|
+
// transport/client.ts
|
|
1301
|
+
var import_value = require("@sinclair/typebox/value");
|
|
1614
1302
|
var ClientTransport = class extends Transport {
|
|
1615
1303
|
/**
|
|
1616
1304
|
* The options for this transport.
|
|
@@ -1741,19 +1429,19 @@ var ClientTransport = class extends Transport {
|
|
|
1741
1429
|
this.deleteSession(session, { unhealthy: true });
|
|
1742
1430
|
}
|
|
1743
1431
|
onHandshakeResponse(session, msg) {
|
|
1744
|
-
if (!
|
|
1432
|
+
if (!import_value.Value.Check(ControlMessageHandshakeResponseSchema, msg.payload)) {
|
|
1745
1433
|
const reason = `received invalid handshake response`;
|
|
1746
1434
|
this.rejectHandshakeResponse(session, reason, {
|
|
1747
1435
|
...session.loggingMetadata,
|
|
1748
1436
|
transportMessage: msg,
|
|
1749
1437
|
validationErrors: [
|
|
1750
|
-
...
|
|
1438
|
+
...import_value.Value.Errors(ControlMessageHandshakeResponseSchema, msg.payload)
|
|
1751
1439
|
]
|
|
1752
1440
|
});
|
|
1753
1441
|
return;
|
|
1754
1442
|
}
|
|
1755
1443
|
if (!msg.payload.status.ok) {
|
|
1756
|
-
const retriable =
|
|
1444
|
+
const retriable = import_value.Value.Check(
|
|
1757
1445
|
HandshakeErrorRetriableResponseCodes,
|
|
1758
1446
|
msg.payload.status.code
|
|
1759
1447
|
);
|
|
@@ -1805,13 +1493,32 @@ var ClientTransport = class extends Transport {
|
|
|
1805
1493
|
this.handleMsg(msg2);
|
|
1806
1494
|
},
|
|
1807
1495
|
onInvalidMessage: (reason) => {
|
|
1808
|
-
this.
|
|
1496
|
+
this.log?.error(`invalid message: ${reason}`, {
|
|
1497
|
+
...connectedSession.loggingMetadata,
|
|
1498
|
+
transportMessage: msg
|
|
1499
|
+
});
|
|
1809
1500
|
this.protocolError({
|
|
1810
1501
|
type: ProtocolError.InvalidMessage,
|
|
1811
1502
|
message: reason
|
|
1812
1503
|
});
|
|
1504
|
+
this.deleteSession(connectedSession, { unhealthy: true });
|
|
1505
|
+
},
|
|
1506
|
+
onMessageSendFailure: (msg2, reason) => {
|
|
1507
|
+
this.log?.error(`failed to send message: ${reason}`, {
|
|
1508
|
+
...connectedSession.loggingMetadata,
|
|
1509
|
+
transportMessage: msg2
|
|
1510
|
+
});
|
|
1511
|
+
this.protocolError({
|
|
1512
|
+
type: ProtocolError.MessageSendFailure,
|
|
1513
|
+
message: reason
|
|
1514
|
+
});
|
|
1515
|
+
this.deleteSession(connectedSession, { unhealthy: true });
|
|
1813
1516
|
}
|
|
1814
1517
|
});
|
|
1518
|
+
const res = connectedSession.sendBufferedMessages();
|
|
1519
|
+
if (!res.ok) {
|
|
1520
|
+
return;
|
|
1521
|
+
}
|
|
1815
1522
|
this.updateSession(connectedSession);
|
|
1816
1523
|
this.retryBudget.startRestoringBudget();
|
|
1817
1524
|
}
|
|
@@ -1950,7 +1657,18 @@ var ClientTransport = class extends Transport {
|
|
|
1950
1657
|
...session.loggingMetadata,
|
|
1951
1658
|
transportMessage: requestMsg
|
|
1952
1659
|
});
|
|
1953
|
-
session.sendHandshake(requestMsg);
|
|
1660
|
+
const res = session.sendHandshake(requestMsg);
|
|
1661
|
+
if (!res.ok) {
|
|
1662
|
+
this.log?.error(`failed to send handshake request: ${res.reason}`, {
|
|
1663
|
+
...session.loggingMetadata,
|
|
1664
|
+
transportMessage: requestMsg
|
|
1665
|
+
});
|
|
1666
|
+
this.protocolError({
|
|
1667
|
+
type: ProtocolError.MessageSendFailure,
|
|
1668
|
+
message: res.reason
|
|
1669
|
+
});
|
|
1670
|
+
this.deleteSession(session, { unhealthy: true });
|
|
1671
|
+
}
|
|
1954
1672
|
}
|
|
1955
1673
|
close() {
|
|
1956
1674
|
this.retryBudget.close();
|
|
@@ -1958,96 +1676,9 @@ var ClientTransport = class extends Transport {
|
|
|
1958
1676
|
}
|
|
1959
1677
|
};
|
|
1960
1678
|
|
|
1961
|
-
// transport/connection.ts
|
|
1962
|
-
var Connection = class {
|
|
1963
|
-
id;
|
|
1964
|
-
telemetry;
|
|
1965
|
-
constructor() {
|
|
1966
|
-
this.id = `conn-${generateId()}`;
|
|
1967
|
-
}
|
|
1968
|
-
get loggingMetadata() {
|
|
1969
|
-
const metadata = { connId: this.id };
|
|
1970
|
-
if (this.telemetry?.span.isRecording()) {
|
|
1971
|
-
const spanContext = this.telemetry.span.spanContext();
|
|
1972
|
-
metadata.telemetry = {
|
|
1973
|
-
traceId: spanContext.traceId,
|
|
1974
|
-
spanId: spanContext.spanId
|
|
1975
|
-
};
|
|
1976
|
-
}
|
|
1977
|
-
return metadata;
|
|
1978
|
-
}
|
|
1979
|
-
// can't use event emitter because we need this to work in both node + browser
|
|
1980
|
-
_dataListeners = /* @__PURE__ */ new Set();
|
|
1981
|
-
_closeListeners = /* @__PURE__ */ new Set();
|
|
1982
|
-
_errorListeners = /* @__PURE__ */ new Set();
|
|
1983
|
-
get dataListeners() {
|
|
1984
|
-
return [...this._dataListeners];
|
|
1985
|
-
}
|
|
1986
|
-
get closeListeners() {
|
|
1987
|
-
return [...this._closeListeners];
|
|
1988
|
-
}
|
|
1989
|
-
get errorListeners() {
|
|
1990
|
-
return [...this._errorListeners];
|
|
1991
|
-
}
|
|
1992
|
-
onData(msg) {
|
|
1993
|
-
for (const cb of this.dataListeners) {
|
|
1994
|
-
cb(msg);
|
|
1995
|
-
}
|
|
1996
|
-
}
|
|
1997
|
-
onError(err) {
|
|
1998
|
-
for (const cb of this.errorListeners) {
|
|
1999
|
-
cb(err);
|
|
2000
|
-
}
|
|
2001
|
-
}
|
|
2002
|
-
onClose() {
|
|
2003
|
-
for (const cb of this.closeListeners) {
|
|
2004
|
-
cb();
|
|
2005
|
-
}
|
|
2006
|
-
this.telemetry?.span.end();
|
|
2007
|
-
}
|
|
2008
|
-
/**
|
|
2009
|
-
* Handle adding a callback for when a message is received.
|
|
2010
|
-
* @param msg The message that was received.
|
|
2011
|
-
*/
|
|
2012
|
-
addDataListener(cb) {
|
|
2013
|
-
this._dataListeners.add(cb);
|
|
2014
|
-
}
|
|
2015
|
-
removeDataListener(cb) {
|
|
2016
|
-
this._dataListeners.delete(cb);
|
|
2017
|
-
}
|
|
2018
|
-
/**
|
|
2019
|
-
* Handle adding a callback for when the connection is closed.
|
|
2020
|
-
* This should also be called if an error happens and after notifying all the error listeners.
|
|
2021
|
-
* @param cb The callback to call when the connection is closed.
|
|
2022
|
-
*/
|
|
2023
|
-
addCloseListener(cb) {
|
|
2024
|
-
this._closeListeners.add(cb);
|
|
2025
|
-
}
|
|
2026
|
-
removeCloseListener(cb) {
|
|
2027
|
-
this._closeListeners.delete(cb);
|
|
2028
|
-
}
|
|
2029
|
-
/**
|
|
2030
|
-
* Handle adding a callback for when an error is received.
|
|
2031
|
-
* This should only be used for this.logging errors, all cleanup
|
|
2032
|
-
* should be delegated to addCloseListener.
|
|
2033
|
-
*
|
|
2034
|
-
* The implementer should take care such that the implemented
|
|
2035
|
-
* connection will call both the close and error callbacks
|
|
2036
|
-
* on an error.
|
|
2037
|
-
*
|
|
2038
|
-
* @param cb The callback to call when an error is received.
|
|
2039
|
-
*/
|
|
2040
|
-
addErrorListener(cb) {
|
|
2041
|
-
this._errorListeners.add(cb);
|
|
2042
|
-
}
|
|
2043
|
-
removeErrorListener(cb) {
|
|
2044
|
-
this._errorListeners.delete(cb);
|
|
2045
|
-
}
|
|
2046
|
-
};
|
|
2047
|
-
|
|
2048
1679
|
// transport/server.ts
|
|
2049
1680
|
var import_api5 = require("@opentelemetry/api");
|
|
2050
|
-
var
|
|
1681
|
+
var import_value2 = require("@sinclair/typebox/value");
|
|
2051
1682
|
var ServerTransport = class extends Transport {
|
|
2052
1683
|
/**
|
|
2053
1684
|
* The options for this transport.
|
|
@@ -2087,8 +1718,7 @@ var ServerTransport = class extends Transport {
|
|
|
2087
1718
|
super.deleteSession(session, options);
|
|
2088
1719
|
}
|
|
2089
1720
|
handleConnection(conn) {
|
|
2090
|
-
if (this.getStatus() !== "open")
|
|
2091
|
-
return;
|
|
1721
|
+
if (this.getStatus() !== "open") return;
|
|
2092
1722
|
this.log?.info(`new incoming connection`, {
|
|
2093
1723
|
...conn.loggingMetadata,
|
|
2094
1724
|
clientId: this.clientId
|
|
@@ -2161,17 +1791,28 @@ var ServerTransport = class extends Transport {
|
|
|
2161
1791
|
message: reason
|
|
2162
1792
|
});
|
|
2163
1793
|
this.log?.warn(reason, metadata);
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
)
|
|
1794
|
+
const responseMsg = handshakeResponseMessage({
|
|
1795
|
+
from: this.clientId,
|
|
1796
|
+
to,
|
|
1797
|
+
status: {
|
|
1798
|
+
ok: false,
|
|
1799
|
+
code,
|
|
1800
|
+
reason
|
|
1801
|
+
}
|
|
1802
|
+
});
|
|
1803
|
+
const res = session.sendHandshake(responseMsg);
|
|
1804
|
+
if (!res.ok) {
|
|
1805
|
+
this.log?.error(`failed to send handshake response: ${res.reason}`, {
|
|
1806
|
+
...session.loggingMetadata,
|
|
1807
|
+
transportMessage: responseMsg
|
|
1808
|
+
});
|
|
1809
|
+
this.protocolError({
|
|
1810
|
+
type: ProtocolError.MessageSendFailure,
|
|
1811
|
+
message: res.reason
|
|
1812
|
+
});
|
|
1813
|
+
this.deletePendingSession(session);
|
|
1814
|
+
return;
|
|
1815
|
+
}
|
|
2175
1816
|
this.protocolError({
|
|
2176
1817
|
type: ProtocolError.HandshakeFailed,
|
|
2177
1818
|
code,
|
|
@@ -2180,7 +1821,7 @@ var ServerTransport = class extends Transport {
|
|
|
2180
1821
|
this.deletePendingSession(session);
|
|
2181
1822
|
}
|
|
2182
1823
|
async onHandshakeRequest(session, msg) {
|
|
2183
|
-
if (!
|
|
1824
|
+
if (!import_value2.Value.Check(ControlMessageHandshakeRequestSchema, msg.payload)) {
|
|
2184
1825
|
this.rejectHandshakeRequest(
|
|
2185
1826
|
session,
|
|
2186
1827
|
msg.from,
|
|
@@ -2191,7 +1832,7 @@ var ServerTransport = class extends Transport {
|
|
|
2191
1832
|
transportMessage: msg,
|
|
2192
1833
|
connectedTo: msg.from,
|
|
2193
1834
|
validationErrors: [
|
|
2194
|
-
...
|
|
1835
|
+
...import_value2.Value.Errors(ControlMessageHandshakeRequestSchema, msg.payload)
|
|
2195
1836
|
]
|
|
2196
1837
|
}
|
|
2197
1838
|
);
|
|
@@ -2214,7 +1855,7 @@ var ServerTransport = class extends Transport {
|
|
|
2214
1855
|
}
|
|
2215
1856
|
let parsedMetadata = {};
|
|
2216
1857
|
if (this.handshakeExtensions) {
|
|
2217
|
-
if (!
|
|
1858
|
+
if (!import_value2.Value.Check(this.handshakeExtensions.schema, msg.payload.metadata)) {
|
|
2218
1859
|
this.rejectHandshakeRequest(
|
|
2219
1860
|
session,
|
|
2220
1861
|
msg.from,
|
|
@@ -2224,7 +1865,7 @@ var ServerTransport = class extends Transport {
|
|
|
2224
1865
|
...session.loggingMetadata,
|
|
2225
1866
|
connectedTo: msg.from,
|
|
2226
1867
|
validationErrors: [
|
|
2227
|
-
...
|
|
1868
|
+
...import_value2.Value.Errors(
|
|
2228
1869
|
this.handshakeExtensions.schema,
|
|
2229
1870
|
msg.payload.metadata
|
|
2230
1871
|
)
|
|
@@ -2243,7 +1884,7 @@ var ServerTransport = class extends Transport {
|
|
|
2243
1884
|
if (session._isConsumed) {
|
|
2244
1885
|
return;
|
|
2245
1886
|
}
|
|
2246
|
-
if (
|
|
1887
|
+
if (import_value2.Value.Check(
|
|
2247
1888
|
HandshakeErrorCustomHandlerFatalResponseCodes,
|
|
2248
1889
|
parsedMetadataOrFailureCode
|
|
2249
1890
|
)) {
|
|
@@ -2355,7 +1996,20 @@ var ServerTransport = class extends Transport {
|
|
|
2355
1996
|
sessionId
|
|
2356
1997
|
}
|
|
2357
1998
|
});
|
|
2358
|
-
session.sendHandshake(responseMsg);
|
|
1999
|
+
const res = session.sendHandshake(responseMsg);
|
|
2000
|
+
if (!res.ok) {
|
|
2001
|
+
this.log?.error(`failed to send handshake response: ${res.reason}`, {
|
|
2002
|
+
...session.loggingMetadata,
|
|
2003
|
+
transportMessage: responseMsg
|
|
2004
|
+
});
|
|
2005
|
+
this.protocolError({
|
|
2006
|
+
type: ProtocolError.MessageSendFailure,
|
|
2007
|
+
message: res.reason
|
|
2008
|
+
});
|
|
2009
|
+
this.deletePendingSession(session);
|
|
2010
|
+
return;
|
|
2011
|
+
}
|
|
2012
|
+
this.pendingSessions.delete(session);
|
|
2359
2013
|
const connectedSession = ServerSessionStateGraph.transition.WaitingForHandshakeToConnected(
|
|
2360
2014
|
session,
|
|
2361
2015
|
// by this point oldSession is either no connection or we dont have an old session
|
|
@@ -2382,81 +2036,527 @@ var ServerTransport = class extends Transport {
|
|
|
2382
2036
|
this.handleMsg(msg2);
|
|
2383
2037
|
},
|
|
2384
2038
|
onInvalidMessage: (reason) => {
|
|
2039
|
+
this.log?.error(`invalid message: ${reason}`, {
|
|
2040
|
+
...connectedSession.loggingMetadata,
|
|
2041
|
+
transportMessage: msg
|
|
2042
|
+
});
|
|
2385
2043
|
this.protocolError({
|
|
2386
2044
|
type: ProtocolError.InvalidMessage,
|
|
2387
2045
|
message: reason
|
|
2388
2046
|
});
|
|
2389
2047
|
this.deleteSession(connectedSession, { unhealthy: true });
|
|
2048
|
+
},
|
|
2049
|
+
onMessageSendFailure: (msg2, reason) => {
|
|
2050
|
+
this.log?.error(`failed to send message: ${reason}`, {
|
|
2051
|
+
...connectedSession.loggingMetadata,
|
|
2052
|
+
transportMessage: msg2
|
|
2053
|
+
});
|
|
2054
|
+
this.protocolError({
|
|
2055
|
+
type: ProtocolError.MessageSendFailure,
|
|
2056
|
+
message: reason
|
|
2057
|
+
});
|
|
2058
|
+
this.deleteSession(connectedSession, { unhealthy: true });
|
|
2390
2059
|
}
|
|
2391
2060
|
},
|
|
2392
2061
|
gotVersion
|
|
2393
2062
|
);
|
|
2063
|
+
const bufferSendRes = connectedSession.sendBufferedMessages();
|
|
2064
|
+
if (!bufferSendRes.ok) {
|
|
2065
|
+
return;
|
|
2066
|
+
}
|
|
2394
2067
|
this.sessionHandshakeMetadata.set(connectedSession.to, parsedMetadata);
|
|
2395
2068
|
if (oldSession) {
|
|
2396
2069
|
this.updateSession(connectedSession);
|
|
2397
2070
|
} else {
|
|
2398
2071
|
this.createSession(connectedSession);
|
|
2399
2072
|
}
|
|
2400
|
-
this.pendingSessions.delete(session);
|
|
2401
2073
|
connectedSession.startActiveHeartbeat();
|
|
2402
2074
|
}
|
|
2403
2075
|
};
|
|
2404
2076
|
|
|
2405
|
-
//
|
|
2406
|
-
var
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
constructor(
|
|
2410
|
-
this.
|
|
2411
|
-
this.listeners = /* @__PURE__ */ new Set();
|
|
2077
|
+
// transport/connection.ts
|
|
2078
|
+
var Connection = class {
|
|
2079
|
+
id;
|
|
2080
|
+
telemetry;
|
|
2081
|
+
constructor() {
|
|
2082
|
+
this.id = `conn-${generateId()}`;
|
|
2412
2083
|
}
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2084
|
+
get loggingMetadata() {
|
|
2085
|
+
const metadata = { connId: this.id };
|
|
2086
|
+
if (this.telemetry?.span.isRecording()) {
|
|
2087
|
+
const spanContext = this.telemetry.span.spanContext();
|
|
2088
|
+
metadata.telemetry = {
|
|
2089
|
+
traceId: spanContext.traceId,
|
|
2090
|
+
spanId: spanContext.spanId
|
|
2091
|
+
};
|
|
2092
|
+
}
|
|
2093
|
+
return metadata;
|
|
2094
|
+
}
|
|
2095
|
+
dataListener;
|
|
2096
|
+
closeListener;
|
|
2097
|
+
errorListener;
|
|
2098
|
+
onData(msg) {
|
|
2099
|
+
this.dataListener?.(msg);
|
|
2100
|
+
}
|
|
2101
|
+
onError(err) {
|
|
2102
|
+
this.errorListener?.(err);
|
|
2103
|
+
}
|
|
2104
|
+
onClose() {
|
|
2105
|
+
this.closeListener?.();
|
|
2106
|
+
this.telemetry?.span.end();
|
|
2418
2107
|
}
|
|
2419
2108
|
/**
|
|
2420
|
-
*
|
|
2421
|
-
* @param
|
|
2109
|
+
* Set the callback for when a message is received.
|
|
2110
|
+
* @param cb The message handler callback.
|
|
2422
2111
|
*/
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2112
|
+
setDataListener(cb) {
|
|
2113
|
+
this.dataListener = cb;
|
|
2114
|
+
}
|
|
2115
|
+
removeDataListener() {
|
|
2116
|
+
this.dataListener = void 0;
|
|
2427
2117
|
}
|
|
2428
2118
|
/**
|
|
2429
|
-
*
|
|
2430
|
-
*
|
|
2431
|
-
* @
|
|
2119
|
+
* Set the callback for when the connection is closed.
|
|
2120
|
+
* This should also be called if an error happens and after notifying the error listener.
|
|
2121
|
+
* @param cb The callback to call when the connection is closed.
|
|
2432
2122
|
*/
|
|
2433
|
-
|
|
2434
|
-
this.
|
|
2435
|
-
|
|
2436
|
-
|
|
2123
|
+
setCloseListener(cb) {
|
|
2124
|
+
this.closeListener = cb;
|
|
2125
|
+
}
|
|
2126
|
+
removeCloseListener() {
|
|
2127
|
+
this.closeListener = void 0;
|
|
2437
2128
|
}
|
|
2438
2129
|
/**
|
|
2439
|
-
*
|
|
2130
|
+
* Set the callback for when an error is received.
|
|
2131
|
+
* This should only be used for logging errors, all cleanup
|
|
2132
|
+
* should be delegated to setCloseListener.
|
|
2133
|
+
*
|
|
2134
|
+
* The implementer should take care such that the implemented
|
|
2135
|
+
* connection will call both the close and error callbacks
|
|
2136
|
+
* on an error.
|
|
2137
|
+
*
|
|
2138
|
+
* @param cb The callback to call when an error is received.
|
|
2440
2139
|
*/
|
|
2441
|
-
|
|
2442
|
-
|
|
2140
|
+
setErrorListener(cb) {
|
|
2141
|
+
this.errorListener = cb;
|
|
2142
|
+
}
|
|
2143
|
+
removeErrorListener() {
|
|
2144
|
+
this.errorListener = void 0;
|
|
2443
2145
|
}
|
|
2444
2146
|
};
|
|
2445
2147
|
|
|
2446
|
-
//
|
|
2447
|
-
var
|
|
2448
|
-
|
|
2449
|
-
|
|
2450
|
-
var kInitOtherSide = Symbol("InitOtherSide");
|
|
2451
|
-
var DuplexSide = class extends import_node_stream.Duplex {
|
|
2452
|
-
otherSide;
|
|
2453
|
-
[kCallback];
|
|
2454
|
-
constructor() {
|
|
2455
|
-
super();
|
|
2456
|
-
this[kCallback] = null;
|
|
2457
|
-
this.otherSide = null;
|
|
2148
|
+
// codec/adapter.ts
|
|
2149
|
+
var CodecMessageAdapter = class {
|
|
2150
|
+
constructor(codec) {
|
|
2151
|
+
this.codec = codec;
|
|
2458
2152
|
}
|
|
2459
|
-
|
|
2153
|
+
toBuffer(msg) {
|
|
2154
|
+
try {
|
|
2155
|
+
return {
|
|
2156
|
+
ok: true,
|
|
2157
|
+
value: this.codec.toBuffer(msg)
|
|
2158
|
+
};
|
|
2159
|
+
} catch (e) {
|
|
2160
|
+
return {
|
|
2161
|
+
ok: false,
|
|
2162
|
+
reason: coerceErrorString(e)
|
|
2163
|
+
};
|
|
2164
|
+
}
|
|
2165
|
+
}
|
|
2166
|
+
fromBuffer(buf) {
|
|
2167
|
+
try {
|
|
2168
|
+
const parsedMsg = this.codec.fromBuffer(buf);
|
|
2169
|
+
if (!import_value3.Value.Check(OpaqueTransportMessageSchema, parsedMsg)) {
|
|
2170
|
+
return {
|
|
2171
|
+
ok: false,
|
|
2172
|
+
reason: "transport message schema mismatch"
|
|
2173
|
+
};
|
|
2174
|
+
}
|
|
2175
|
+
return {
|
|
2176
|
+
ok: true,
|
|
2177
|
+
value: parsedMsg
|
|
2178
|
+
};
|
|
2179
|
+
} catch (e) {
|
|
2180
|
+
return {
|
|
2181
|
+
ok: false,
|
|
2182
|
+
reason: coerceErrorString(e)
|
|
2183
|
+
};
|
|
2184
|
+
}
|
|
2185
|
+
}
|
|
2186
|
+
};
|
|
2187
|
+
|
|
2188
|
+
// transport/sessionStateMachine/transitions.ts
|
|
2189
|
+
function inheritSharedSession(session) {
|
|
2190
|
+
return {
|
|
2191
|
+
id: session.id,
|
|
2192
|
+
from: session.from,
|
|
2193
|
+
to: session.to,
|
|
2194
|
+
seq: session.seq,
|
|
2195
|
+
ack: session.ack,
|
|
2196
|
+
seqSent: session.seqSent,
|
|
2197
|
+
sendBuffer: session.sendBuffer,
|
|
2198
|
+
telemetry: session.telemetry,
|
|
2199
|
+
options: session.options,
|
|
2200
|
+
log: session.log,
|
|
2201
|
+
tracer: session.tracer,
|
|
2202
|
+
protocolVersion: session.protocolVersion,
|
|
2203
|
+
codec: session.codec
|
|
2204
|
+
};
|
|
2205
|
+
}
|
|
2206
|
+
function inheritSharedSessionWithGrace(session) {
|
|
2207
|
+
return {
|
|
2208
|
+
...inheritSharedSession(session),
|
|
2209
|
+
graceExpiryTime: session.graceExpiryTime
|
|
2210
|
+
};
|
|
2211
|
+
}
|
|
2212
|
+
var SessionStateGraph = {
|
|
2213
|
+
entrypoints: {
|
|
2214
|
+
NoConnection: (to, from, listeners, options, protocolVersion, tracer, log) => {
|
|
2215
|
+
const id = `session-${generateId()}`;
|
|
2216
|
+
const telemetry = createSessionTelemetryInfo(tracer, id, to, from);
|
|
2217
|
+
const sendBuffer = [];
|
|
2218
|
+
const session = new SessionNoConnection({
|
|
2219
|
+
listeners,
|
|
2220
|
+
id,
|
|
2221
|
+
from,
|
|
2222
|
+
to,
|
|
2223
|
+
seq: 0,
|
|
2224
|
+
ack: 0,
|
|
2225
|
+
seqSent: 0,
|
|
2226
|
+
graceExpiryTime: Date.now() + options.sessionDisconnectGraceMs,
|
|
2227
|
+
sendBuffer,
|
|
2228
|
+
telemetry,
|
|
2229
|
+
options,
|
|
2230
|
+
protocolVersion,
|
|
2231
|
+
tracer,
|
|
2232
|
+
log,
|
|
2233
|
+
codec: new CodecMessageAdapter(options.codec)
|
|
2234
|
+
});
|
|
2235
|
+
session.log?.info(`session ${session.id} created in NoConnection state`, {
|
|
2236
|
+
...session.loggingMetadata,
|
|
2237
|
+
tags: ["state-transition"]
|
|
2238
|
+
});
|
|
2239
|
+
return session;
|
|
2240
|
+
},
|
|
2241
|
+
WaitingForHandshake: (from, conn, listeners, options, tracer, log) => {
|
|
2242
|
+
const session = new SessionWaitingForHandshake({
|
|
2243
|
+
conn,
|
|
2244
|
+
listeners,
|
|
2245
|
+
from,
|
|
2246
|
+
options,
|
|
2247
|
+
tracer,
|
|
2248
|
+
log,
|
|
2249
|
+
codec: new CodecMessageAdapter(options.codec)
|
|
2250
|
+
});
|
|
2251
|
+
session.log?.info(`session created in WaitingForHandshake state`, {
|
|
2252
|
+
...session.loggingMetadata,
|
|
2253
|
+
tags: ["state-transition"]
|
|
2254
|
+
});
|
|
2255
|
+
return session;
|
|
2256
|
+
}
|
|
2257
|
+
},
|
|
2258
|
+
// All of the transitions 'move'/'consume' the old session and return a new one.
|
|
2259
|
+
// After a session is transitioned, any usage of the old session will throw.
|
|
2260
|
+
transition: {
|
|
2261
|
+
// happy path transitions
|
|
2262
|
+
NoConnectionToBackingOff: (oldSession, backoffMs, listeners) => {
|
|
2263
|
+
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
2264
|
+
oldSession._handleStateExit();
|
|
2265
|
+
const session = new SessionBackingOff({
|
|
2266
|
+
backoffMs,
|
|
2267
|
+
listeners,
|
|
2268
|
+
...carriedState
|
|
2269
|
+
});
|
|
2270
|
+
session.log?.info(
|
|
2271
|
+
`session ${session.id} transition from NoConnection to BackingOff`,
|
|
2272
|
+
{
|
|
2273
|
+
...session.loggingMetadata,
|
|
2274
|
+
tags: ["state-transition"]
|
|
2275
|
+
}
|
|
2276
|
+
);
|
|
2277
|
+
return session;
|
|
2278
|
+
},
|
|
2279
|
+
BackingOffToConnecting: (oldSession, connPromise, listeners) => {
|
|
2280
|
+
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
2281
|
+
oldSession._handleStateExit();
|
|
2282
|
+
const session = new SessionConnecting({
|
|
2283
|
+
connPromise,
|
|
2284
|
+
listeners,
|
|
2285
|
+
...carriedState
|
|
2286
|
+
});
|
|
2287
|
+
session.log?.info(
|
|
2288
|
+
`session ${session.id} transition from BackingOff to Connecting`,
|
|
2289
|
+
{
|
|
2290
|
+
...session.loggingMetadata,
|
|
2291
|
+
tags: ["state-transition"]
|
|
2292
|
+
}
|
|
2293
|
+
);
|
|
2294
|
+
return session;
|
|
2295
|
+
},
|
|
2296
|
+
ConnectingToHandshaking: (oldSession, conn, listeners) => {
|
|
2297
|
+
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
2298
|
+
oldSession._handleStateExit();
|
|
2299
|
+
const session = new SessionHandshaking({
|
|
2300
|
+
conn,
|
|
2301
|
+
listeners,
|
|
2302
|
+
...carriedState
|
|
2303
|
+
});
|
|
2304
|
+
conn.telemetry = createConnectionTelemetryInfo(
|
|
2305
|
+
session.tracer,
|
|
2306
|
+
conn,
|
|
2307
|
+
session.telemetry
|
|
2308
|
+
);
|
|
2309
|
+
session.log?.info(
|
|
2310
|
+
`session ${session.id} transition from Connecting to Handshaking`,
|
|
2311
|
+
{
|
|
2312
|
+
...session.loggingMetadata,
|
|
2313
|
+
tags: ["state-transition"]
|
|
2314
|
+
}
|
|
2315
|
+
);
|
|
2316
|
+
return session;
|
|
2317
|
+
},
|
|
2318
|
+
HandshakingToConnected: (oldSession, listeners) => {
|
|
2319
|
+
const carriedState = inheritSharedSession(oldSession);
|
|
2320
|
+
const conn = oldSession.conn;
|
|
2321
|
+
oldSession._handleStateExit();
|
|
2322
|
+
const session = new SessionConnected({
|
|
2323
|
+
conn,
|
|
2324
|
+
listeners,
|
|
2325
|
+
...carriedState
|
|
2326
|
+
});
|
|
2327
|
+
session.startMissingHeartbeatTimeout();
|
|
2328
|
+
session.log?.info(
|
|
2329
|
+
`session ${session.id} transition from Handshaking to Connected`,
|
|
2330
|
+
{
|
|
2331
|
+
...session.loggingMetadata,
|
|
2332
|
+
tags: ["state-transition"]
|
|
2333
|
+
}
|
|
2334
|
+
);
|
|
2335
|
+
return session;
|
|
2336
|
+
},
|
|
2337
|
+
WaitingForHandshakeToConnected: (pendingSession, oldSession, sessionId, to, propagationCtx, listeners, protocolVersion) => {
|
|
2338
|
+
const conn = pendingSession.conn;
|
|
2339
|
+
const { from, options } = pendingSession;
|
|
2340
|
+
const carriedState = oldSession ? (
|
|
2341
|
+
// old session exists, inherit state
|
|
2342
|
+
inheritSharedSession(oldSession)
|
|
2343
|
+
) : (
|
|
2344
|
+
// old session does not exist, create new state
|
|
2345
|
+
{
|
|
2346
|
+
id: sessionId,
|
|
2347
|
+
from,
|
|
2348
|
+
to,
|
|
2349
|
+
seq: 0,
|
|
2350
|
+
ack: 0,
|
|
2351
|
+
seqSent: 0,
|
|
2352
|
+
sendBuffer: [],
|
|
2353
|
+
telemetry: createSessionTelemetryInfo(
|
|
2354
|
+
pendingSession.tracer,
|
|
2355
|
+
sessionId,
|
|
2356
|
+
to,
|
|
2357
|
+
from,
|
|
2358
|
+
propagationCtx
|
|
2359
|
+
),
|
|
2360
|
+
options,
|
|
2361
|
+
tracer: pendingSession.tracer,
|
|
2362
|
+
log: pendingSession.log,
|
|
2363
|
+
protocolVersion,
|
|
2364
|
+
codec: new CodecMessageAdapter(options.codec)
|
|
2365
|
+
}
|
|
2366
|
+
);
|
|
2367
|
+
pendingSession._handleStateExit();
|
|
2368
|
+
oldSession?._handleStateExit();
|
|
2369
|
+
const session = new SessionConnected({
|
|
2370
|
+
conn,
|
|
2371
|
+
listeners,
|
|
2372
|
+
...carriedState
|
|
2373
|
+
});
|
|
2374
|
+
session.startMissingHeartbeatTimeout();
|
|
2375
|
+
conn.telemetry = createConnectionTelemetryInfo(
|
|
2376
|
+
session.tracer,
|
|
2377
|
+
conn,
|
|
2378
|
+
session.telemetry
|
|
2379
|
+
);
|
|
2380
|
+
session.log?.info(
|
|
2381
|
+
`session ${session.id} transition from WaitingForHandshake to Connected`,
|
|
2382
|
+
{
|
|
2383
|
+
...session.loggingMetadata,
|
|
2384
|
+
tags: ["state-transition"]
|
|
2385
|
+
}
|
|
2386
|
+
);
|
|
2387
|
+
return session;
|
|
2388
|
+
},
|
|
2389
|
+
// disconnect paths
|
|
2390
|
+
BackingOffToNoConnection: (oldSession, listeners) => {
|
|
2391
|
+
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
2392
|
+
oldSession._handleStateExit();
|
|
2393
|
+
const session = new SessionNoConnection({
|
|
2394
|
+
listeners,
|
|
2395
|
+
...carriedState
|
|
2396
|
+
});
|
|
2397
|
+
session.log?.info(
|
|
2398
|
+
`session ${session.id} transition from BackingOff to NoConnection`,
|
|
2399
|
+
{
|
|
2400
|
+
...session.loggingMetadata,
|
|
2401
|
+
tags: ["state-transition"]
|
|
2402
|
+
}
|
|
2403
|
+
);
|
|
2404
|
+
return session;
|
|
2405
|
+
},
|
|
2406
|
+
ConnectingToNoConnection: (oldSession, listeners) => {
|
|
2407
|
+
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
2408
|
+
oldSession.bestEffortClose();
|
|
2409
|
+
oldSession._handleStateExit();
|
|
2410
|
+
const session = new SessionNoConnection({
|
|
2411
|
+
listeners,
|
|
2412
|
+
...carriedState
|
|
2413
|
+
});
|
|
2414
|
+
session.log?.info(
|
|
2415
|
+
`session ${session.id} transition from Connecting to NoConnection`,
|
|
2416
|
+
{
|
|
2417
|
+
...session.loggingMetadata,
|
|
2418
|
+
tags: ["state-transition"]
|
|
2419
|
+
}
|
|
2420
|
+
);
|
|
2421
|
+
return session;
|
|
2422
|
+
},
|
|
2423
|
+
HandshakingToNoConnection: (oldSession, listeners) => {
|
|
2424
|
+
const carriedState = inheritSharedSessionWithGrace(oldSession);
|
|
2425
|
+
oldSession.conn.close();
|
|
2426
|
+
oldSession._handleStateExit();
|
|
2427
|
+
const session = new SessionNoConnection({
|
|
2428
|
+
listeners,
|
|
2429
|
+
...carriedState
|
|
2430
|
+
});
|
|
2431
|
+
session.log?.info(
|
|
2432
|
+
`session ${session.id} transition from Handshaking to NoConnection`,
|
|
2433
|
+
{
|
|
2434
|
+
...session.loggingMetadata,
|
|
2435
|
+
tags: ["state-transition"]
|
|
2436
|
+
}
|
|
2437
|
+
);
|
|
2438
|
+
return session;
|
|
2439
|
+
},
|
|
2440
|
+
ConnectedToNoConnection: (oldSession, listeners) => {
|
|
2441
|
+
const carriedState = inheritSharedSession(oldSession);
|
|
2442
|
+
const graceExpiryTime = Date.now() + oldSession.options.sessionDisconnectGraceMs;
|
|
2443
|
+
oldSession.conn.close();
|
|
2444
|
+
oldSession._handleStateExit();
|
|
2445
|
+
const session = new SessionNoConnection({
|
|
2446
|
+
listeners,
|
|
2447
|
+
graceExpiryTime,
|
|
2448
|
+
...carriedState
|
|
2449
|
+
});
|
|
2450
|
+
session.log?.info(
|
|
2451
|
+
`session ${session.id} transition from Connected to NoConnection`,
|
|
2452
|
+
{
|
|
2453
|
+
...session.loggingMetadata,
|
|
2454
|
+
tags: ["state-transition"]
|
|
2455
|
+
}
|
|
2456
|
+
);
|
|
2457
|
+
return session;
|
|
2458
|
+
}
|
|
2459
|
+
}
|
|
2460
|
+
};
|
|
2461
|
+
var transitions = SessionStateGraph.transition;
|
|
2462
|
+
var ClientSessionStateGraph = {
|
|
2463
|
+
entrypoint: SessionStateGraph.entrypoints.NoConnection,
|
|
2464
|
+
transition: {
|
|
2465
|
+
// happy paths
|
|
2466
|
+
// NoConnection -> BackingOff: attempt to connect
|
|
2467
|
+
NoConnectionToBackingOff: transitions.NoConnectionToBackingOff,
|
|
2468
|
+
// BackingOff -> Connecting: backoff period elapsed, start connection
|
|
2469
|
+
BackingOffToConnecting: transitions.BackingOffToConnecting,
|
|
2470
|
+
// Connecting -> Handshaking: connection established, start handshake
|
|
2471
|
+
ConnectingToHandshaking: transitions.ConnectingToHandshaking,
|
|
2472
|
+
// Handshaking -> Connected: handshake complete, session ready
|
|
2473
|
+
HandshakingToConnected: transitions.HandshakingToConnected,
|
|
2474
|
+
// disconnect paths
|
|
2475
|
+
// BackingOff -> NoConnection: unused
|
|
2476
|
+
BackingOffToNoConnection: transitions.BackingOffToNoConnection,
|
|
2477
|
+
// Connecting -> NoConnection: connection failed or connection timeout
|
|
2478
|
+
ConnectingToNoConnection: transitions.ConnectingToNoConnection,
|
|
2479
|
+
// Handshaking -> NoConnection: connection closed or handshake timeout
|
|
2480
|
+
HandshakingToNoConnection: transitions.HandshakingToNoConnection,
|
|
2481
|
+
// Connected -> NoConnection: connection closed
|
|
2482
|
+
ConnectedToNoConnection: transitions.ConnectedToNoConnection
|
|
2483
|
+
// destroy/close paths
|
|
2484
|
+
// NoConnection -> x: grace period elapsed
|
|
2485
|
+
// BackingOff -> x: grace period elapsed
|
|
2486
|
+
// Connecting -> x: grace period elapsed
|
|
2487
|
+
// Handshaking -> x: grace period elapsed or invalid handshake message or handshake rejection
|
|
2488
|
+
// Connected -> x: grace period elapsed or invalid message
|
|
2489
|
+
}
|
|
2490
|
+
};
|
|
2491
|
+
var ServerSessionStateGraph = {
|
|
2492
|
+
entrypoint: SessionStateGraph.entrypoints.WaitingForHandshake,
|
|
2493
|
+
transition: {
|
|
2494
|
+
// happy paths
|
|
2495
|
+
// WaitingForHandshake -> Connected: handshake complete, session ready
|
|
2496
|
+
WaitingForHandshakeToConnected: transitions.WaitingForHandshakeToConnected,
|
|
2497
|
+
// disconnect paths
|
|
2498
|
+
// Connected -> NoConnection: connection closed
|
|
2499
|
+
ConnectedToNoConnection: transitions.ConnectedToNoConnection
|
|
2500
|
+
// destroy/close paths
|
|
2501
|
+
// WaitingForHandshake -> x: handshake timeout elapsed or invalid handshake message or handshake rejection or connection closed
|
|
2502
|
+
}
|
|
2503
|
+
};
|
|
2504
|
+
|
|
2505
|
+
// testUtil/observable/observable.ts
|
|
2506
|
+
var Observable = class {
|
|
2507
|
+
value;
|
|
2508
|
+
listeners;
|
|
2509
|
+
constructor(initialValue) {
|
|
2510
|
+
this.value = initialValue;
|
|
2511
|
+
this.listeners = /* @__PURE__ */ new Set();
|
|
2512
|
+
}
|
|
2513
|
+
/**
|
|
2514
|
+
* Gets the current value of the observable.
|
|
2515
|
+
*/
|
|
2516
|
+
get() {
|
|
2517
|
+
return this.value;
|
|
2518
|
+
}
|
|
2519
|
+
/**
|
|
2520
|
+
* Sets the current value of the observable. All listeners will get an update with this value.
|
|
2521
|
+
* @param newValue - The new value to set.
|
|
2522
|
+
*/
|
|
2523
|
+
set(tx) {
|
|
2524
|
+
const newValue = tx(this.value);
|
|
2525
|
+
this.value = newValue;
|
|
2526
|
+
this.listeners.forEach((listener) => listener(newValue));
|
|
2527
|
+
}
|
|
2528
|
+
/**
|
|
2529
|
+
* Subscribes to changes in the observable value.
|
|
2530
|
+
* @param listener - A callback function that will be called when the value changes.
|
|
2531
|
+
* @returns A function that can be called to unsubscribe from further notifications.
|
|
2532
|
+
*/
|
|
2533
|
+
observe(listener) {
|
|
2534
|
+
this.listeners.add(listener);
|
|
2535
|
+
listener(this.get());
|
|
2536
|
+
return () => this.listeners.delete(listener);
|
|
2537
|
+
}
|
|
2538
|
+
/**
|
|
2539
|
+
* Returns the number of listeners currently observing the observable
|
|
2540
|
+
*/
|
|
2541
|
+
get listenerCount() {
|
|
2542
|
+
return this.listeners.size;
|
|
2543
|
+
}
|
|
2544
|
+
};
|
|
2545
|
+
|
|
2546
|
+
// testUtil/duplex/duplexPair.ts
|
|
2547
|
+
var import_node_stream = require("stream");
|
|
2548
|
+
var import_assert = __toESM(require("assert"), 1);
|
|
2549
|
+
var kCallback = Symbol("Callback");
|
|
2550
|
+
var kInitOtherSide = Symbol("InitOtherSide");
|
|
2551
|
+
var DuplexSide = class extends import_node_stream.Duplex {
|
|
2552
|
+
otherSide;
|
|
2553
|
+
[kCallback];
|
|
2554
|
+
constructor() {
|
|
2555
|
+
super();
|
|
2556
|
+
this[kCallback] = null;
|
|
2557
|
+
this.otherSide = null;
|
|
2558
|
+
}
|
|
2559
|
+
[kInitOtherSide](otherSide) {
|
|
2460
2560
|
if (this.otherSide === null) {
|
|
2461
2561
|
this.otherSide = otherSide;
|
|
2462
2562
|
}
|
|
@@ -2488,6 +2588,16 @@ function duplexPair() {
|
|
|
2488
2588
|
const side1 = new DuplexSide();
|
|
2489
2589
|
side0[kInitOtherSide](side1);
|
|
2490
2590
|
side1[kInitOtherSide](side0);
|
|
2591
|
+
side0.on("close", () => {
|
|
2592
|
+
setImmediate(() => {
|
|
2593
|
+
side1.destroy();
|
|
2594
|
+
});
|
|
2595
|
+
});
|
|
2596
|
+
side1.on("close", () => {
|
|
2597
|
+
setImmediate(() => {
|
|
2598
|
+
side0.destroy();
|
|
2599
|
+
});
|
|
2600
|
+
});
|
|
2491
2601
|
return [side0, side1];
|
|
2492
2602
|
}
|
|
2493
2603
|
|
|
@@ -2500,19 +2610,13 @@ var InMemoryConnection = class extends Connection {
|
|
|
2500
2610
|
this.conn = pipe;
|
|
2501
2611
|
this.conn.allowHalfOpen = false;
|
|
2502
2612
|
this.conn.on("data", (data) => {
|
|
2503
|
-
|
|
2504
|
-
cb(data);
|
|
2505
|
-
}
|
|
2613
|
+
this.dataListener?.(data);
|
|
2506
2614
|
});
|
|
2507
2615
|
this.conn.on("close", () => {
|
|
2508
|
-
|
|
2509
|
-
cb();
|
|
2510
|
-
}
|
|
2616
|
+
this.closeListener?.();
|
|
2511
2617
|
});
|
|
2512
2618
|
this.conn.on("error", (err) => {
|
|
2513
|
-
|
|
2514
|
-
cb(err);
|
|
2515
|
-
}
|
|
2619
|
+
this.errorListener?.(err);
|
|
2516
2620
|
});
|
|
2517
2621
|
}
|
|
2518
2622
|
send(payload) {
|
|
@@ -2595,19 +2699,18 @@ function createMockTransportNetwork(opts) {
|
|
|
2595
2699
|
},
|
|
2596
2700
|
async restartServer() {
|
|
2597
2701
|
for (const transport of transports) {
|
|
2598
|
-
if (transport.clientId !== "SERVER")
|
|
2599
|
-
continue;
|
|
2702
|
+
if (transport.clientId !== "SERVER") continue;
|
|
2600
2703
|
transport.close();
|
|
2601
2704
|
}
|
|
2602
2705
|
for (const conn of Object.values(connections.get())) {
|
|
2603
|
-
conn.serverToClient.
|
|
2604
|
-
conn.clientToServer.
|
|
2706
|
+
conn.serverToClient.destroy();
|
|
2707
|
+
conn.clientToServer.destroy();
|
|
2605
2708
|
}
|
|
2606
2709
|
},
|
|
2607
2710
|
cleanup() {
|
|
2608
2711
|
for (const conn of Object.values(connections.get())) {
|
|
2609
|
-
conn.serverToClient.
|
|
2610
|
-
conn.clientToServer.
|
|
2712
|
+
conn.serverToClient.destroy();
|
|
2713
|
+
conn.clientToServer.destroy();
|
|
2611
2714
|
}
|
|
2612
2715
|
}
|
|
2613
2716
|
};
|