@zlink-systems/stream-connector 0.24.0 → 0.26.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/browser/Runtime/Calls/ZlinkStreamCallBuilders.d.ts +2 -1
- package/dist/browser/Runtime/Transport/BrowserWebSocketConnection.d.ts +5 -0
- package/dist/browser/Runtime/ZlinkStreamActors.d.ts +0 -1
- package/dist/browser/Runtime/ZlinkStreamConnector.d.ts +1 -1
- package/dist/browser/Runtime/ZlinkStreamConnectorEvents.d.ts +18 -3
- package/dist/browser/Runtime/ZlinkStreamConnectorLifecycle.d.ts +34 -30
- package/dist/browser/Runtime/ZlinkStreamFrameSender.d.ts +21 -5
- package/dist/browser/Runtime/ZlinkStreamPendingRequests.d.ts +2 -2
- package/dist/browser/Runtime/ZlinkStreamReceiveDispatcher.d.ts +21 -5
- package/dist/browser/Runtime/ZlinkStreamReceivedMessages.d.ts +35 -14
- package/dist/browser/index.global.js +887 -611
- package/dist/browser/index.mjs +858 -578
- package/package.json +2 -2
|
@@ -53,11 +53,7 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
53
53
|
pickled.set(payload, 1);
|
|
54
54
|
return pickled;
|
|
55
55
|
}
|
|
56
|
-
function
|
|
57
|
-
const maxDecompressedSize = maxSize != null ? maxSize : defaultMaxDecompressedPayloadSize;
|
|
58
|
-
if (payload.length === 0) {
|
|
59
|
-
return new Uint8Array();
|
|
60
|
-
}
|
|
56
|
+
function readLz4Pickle(payload) {
|
|
61
57
|
const header = payload[0];
|
|
62
58
|
if ((header & 7) !== 0) {
|
|
63
59
|
throw new Error("Unexpected LZ4 pickle version.");
|
|
@@ -69,7 +65,17 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
69
65
|
}
|
|
70
66
|
const data = payload.subarray(dataOffset);
|
|
71
67
|
const resultDiff = sizeOfDiff === 0 ? 0 : readLittleEndian(payload, 1, sizeOfDiff);
|
|
72
|
-
|
|
68
|
+
return { data, resultDiff, resultLength: data.length + resultDiff };
|
|
69
|
+
}
|
|
70
|
+
function lz4PickledLength(payload) {
|
|
71
|
+
return payload.length === 0 ? 0 : readLz4Pickle(payload).resultLength;
|
|
72
|
+
}
|
|
73
|
+
function lz4UnpicklePayload(payload, maxSize) {
|
|
74
|
+
const maxDecompressedSize = maxSize != null ? maxSize : defaultMaxDecompressedPayloadSize;
|
|
75
|
+
if (payload.length === 0) {
|
|
76
|
+
return new Uint8Array();
|
|
77
|
+
}
|
|
78
|
+
const { data, resultDiff, resultLength } = readLz4Pickle(payload);
|
|
73
79
|
if (resultLength > maxDecompressedSize) {
|
|
74
80
|
throw new Error("LZ4 decoded payload exceeds maximum stream payload size.");
|
|
75
81
|
}
|
|
@@ -420,6 +426,9 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
420
426
|
function lz4PickleUncompressed2(payload) {
|
|
421
427
|
return lz4PickleUncompressed(payload);
|
|
422
428
|
}
|
|
429
|
+
function lz4PickledLength2(payload) {
|
|
430
|
+
return lz4PickledLength(payload);
|
|
431
|
+
}
|
|
423
432
|
function lz4UnpicklePayload2(payload, maxDecompressedSize) {
|
|
424
433
|
return lz4UnpicklePayload(payload, maxDecompressedSize != null ? maxDecompressedSize : defaultMaxDecompressedPayloadSize);
|
|
425
434
|
}
|
|
@@ -864,9 +873,10 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
864
873
|
}
|
|
865
874
|
};
|
|
866
875
|
var ZlinkStreamRequestBuilder = class {
|
|
867
|
-
constructor(connector, name, payload, actorSlot, validateActor) {
|
|
876
|
+
constructor(connector, name, payload, enqueueCallback, actorSlot, validateActor) {
|
|
868
877
|
this.connector = connector;
|
|
869
878
|
this.payload = payload;
|
|
879
|
+
this.enqueueCallback = enqueueCallback;
|
|
870
880
|
__publicField(this, "state");
|
|
871
881
|
this.state = new ZlinkStreamCallBuilderState(name, actorSlot, validateActor);
|
|
872
882
|
}
|
|
@@ -901,8 +911,10 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
901
911
|
);
|
|
902
912
|
if (typeof signalOrCallback === "function") {
|
|
903
913
|
operation.then(
|
|
904
|
-
(value) => signalOrCallback({ isSuccess: true, value }),
|
|
905
|
-
(error) =>
|
|
914
|
+
(value) => this.enqueueCallback(() => signalOrCallback({ isSuccess: true, value })),
|
|
915
|
+
(error) => this.enqueueCallback(
|
|
916
|
+
() => signalOrCallback({ isSuccess: false, error: unwrapStreamError(error) })
|
|
917
|
+
)
|
|
906
918
|
);
|
|
907
919
|
return;
|
|
908
920
|
}
|
|
@@ -1113,6 +1125,12 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
1113
1125
|
return lz4PickleUncompressed2(payload);
|
|
1114
1126
|
},
|
|
1115
1127
|
decompress(payload, maxDecompressedSize) {
|
|
1128
|
+
if (lz4PickledLength2(payload) > maxDecompressedSize) {
|
|
1129
|
+
throw connectorError(
|
|
1130
|
+
"frameTooLarge" /* FrameTooLarge */,
|
|
1131
|
+
"LZ4 decoded payload exceeds MaxReceivePayloadSize."
|
|
1132
|
+
);
|
|
1133
|
+
}
|
|
1116
1134
|
return lz4UnpicklePayload2(payload, maxDecompressedSize);
|
|
1117
1135
|
}
|
|
1118
1136
|
};
|
|
@@ -1124,7 +1142,11 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
1124
1142
|
"Compression codec is not configured."
|
|
1125
1143
|
);
|
|
1126
1144
|
}
|
|
1127
|
-
|
|
1145
|
+
try {
|
|
1146
|
+
return codec.compress(payload);
|
|
1147
|
+
} catch (cause) {
|
|
1148
|
+
throw connectorError("compressionFailed" /* CompressionFailed */, "Compression failed.", cause);
|
|
1149
|
+
}
|
|
1128
1150
|
}
|
|
1129
1151
|
function decompressIfNeeded(header, payload, compression, compressionCodec, maxDecompressedSize) {
|
|
1130
1152
|
if ((header.flags & 4 /* PayloadCompressed */) === 0) {
|
|
@@ -1137,15 +1159,20 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
1137
1159
|
"Compression codec is not configured."
|
|
1138
1160
|
);
|
|
1139
1161
|
}
|
|
1162
|
+
let decompressed;
|
|
1140
1163
|
try {
|
|
1141
|
-
|
|
1142
|
-
if (decompressed.length > maxDecompressedSize) {
|
|
1143
|
-
throw new Error("Decoded payload exceeds MaxReceivePayloadSize.");
|
|
1144
|
-
}
|
|
1145
|
-
return decompressed;
|
|
1164
|
+
decompressed = codec.decompress(payload, maxDecompressedSize);
|
|
1146
1165
|
} catch (cause) {
|
|
1166
|
+
if (cause instanceof ZlinkStreamException) throw cause;
|
|
1147
1167
|
throw connectorError("decompressionFailed" /* DecompressionFailed */, "Decompression failed.", cause);
|
|
1148
1168
|
}
|
|
1169
|
+
if (decompressed.length > maxDecompressedSize) {
|
|
1170
|
+
throw connectorError(
|
|
1171
|
+
"frameTooLarge" /* FrameTooLarge */,
|
|
1172
|
+
"Decompressed payload exceeds MaxReceivePayloadSize."
|
|
1173
|
+
);
|
|
1174
|
+
}
|
|
1175
|
+
return decompressed;
|
|
1149
1176
|
}
|
|
1150
1177
|
function resolveCompressionCodec(compression, compressionCodec) {
|
|
1151
1178
|
if (compression === "none" /* None */) {
|
|
@@ -1495,7 +1522,7 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
1495
1522
|
|
|
1496
1523
|
// packages/stream-connector/src/Runtime/ZlinkStreamConnectorOptions.ts
|
|
1497
1524
|
function normalizeOptions(options, defaultTransportFactory) {
|
|
1498
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C;
|
|
1525
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G;
|
|
1499
1526
|
const endpoint = options.endpoint;
|
|
1500
1527
|
if (endpoint.trim().length === 0) {
|
|
1501
1528
|
throw connectorError("configurationError" /* ConfigurationError */, "Endpoint must not be empty.");
|
|
@@ -1514,31 +1541,65 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
1514
1541
|
validatePositive((_e = options.maxReceivePayloadSize) != null ? _e : 64 * 1024, "MaxReceivePayloadSize");
|
|
1515
1542
|
validateHeartbeat(options.heartbeat);
|
|
1516
1543
|
validateReconnect(options.reconnect);
|
|
1544
|
+
if (((_f = options.heartbeat) == null ? void 0 : _f.enabled) !== void 0 && typeof options.heartbeat.enabled !== "boolean") {
|
|
1545
|
+
throw connectorError(
|
|
1546
|
+
"validationFailed" /* ValidationFailed */,
|
|
1547
|
+
"Heartbeat enabled must be boolean."
|
|
1548
|
+
);
|
|
1549
|
+
}
|
|
1550
|
+
if (((_g = options.reconnect) == null ? void 0 : _g.enabled) !== void 0 && typeof options.reconnect.enabled !== "boolean") {
|
|
1551
|
+
throw connectorError(
|
|
1552
|
+
"validationFailed" /* ValidationFailed */,
|
|
1553
|
+
"Reconnect enabled must be boolean."
|
|
1554
|
+
);
|
|
1555
|
+
}
|
|
1556
|
+
if (options.compressionCodec !== void 0 && !hasMethods(options.compressionCodec, "compress", "decompress")) {
|
|
1557
|
+
throw connectorError("validationFailed" /* ValidationFailed */, "Compression codec is invalid.");
|
|
1558
|
+
}
|
|
1559
|
+
if (options.codec !== void 0 && !hasMethods(options.codec, "encode", "decode")) {
|
|
1560
|
+
throw connectorError("validationFailed" /* ValidationFailed */, "Payload codec is invalid.");
|
|
1561
|
+
}
|
|
1562
|
+
if (options.nameResolver !== void 0 && !hasMethods(options.nameResolver, "resolve")) {
|
|
1563
|
+
throw connectorError("validationFailed" /* ValidationFailed */, "Packet name resolver is invalid.");
|
|
1564
|
+
}
|
|
1565
|
+
if (options.transportFactory !== void 0 && !hasMethods(options.transportFactory, "connect")) {
|
|
1566
|
+
throw connectorError("validationFailed" /* ValidationFailed */, "Transport factory is invalid.");
|
|
1567
|
+
}
|
|
1568
|
+
if (!Object.values(ZlinkStreamDispatchMode).includes(
|
|
1569
|
+
(_h = options.dispatchMode) != null ? _h : "manual" /* Manual */
|
|
1570
|
+
)) {
|
|
1571
|
+
throw connectorError("validationFailed" /* ValidationFailed */, "DispatchMode is invalid.");
|
|
1572
|
+
}
|
|
1573
|
+
if (!Object.values(ZlinkStreamCompression).includes(
|
|
1574
|
+
(_i = options.compression) != null ? _i : "lz4" /* Lz4 */
|
|
1575
|
+
)) {
|
|
1576
|
+
throw connectorError("validationFailed" /* ValidationFailed */, "Compression is invalid.");
|
|
1577
|
+
}
|
|
1517
1578
|
return {
|
|
1518
1579
|
endpoint,
|
|
1519
1580
|
transport: inferredTransport,
|
|
1520
|
-
connectTimeoutMs: (
|
|
1521
|
-
requestTimeoutMs: (
|
|
1522
|
-
waitTimeoutMs: (
|
|
1581
|
+
connectTimeoutMs: (_j = options.connectTimeoutMs) != null ? _j : 5e3,
|
|
1582
|
+
requestTimeoutMs: (_k = options.requestTimeoutMs) != null ? _k : 3e4,
|
|
1583
|
+
waitTimeoutMs: (_l = options.waitTimeoutMs) != null ? _l : 5e3,
|
|
1523
1584
|
heartbeat: {
|
|
1524
|
-
enabled: (
|
|
1525
|
-
intervalMs: (
|
|
1526
|
-
timeoutMs: (
|
|
1585
|
+
enabled: (_n = (_m = options.heartbeat) == null ? void 0 : _m.enabled) != null ? _n : true,
|
|
1586
|
+
intervalMs: (_p = (_o = options.heartbeat) == null ? void 0 : _o.intervalMs) != null ? _p : 1e3,
|
|
1587
|
+
timeoutMs: (_r = (_q = options.heartbeat) == null ? void 0 : _q.timeoutMs) != null ? _r : 5e3
|
|
1527
1588
|
},
|
|
1528
1589
|
reconnect: {
|
|
1529
|
-
enabled: (
|
|
1530
|
-
initialDelayMs: (
|
|
1531
|
-
maxDelayMs: (
|
|
1532
|
-
backoffFactor: (
|
|
1533
|
-
maxAttempts: ((
|
|
1590
|
+
enabled: (_t = (_s = options.reconnect) == null ? void 0 : _s.enabled) != null ? _t : true,
|
|
1591
|
+
initialDelayMs: (_v = (_u = options.reconnect) == null ? void 0 : _u.initialDelayMs) != null ? _v : 250,
|
|
1592
|
+
maxDelayMs: (_x = (_w = options.reconnect) == null ? void 0 : _w.maxDelayMs) != null ? _x : 5e3,
|
|
1593
|
+
backoffFactor: (_z = (_y = options.reconnect) == null ? void 0 : _y.backoffFactor) != null ? _z : 2,
|
|
1594
|
+
maxAttempts: ((_A = options.reconnect) == null ? void 0 : _A.maxAttempts) === void 0 ? 3 : options.reconnect.maxAttempts
|
|
1534
1595
|
},
|
|
1535
|
-
maxSendPayloadSize: (
|
|
1536
|
-
maxReceivePayloadSize: (
|
|
1537
|
-
dispatchMode: (
|
|
1538
|
-
compression: (
|
|
1596
|
+
maxSendPayloadSize: (_B = options.maxSendPayloadSize) != null ? _B : 64 * 1024,
|
|
1597
|
+
maxReceivePayloadSize: (_C = options.maxReceivePayloadSize) != null ? _C : 64 * 1024,
|
|
1598
|
+
dispatchMode: (_D = options.dispatchMode) != null ? _D : "manual" /* Manual */,
|
|
1599
|
+
compression: (_E = options.compression) != null ? _E : "lz4" /* Lz4 */,
|
|
1539
1600
|
compressionCodec: resolveCompressionCodec2(options),
|
|
1540
|
-
nameResolver: (
|
|
1541
|
-
transportFactory: (
|
|
1601
|
+
nameResolver: (_F = options.nameResolver) != null ? _F : defaultPacketNameResolver,
|
|
1602
|
+
transportFactory: (_G = options.transportFactory) != null ? _G : defaultTransportFactory,
|
|
1542
1603
|
codec: options.codec
|
|
1543
1604
|
};
|
|
1544
1605
|
}
|
|
@@ -1566,41 +1627,27 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
1566
1627
|
return options.compressionCodec;
|
|
1567
1628
|
}
|
|
1568
1629
|
function validatePositive(value, name) {
|
|
1569
|
-
if (value <= 0) {
|
|
1630
|
+
if (!Number.isFinite(value) || value <= 0) {
|
|
1570
1631
|
throw connectorError("validationFailed" /* ValidationFailed */, `${name} must be positive.`);
|
|
1571
1632
|
}
|
|
1572
1633
|
}
|
|
1634
|
+
function hasMethods(value, ...names) {
|
|
1635
|
+
if (value === null || typeof value !== "object") return false;
|
|
1636
|
+
const candidate = value;
|
|
1637
|
+
return names.every((name) => typeof candidate[name] === "function");
|
|
1638
|
+
}
|
|
1573
1639
|
function validateHeartbeat(options) {
|
|
1574
|
-
var _a, _b
|
|
1575
|
-
const
|
|
1576
|
-
const
|
|
1577
|
-
const timeoutMs = (_c = options == null ? void 0 : options.timeoutMs) != null ? _c : 5e3;
|
|
1578
|
-
if (!enabled) {
|
|
1579
|
-
return;
|
|
1580
|
-
}
|
|
1640
|
+
var _a, _b;
|
|
1641
|
+
const intervalMs = (_a = options == null ? void 0 : options.intervalMs) != null ? _a : 1e3;
|
|
1642
|
+
const timeoutMs = (_b = options == null ? void 0 : options.timeoutMs) != null ? _b : 5e3;
|
|
1581
1643
|
validatePositive(intervalMs, "Heartbeat interval");
|
|
1582
1644
|
validatePositive(timeoutMs, "Heartbeat timeout");
|
|
1583
|
-
if (timeoutMs <= intervalMs) {
|
|
1584
|
-
throw connectorError(
|
|
1585
|
-
"validationFailed" /* ValidationFailed */,
|
|
1586
|
-
"Heartbeat timeout must be greater than the heartbeat interval."
|
|
1587
|
-
);
|
|
1588
|
-
}
|
|
1589
1645
|
}
|
|
1590
1646
|
function validateReconnect(options) {
|
|
1591
|
-
var _a, _b, _c
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
}
|
|
1596
|
-
validatePositive((_b = options == null ? void 0 : options.initialDelayMs) != null ? _b : 250, "Reconnect InitialDelay");
|
|
1597
|
-
validatePositive((_c = options == null ? void 0 : options.maxDelayMs) != null ? _c : 5e3, "Reconnect MaxDelay");
|
|
1598
|
-
if (((_d = options == null ? void 0 : options.backoffFactor) != null ? _d : 2) < 1) {
|
|
1599
|
-
throw connectorError(
|
|
1600
|
-
"validationFailed" /* ValidationFailed */,
|
|
1601
|
-
"Reconnect BackoffFactor must be at least 1.0."
|
|
1602
|
-
);
|
|
1603
|
-
}
|
|
1647
|
+
var _a, _b, _c;
|
|
1648
|
+
validatePositive((_a = options == null ? void 0 : options.initialDelayMs) != null ? _a : 250, "Reconnect InitialDelay");
|
|
1649
|
+
validatePositive((_b = options == null ? void 0 : options.maxDelayMs) != null ? _b : 5e3, "Reconnect MaxDelay");
|
|
1650
|
+
validatePositive((_c = options == null ? void 0 : options.backoffFactor) != null ? _c : 2, "Reconnect BackoffFactor");
|
|
1604
1651
|
const maxAttempts = (options == null ? void 0 : options.maxAttempts) === void 0 ? 3 : options.maxAttempts;
|
|
1605
1652
|
if (maxAttempts !== null && !(Number.isFinite(maxAttempts) && maxAttempts > 0)) {
|
|
1606
1653
|
throw connectorError(
|
|
@@ -1616,32 +1663,33 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
1616
1663
|
__publicField(this, "nextRequestSeq", 1n);
|
|
1617
1664
|
__publicField(this, "active", /* @__PURE__ */ new Map());
|
|
1618
1665
|
}
|
|
1619
|
-
get count() {
|
|
1620
|
-
return this.active.size;
|
|
1621
|
-
}
|
|
1622
1666
|
create(packetName, timeoutMs) {
|
|
1667
|
+
if (this.nextRequestSeq > 0xffffffffffffffffn) {
|
|
1668
|
+
throw connectorError("sendFailed" /* SendFailed */, "Request sequence is exhausted.");
|
|
1669
|
+
}
|
|
1623
1670
|
const requestSeq = this.nextRequestSeq++;
|
|
1624
1671
|
let timeout;
|
|
1625
1672
|
let resolvePending;
|
|
1626
1673
|
let rejectPending;
|
|
1627
1674
|
const promise = new Promise(
|
|
1628
1675
|
(resolve, reject) => {
|
|
1629
|
-
timeout = setTimeout(() => {
|
|
1630
|
-
this.active.delete(requestSeq);
|
|
1631
|
-
reject(
|
|
1632
|
-
connectorError(
|
|
1633
|
-
"requestTimeout" /* RequestTimeout */,
|
|
1634
|
-
`Request '${packetName}' timed out.`
|
|
1635
|
-
)
|
|
1636
|
-
);
|
|
1637
|
-
}, timeoutMs);
|
|
1638
1676
|
resolvePending = resolve;
|
|
1639
1677
|
rejectPending = (error) => reject(connectorError(error.code, error.message, error.cause));
|
|
1640
1678
|
}
|
|
1641
1679
|
);
|
|
1642
|
-
|
|
1680
|
+
const tracked = {
|
|
1643
1681
|
packetName,
|
|
1644
1682
|
promise,
|
|
1683
|
+
startTimeout: () => {
|
|
1684
|
+
if (timeout !== void 0 || this.active.get(requestSeq) !== tracked) return;
|
|
1685
|
+
timeout = setTimeout(() => {
|
|
1686
|
+
this.active.delete(requestSeq);
|
|
1687
|
+
rejectPending({
|
|
1688
|
+
code: "requestTimeout" /* RequestTimeout */,
|
|
1689
|
+
message: `Request '${packetName}' timed out.`
|
|
1690
|
+
});
|
|
1691
|
+
}, timeoutMs);
|
|
1692
|
+
},
|
|
1645
1693
|
resolve: (value) => {
|
|
1646
1694
|
if (timeout !== void 0) {
|
|
1647
1695
|
clearTimeout(timeout);
|
|
@@ -1659,8 +1707,9 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
1659
1707
|
clearTimeout(timeout);
|
|
1660
1708
|
}
|
|
1661
1709
|
}
|
|
1662
|
-
}
|
|
1663
|
-
|
|
1710
|
+
};
|
|
1711
|
+
this.active.set(requestSeq, tracked);
|
|
1712
|
+
return { requestSeq, promise, startTimeout: tracked.startTimeout };
|
|
1664
1713
|
}
|
|
1665
1714
|
/* stream connector spec §5.2: a pending request is matched by request_seq alone. */
|
|
1666
1715
|
resolve(requestSeq, value, metadata) {
|
|
@@ -1668,8 +1717,9 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
1668
1717
|
if (pending === void 0) {
|
|
1669
1718
|
return false;
|
|
1670
1719
|
}
|
|
1720
|
+
const payload = value();
|
|
1671
1721
|
this.active.delete(requestSeq);
|
|
1672
|
-
pending.resolve({ name: pending.packetName, metadata, payload
|
|
1722
|
+
pending.resolve({ name: pending.packetName, metadata, payload });
|
|
1673
1723
|
return true;
|
|
1674
1724
|
}
|
|
1675
1725
|
reject(requestSeq, error) {
|
|
@@ -1697,7 +1747,164 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
1697
1747
|
}
|
|
1698
1748
|
};
|
|
1699
1749
|
|
|
1750
|
+
// packages/stream-connector/src/Runtime/ZlinkStreamActors.ts
|
|
1751
|
+
var ACTOR_BOUND = "$zlink.actor.bound";
|
|
1752
|
+
var ACTOR_UNBOUND = "$zlink.actor.unbound";
|
|
1753
|
+
var zlinkStreamActorBinding = Symbol("zlink.stream.actorBinding");
|
|
1754
|
+
var DefaultZlinkStreamActor = class {
|
|
1755
|
+
constructor(connector, actorId, slot) {
|
|
1756
|
+
this.connector = connector;
|
|
1757
|
+
this.actorId = actorId;
|
|
1758
|
+
this.slot = slot;
|
|
1759
|
+
__publicField(this, "bound", true);
|
|
1760
|
+
}
|
|
1761
|
+
get isBound() {
|
|
1762
|
+
return this.bound;
|
|
1763
|
+
}
|
|
1764
|
+
send(payload, messageType) {
|
|
1765
|
+
this.ensureBound();
|
|
1766
|
+
return this.connector.sendForActor(this, payload, messageType);
|
|
1767
|
+
}
|
|
1768
|
+
request(payload, messageType) {
|
|
1769
|
+
this.ensureBound();
|
|
1770
|
+
return this.connector.requestForActor(this, payload, messageType);
|
|
1771
|
+
}
|
|
1772
|
+
on(nameOrType, handler, messageType) {
|
|
1773
|
+
return this.connector.onActorMessage(this, nameOrType, handler, messageType);
|
|
1774
|
+
}
|
|
1775
|
+
ensureBound() {
|
|
1776
|
+
if (!this.bound) {
|
|
1777
|
+
throw connectorError(
|
|
1778
|
+
"validationFailed" /* ValidationFailed */,
|
|
1779
|
+
`Actor '${this.actorId}' is no longer bound.`
|
|
1780
|
+
);
|
|
1781
|
+
}
|
|
1782
|
+
}
|
|
1783
|
+
close() {
|
|
1784
|
+
this.bound = false;
|
|
1785
|
+
}
|
|
1786
|
+
};
|
|
1787
|
+
var ZlinkStreamActors = class {
|
|
1788
|
+
constructor(connector, receivedMessages, events) {
|
|
1789
|
+
this.connector = connector;
|
|
1790
|
+
this.receivedMessages = receivedMessages;
|
|
1791
|
+
this.events = events;
|
|
1792
|
+
__publicField(this, "bySlot", /* @__PURE__ */ new Map());
|
|
1793
|
+
__publicField(this, "byId", /* @__PURE__ */ new Map());
|
|
1794
|
+
__publicField(this, "issued", []);
|
|
1795
|
+
__publicField(this, "boundHandlers", /* @__PURE__ */ new Set());
|
|
1796
|
+
__publicField(this, "unboundHandlers", /* @__PURE__ */ new Set());
|
|
1797
|
+
}
|
|
1798
|
+
get snapshot() {
|
|
1799
|
+
return Object.freeze(Array.from(this.bySlot.values()));
|
|
1800
|
+
}
|
|
1801
|
+
find(actorId) {
|
|
1802
|
+
return this.byId.get(actorId);
|
|
1803
|
+
}
|
|
1804
|
+
onBound(handler) {
|
|
1805
|
+
this.boundHandlers.add(handler);
|
|
1806
|
+
return subscription(() => this.boundHandlers.delete(handler));
|
|
1807
|
+
}
|
|
1808
|
+
onUnbound(handler) {
|
|
1809
|
+
this.unboundHandlers.add(handler);
|
|
1810
|
+
return subscription(() => this.unboundHandlers.delete(handler));
|
|
1811
|
+
}
|
|
1812
|
+
processControl(name, payload, signal) {
|
|
1813
|
+
if (name === ACTOR_BOUND) {
|
|
1814
|
+
this.bind(payload, signal);
|
|
1815
|
+
return true;
|
|
1816
|
+
}
|
|
1817
|
+
if (name === ACTOR_UNBOUND) {
|
|
1818
|
+
this.unbind(payload, signal);
|
|
1819
|
+
return true;
|
|
1820
|
+
}
|
|
1821
|
+
return false;
|
|
1822
|
+
}
|
|
1823
|
+
resolve(slot) {
|
|
1824
|
+
const actor = this.bySlot.get(slot);
|
|
1825
|
+
if (actor === void 0) {
|
|
1826
|
+
throw connectorError(
|
|
1827
|
+
"frameDecodeFailed" /* FrameDecodeFailed */,
|
|
1828
|
+
`Actor slot '${slot}' is not bound.`
|
|
1829
|
+
);
|
|
1830
|
+
}
|
|
1831
|
+
return actor;
|
|
1832
|
+
}
|
|
1833
|
+
closeAll(signal) {
|
|
1834
|
+
for (const actor of this.issued) {
|
|
1835
|
+
if (!actor.isBound) continue;
|
|
1836
|
+
this.bySlot.delete(actor.slot);
|
|
1837
|
+
this.byId.delete(actor.actorId);
|
|
1838
|
+
actor.close();
|
|
1839
|
+
this.queue(this.unboundHandlers, actor, signal);
|
|
1840
|
+
}
|
|
1841
|
+
this.issued.length = 0;
|
|
1842
|
+
}
|
|
1843
|
+
bind(payload, signal) {
|
|
1844
|
+
if (payload.length < 5 || payload[0] !== 1) {
|
|
1845
|
+
throw invalidControl("Actor bound payload is invalid.");
|
|
1846
|
+
}
|
|
1847
|
+
const slot = payload[1] << 8 | payload[2];
|
|
1848
|
+
const idLength = payload[3];
|
|
1849
|
+
if (slot === 0 || idLength === 0 || payload.length !== 4 + idLength) {
|
|
1850
|
+
throw invalidControl("Actor bound payload is invalid.");
|
|
1851
|
+
}
|
|
1852
|
+
let actorId;
|
|
1853
|
+
try {
|
|
1854
|
+
actorId = new TextDecoder("utf-8", { fatal: true }).decode(payload.subarray(4));
|
|
1855
|
+
} catch (cause) {
|
|
1856
|
+
throw connectorError(
|
|
1857
|
+
"frameDecodeFailed" /* FrameDecodeFailed */,
|
|
1858
|
+
"Actor id is not valid UTF-8.",
|
|
1859
|
+
cause
|
|
1860
|
+
);
|
|
1861
|
+
}
|
|
1862
|
+
if (actorId.length === 0 || this.bySlot.has(slot) || this.byId.has(actorId)) {
|
|
1863
|
+
throw invalidControl("Actor bound identity is already in use.");
|
|
1864
|
+
}
|
|
1865
|
+
const actor = new DefaultZlinkStreamActor(this.connector, actorId, slot);
|
|
1866
|
+
this.bySlot.set(slot, actor);
|
|
1867
|
+
this.byId.set(actorId, actor);
|
|
1868
|
+
this.issued.push(actor);
|
|
1869
|
+
this.queue(this.boundHandlers, actor, signal);
|
|
1870
|
+
}
|
|
1871
|
+
unbind(payload, signal) {
|
|
1872
|
+
if (payload.length !== 3 || payload[0] !== 1) {
|
|
1873
|
+
throw invalidControl("Actor unbound payload is invalid.");
|
|
1874
|
+
}
|
|
1875
|
+
const slot = payload[1] << 8 | payload[2];
|
|
1876
|
+
const actor = this.bySlot.get(slot);
|
|
1877
|
+
if (slot === 0 || actor === void 0) {
|
|
1878
|
+
throw invalidControl(`Actor slot '${slot}' is not bound.`);
|
|
1879
|
+
}
|
|
1880
|
+
this.bySlot.delete(slot);
|
|
1881
|
+
this.byId.delete(actor.actorId);
|
|
1882
|
+
actor.close();
|
|
1883
|
+
this.queue(this.unboundHandlers, actor, signal);
|
|
1884
|
+
}
|
|
1885
|
+
queue(handlers, actor, signal) {
|
|
1886
|
+
this.receivedMessages.enqueueCallback(
|
|
1887
|
+
() => {
|
|
1888
|
+
for (const handler of Array.from(handlers)) {
|
|
1889
|
+
this.events.runUserCallback(
|
|
1890
|
+
() => handler(actor, signal),
|
|
1891
|
+
"Actor lifecycle handler failed.",
|
|
1892
|
+
signal
|
|
1893
|
+
);
|
|
1894
|
+
}
|
|
1895
|
+
},
|
|
1896
|
+
() => handlers.size
|
|
1897
|
+
);
|
|
1898
|
+
}
|
|
1899
|
+
};
|
|
1900
|
+
function invalidControl(message) {
|
|
1901
|
+
return connectorError("frameDecodeFailed" /* FrameDecodeFailed */, message);
|
|
1902
|
+
}
|
|
1903
|
+
|
|
1700
1904
|
// packages/stream-connector/src/Runtime/ZlinkStreamReceivedMessages.ts
|
|
1905
|
+
function receives(registration, message) {
|
|
1906
|
+
return registration.actor === void 0 || registration.actor === message[zlinkStreamActorBinding];
|
|
1907
|
+
}
|
|
1701
1908
|
var ZlinkStreamReceivedMessages = class {
|
|
1702
1909
|
/**
|
|
1703
1910
|
* @param deliverOnArrival `Immediate` runs registered handlers on the receive
|
|
@@ -1714,10 +1921,10 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
1714
1921
|
// queue is not a simple FIFO. Tombstones let us remove a deliverable entry
|
|
1715
1922
|
// without shifting every later message on the hot receive path.
|
|
1716
1923
|
__publicField(this, "queue", []);
|
|
1924
|
+
__publicField(this, "deliverable", []);
|
|
1717
1925
|
__publicField(this, "queueHead", 0);
|
|
1718
1926
|
__publicField(this, "queuedCount", 0);
|
|
1719
|
-
|
|
1720
|
-
// True for as long as `drain` is on the stack, handler awaits included. It
|
|
1927
|
+
// True for as long as `pump` is on the stack. It
|
|
1721
1928
|
// marks the execution context a registered handler runs in, so a `dispatch`
|
|
1722
1929
|
// made from inside a handler is recognised as re-entry rather than a fresh
|
|
1723
1930
|
// pump. It is not a lock: a single event loop admits no second thread, and
|
|
@@ -1728,19 +1935,32 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
1728
1935
|
// so consuming does not lower it and the dispatch mode does not change it.
|
|
1729
1936
|
__publicField(this, "receivedCounts", /* @__PURE__ */ new Map());
|
|
1730
1937
|
}
|
|
1731
|
-
|
|
1938
|
+
/**
|
|
1939
|
+
* @param actor The Actor handle that registers the handler, if any. Its
|
|
1940
|
+
* handler receives only that Actor's packets.
|
|
1941
|
+
*/
|
|
1942
|
+
on(name, handler, actor) {
|
|
1732
1943
|
validateName(name);
|
|
1733
1944
|
let set = this.handlers.get(name);
|
|
1734
1945
|
if (set === void 0) {
|
|
1735
1946
|
set = /* @__PURE__ */ new Set();
|
|
1736
1947
|
this.handlers.set(name, set);
|
|
1737
1948
|
}
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1949
|
+
const registration = { handle: handler, actor };
|
|
1950
|
+
set.add(registration);
|
|
1951
|
+
let newlyDeliverable = false;
|
|
1952
|
+
for (let index = this.queueHead; index < this.queue.length; index += 1) {
|
|
1953
|
+
const queued = this.queue[index];
|
|
1954
|
+
if ((queued == null ? void 0 : queued.kind) === "message" && queued.indexed !== true && queued.message.name === name && receives(registration, queued.message)) {
|
|
1955
|
+
this.indexDeliverable(index);
|
|
1956
|
+
newlyDeliverable = true;
|
|
1957
|
+
}
|
|
1958
|
+
}
|
|
1959
|
+
if (this.deliverOnArrival && newlyDeliverable) {
|
|
1960
|
+
queueMicrotask(() => this.pump());
|
|
1741
1961
|
}
|
|
1742
1962
|
return subscription(() => {
|
|
1743
|
-
set.delete(
|
|
1963
|
+
set.delete(registration);
|
|
1744
1964
|
if (set.size === 0 && this.handlers.get(name) === set) {
|
|
1745
1965
|
this.handlers.delete(name);
|
|
1746
1966
|
}
|
|
@@ -1812,6 +2032,11 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
1812
2032
|
this.queue.push(...submittedCallbacks);
|
|
1813
2033
|
this.queueHead = 0;
|
|
1814
2034
|
this.queuedCount = submittedCallbacks.length;
|
|
2035
|
+
this.deliverable.length = 0;
|
|
2036
|
+
for (let index = 0; index < this.queue.length; index += 1) {
|
|
2037
|
+
this.queue[index].indexed = false;
|
|
2038
|
+
this.indexDeliverable(index);
|
|
2039
|
+
}
|
|
1815
2040
|
}
|
|
1816
2041
|
/**
|
|
1817
2042
|
* Releases every registered wait surface because the connection it was
|
|
@@ -1843,60 +2068,38 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
1843
2068
|
}
|
|
1844
2069
|
this.queue.push({ kind: "message", message, signal });
|
|
1845
2070
|
this.queuedCount += 1;
|
|
2071
|
+
this.indexDeliverable(this.queue.length - 1);
|
|
1846
2072
|
if (this.deliverOnArrival) {
|
|
1847
|
-
this.
|
|
2073
|
+
this.pump();
|
|
1848
2074
|
}
|
|
1849
2075
|
}
|
|
1850
|
-
|
|
1851
|
-
|
|
2076
|
+
/**
|
|
2077
|
+
* @param callbacks The number of handler calls `callback` makes when it runs
|
|
2078
|
+
* with the handlers registered at that moment; a callback that runs a set
|
|
2079
|
+
* of handlers reads the set's size. One callback by default.
|
|
2080
|
+
*/
|
|
2081
|
+
enqueueCallback(callback, callbacks = () => 1) {
|
|
2082
|
+
this.queue.push({ kind: "callback", callback, callbacks });
|
|
1852
2083
|
this.queuedCount += 1;
|
|
2084
|
+
this.indexDeliverable(this.queue.length - 1);
|
|
1853
2085
|
if (this.deliverOnArrival) {
|
|
1854
|
-
this.
|
|
2086
|
+
this.pump();
|
|
1855
2087
|
}
|
|
1856
2088
|
}
|
|
1857
2089
|
/**
|
|
1858
2090
|
* Runs the registered handlers the receive path left queued. `Manual` calls
|
|
1859
|
-
* this from `dispatch`; `Immediate`
|
|
2091
|
+
* this from `dispatch`; `Immediate` drains on arrival.
|
|
1860
2092
|
*
|
|
1861
|
-
*
|
|
1862
|
-
*
|
|
1863
|
-
*
|
|
1864
|
-
*
|
|
1865
|
-
*
|
|
1866
|
-
* would deliver and returning is the whole of the correct behaviour.
|
|
2093
|
+
* The drain is synchronous: the connector does not wait for a handler
|
|
2094
|
+
* (spec stream-connector 32 §7), so nothing inside it awaits. A handler that
|
|
2095
|
+
* calls `dispatch` arrives back here from inside the drain it was started by;
|
|
2096
|
+
* the running loop already takes every deliverable entry, so returning is the
|
|
2097
|
+
* whole of the correct behaviour.
|
|
1867
2098
|
*/
|
|
1868
|
-
|
|
2099
|
+
pump() {
|
|
1869
2100
|
if (this.draining) {
|
|
1870
2101
|
return;
|
|
1871
2102
|
}
|
|
1872
|
-
this.scheduleDrain();
|
|
1873
|
-
await this.drainTask;
|
|
1874
|
-
}
|
|
1875
|
-
offerQueued(name, registration) {
|
|
1876
|
-
for (let index = this.queueHead; index < this.queue.length; index += 1) {
|
|
1877
|
-
const queued = this.queue[index];
|
|
1878
|
-
if (queued === void 0 || queued.kind !== "message" || queued.message.name !== name) {
|
|
1879
|
-
continue;
|
|
1880
|
-
}
|
|
1881
|
-
if (!registration.consume(queued.message)) {
|
|
1882
|
-
continue;
|
|
1883
|
-
}
|
|
1884
|
-
this.removeAt(index);
|
|
1885
|
-
return;
|
|
1886
|
-
}
|
|
1887
|
-
}
|
|
1888
|
-
scheduleDrain() {
|
|
1889
|
-
if (this.drainTask !== void 0) {
|
|
1890
|
-
return;
|
|
1891
|
-
}
|
|
1892
|
-
this.drainTask = this.drain().finally(() => {
|
|
1893
|
-
this.drainTask = void 0;
|
|
1894
|
-
if (this.deliverOnArrival && this.findDeliverableIndex() >= 0) {
|
|
1895
|
-
this.scheduleDrain();
|
|
1896
|
-
}
|
|
1897
|
-
});
|
|
1898
|
-
}
|
|
1899
|
-
async drain() {
|
|
1900
2103
|
this.draining = true;
|
|
1901
2104
|
try {
|
|
1902
2105
|
for (let index = this.findDeliverableIndex(); index >= 0; index = this.findDeliverableIndex()) {
|
|
@@ -1904,52 +2107,113 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
1904
2107
|
if (queued === void 0) continue;
|
|
1905
2108
|
this.removeAt(index);
|
|
1906
2109
|
if (queued.kind === "callback") {
|
|
1907
|
-
|
|
2110
|
+
this.events.runUserCallback(queued.callback, "Connector callback failed.");
|
|
1908
2111
|
continue;
|
|
1909
2112
|
}
|
|
1910
2113
|
const { message, signal } = queued;
|
|
1911
|
-
const handlers =
|
|
2114
|
+
const handlers = this.receiversOf(message);
|
|
1912
2115
|
for (const handler of handlers) {
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
code: "userCallbackFailed" /* UserCallbackFailed */,
|
|
1919
|
-
message: "Typed message handler failed.",
|
|
1920
|
-
cause
|
|
1921
|
-
},
|
|
1922
|
-
signal
|
|
1923
|
-
);
|
|
1924
|
-
}
|
|
2116
|
+
this.events.runUserCallback(
|
|
2117
|
+
() => handler.handle(message, signal),
|
|
2118
|
+
"Typed message handler failed.",
|
|
2119
|
+
signal
|
|
2120
|
+
);
|
|
1925
2121
|
}
|
|
1926
2122
|
}
|
|
1927
2123
|
} finally {
|
|
1928
2124
|
this.draining = false;
|
|
1929
2125
|
}
|
|
1930
2126
|
}
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
2127
|
+
/**
|
|
2128
|
+
* True while a registered callback runs from {@link pump}: the execution
|
|
2129
|
+
* context spec stream-connector 32 §7 calls "inside a handler".
|
|
2130
|
+
*/
|
|
2131
|
+
get dispatching() {
|
|
2132
|
+
return this.draining;
|
|
2133
|
+
}
|
|
2134
|
+
get pendingCallbacks() {
|
|
2135
|
+
let count = 0;
|
|
2136
|
+
for (let index = this.queueHead; index < this.queue.length; index += 1) {
|
|
2137
|
+
const queued = this.queue[index];
|
|
2138
|
+
if ((queued == null ? void 0 : queued.kind) === "callback" && queued.callbacks() > 0) count += 1;
|
|
2139
|
+
if ((queued == null ? void 0 : queued.kind) === "message" && this.receiversOf(queued.message).length > 0) count += 1;
|
|
2140
|
+
}
|
|
2141
|
+
return count;
|
|
2142
|
+
}
|
|
2143
|
+
offerQueued(name, registration) {
|
|
1939
2144
|
for (let index = this.queueHead; index < this.queue.length; index += 1) {
|
|
1940
2145
|
const queued = this.queue[index];
|
|
1941
|
-
if (queued
|
|
2146
|
+
if (queued === void 0 || queued.kind !== "message" || queued.message.name !== name) {
|
|
2147
|
+
continue;
|
|
2148
|
+
}
|
|
2149
|
+
if (!registration.consume(queued.message)) {
|
|
2150
|
+
continue;
|
|
2151
|
+
}
|
|
2152
|
+
this.removeAt(index);
|
|
2153
|
+
return;
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
removeAt(index) {
|
|
2157
|
+
this.queue[index] = void 0;
|
|
2158
|
+
this.queuedCount -= 1;
|
|
2159
|
+
this.advanceHead();
|
|
2160
|
+
this.compactQueue();
|
|
2161
|
+
}
|
|
2162
|
+
findDeliverableIndex() {
|
|
2163
|
+
while (this.deliverable.length > 0) {
|
|
2164
|
+
const index = this.deliverable[0];
|
|
2165
|
+
const queued = this.queue[index];
|
|
2166
|
+
if (this.isDeliverable(queued)) {
|
|
1942
2167
|
return index;
|
|
1943
2168
|
}
|
|
2169
|
+
if (queued !== void 0) queued.indexed = false;
|
|
2170
|
+
this.removeDeliverable();
|
|
1944
2171
|
}
|
|
1945
2172
|
return -1;
|
|
1946
2173
|
}
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
2174
|
+
indexDeliverable(index) {
|
|
2175
|
+
const queued = this.queue[index];
|
|
2176
|
+
if (queued === void 0 || !this.isDeliverable(queued) || queued.indexed === true) return;
|
|
2177
|
+
queued.indexed = true;
|
|
2178
|
+
let position = this.deliverable.length;
|
|
2179
|
+
this.deliverable.push(index);
|
|
2180
|
+
while (position > 0) {
|
|
2181
|
+
const parent = Math.floor((position - 1) / 2);
|
|
2182
|
+
if (this.deliverable[parent] <= index) break;
|
|
2183
|
+
this.deliverable[position] = this.deliverable[parent];
|
|
2184
|
+
position = parent;
|
|
1951
2185
|
}
|
|
1952
|
-
|
|
2186
|
+
this.deliverable[position] = index;
|
|
2187
|
+
}
|
|
2188
|
+
isDeliverable(queued) {
|
|
2189
|
+
return (queued == null ? void 0 : queued.kind) === "callback" || (queued == null ? void 0 : queued.kind) === "message" && this.receiversOf(queued.message).length > 0;
|
|
2190
|
+
}
|
|
2191
|
+
/**
|
|
2192
|
+
* Spec stream-connector 32 §7 and §10: the handlers that receive `message`
|
|
2193
|
+
* are the connector handlers for its name and the handle handlers of the
|
|
2194
|
+
* Actor it carries. A packet no handler receives stays in the queue for the
|
|
2195
|
+
* wait surfaces. This is the one place that decides it.
|
|
2196
|
+
*/
|
|
2197
|
+
receiversOf(message) {
|
|
2198
|
+
const set = this.handlers.get(message.name);
|
|
2199
|
+
if (set === void 0) return [];
|
|
2200
|
+
return Array.from(set).filter((registration) => receives(registration, message));
|
|
2201
|
+
}
|
|
2202
|
+
removeDeliverable() {
|
|
2203
|
+
if (this.deliverable.length === 0) return;
|
|
2204
|
+
const last = this.deliverable.pop();
|
|
2205
|
+
if (this.deliverable.length === 0) return;
|
|
2206
|
+
let position = 0;
|
|
2207
|
+
for (; ; ) {
|
|
2208
|
+
const left = position * 2 + 1;
|
|
2209
|
+
if (left >= this.deliverable.length) break;
|
|
2210
|
+
const right = left + 1;
|
|
2211
|
+
const child = right < this.deliverable.length && this.deliverable[right] < this.deliverable[left] ? right : left;
|
|
2212
|
+
if (this.deliverable[child] >= last) break;
|
|
2213
|
+
this.deliverable[position] = this.deliverable[child];
|
|
2214
|
+
position = child;
|
|
2215
|
+
}
|
|
2216
|
+
this.deliverable[position] = last;
|
|
1953
2217
|
}
|
|
1954
2218
|
advanceHead() {
|
|
1955
2219
|
while (this.queueHead < this.queue.length && this.queue[this.queueHead] === void 0) {
|
|
@@ -1960,22 +2224,99 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
1960
2224
|
if (this.queuedCount === 0) {
|
|
1961
2225
|
this.queue.length = 0;
|
|
1962
2226
|
this.queueHead = 0;
|
|
2227
|
+
this.deliverable.length = 0;
|
|
1963
2228
|
return;
|
|
1964
2229
|
}
|
|
1965
2230
|
if (this.queueHead >= 1024 && this.queueHead * 2 >= this.queue.length) {
|
|
1966
2231
|
this.queue.splice(0, this.queueHead);
|
|
1967
2232
|
this.queueHead = 0;
|
|
2233
|
+
this.deliverable.length = 0;
|
|
2234
|
+
for (let index = 0; index < this.queue.length; index += 1) {
|
|
2235
|
+
const queued = this.queue[index];
|
|
2236
|
+
if (queued === void 0) continue;
|
|
2237
|
+
queued.indexed = false;
|
|
2238
|
+
this.indexDeliverable(index);
|
|
2239
|
+
}
|
|
1968
2240
|
}
|
|
1969
2241
|
}
|
|
1970
2242
|
};
|
|
1971
2243
|
|
|
1972
2244
|
// packages/stream-connector/src/Runtime/ZlinkStreamFrameSender.ts
|
|
2245
|
+
var ZlinkStreamConnectionWriteQueue = class {
|
|
2246
|
+
/**
|
|
2247
|
+
* @param writeFailed Ends the connection whose transport write failed (spec
|
|
2248
|
+
* stream-connector 32 §9: a transport write failure ends the connection as
|
|
2249
|
+
* `TransportError`).
|
|
2250
|
+
*/
|
|
2251
|
+
constructor(connection, writeFailed) {
|
|
2252
|
+
this.connection = connection;
|
|
2253
|
+
this.writeFailed = writeFailed;
|
|
2254
|
+
__publicField(this, "queue", /* @__PURE__ */ new Set());
|
|
2255
|
+
__publicField(this, "active");
|
|
2256
|
+
}
|
|
2257
|
+
enqueue(operation) {
|
|
2258
|
+
this.queue.add(operation);
|
|
2259
|
+
this.advance();
|
|
2260
|
+
}
|
|
2261
|
+
cancel(operation, error) {
|
|
2262
|
+
if (this.queue.has(operation) || this.active === operation) operation.fail(error);
|
|
2263
|
+
}
|
|
2264
|
+
/**
|
|
2265
|
+
* Spec stream-connector 32 §7: when the connection ends, frames that have not
|
|
2266
|
+
* reached the transport are not written and the frame being written is not
|
|
2267
|
+
* waited for. The operations of both fail with `error`.
|
|
2268
|
+
*/
|
|
2269
|
+
failAll(error) {
|
|
2270
|
+
const operations = this.active === void 0 ? [...this.queue] : [this.active, ...this.queue];
|
|
2271
|
+
this.queue.clear();
|
|
2272
|
+
this.active = void 0;
|
|
2273
|
+
for (const operation of operations) operation.fail(error);
|
|
2274
|
+
}
|
|
2275
|
+
advance() {
|
|
2276
|
+
if (this.active !== void 0) return;
|
|
2277
|
+
const next = this.queue.values().next().value;
|
|
2278
|
+
if (next === void 0) return;
|
|
2279
|
+
this.queue.delete(next);
|
|
2280
|
+
this.active = next;
|
|
2281
|
+
let write;
|
|
2282
|
+
try {
|
|
2283
|
+
write = Promise.resolve(this.connection.write(next.frame));
|
|
2284
|
+
} catch (error) {
|
|
2285
|
+
write = Promise.reject(error);
|
|
2286
|
+
}
|
|
2287
|
+
void write.then(
|
|
2288
|
+
() => next.complete(),
|
|
2289
|
+
(cause) => this.failWrite(next, cause)
|
|
2290
|
+
).finally(() => {
|
|
2291
|
+
if (this.active !== next) return;
|
|
2292
|
+
this.active = void 0;
|
|
2293
|
+
this.advance();
|
|
2294
|
+
});
|
|
2295
|
+
}
|
|
2296
|
+
/**
|
|
2297
|
+
* Spec stream-connector 32 §9: a transport write failure is `SendFailed` for
|
|
2298
|
+
* the operation of that write, and it ends the connection. The ending fails
|
|
2299
|
+
* every other operation of the connection with `Disconnected`. A write that
|
|
2300
|
+
* fails after the connection already ended belongs to that ending, which has
|
|
2301
|
+
* already failed its operation with `Disconnected`.
|
|
2302
|
+
*/
|
|
2303
|
+
failWrite(operation, cause) {
|
|
2304
|
+
if (this.active !== operation) return;
|
|
2305
|
+
const error = {
|
|
2306
|
+
code: "sendFailed" /* SendFailed */,
|
|
2307
|
+
message: `Frame write failed: ${cause instanceof Error ? cause.message : String(cause)}`,
|
|
2308
|
+
cause
|
|
2309
|
+
};
|
|
2310
|
+
operation.fail(new ZlinkStreamException(error));
|
|
2311
|
+
this.writeFailed(error);
|
|
2312
|
+
}
|
|
2313
|
+
};
|
|
1973
2314
|
var ZlinkStreamFrameSender = class {
|
|
1974
2315
|
constructor(protocol) {
|
|
1975
2316
|
this.protocol = protocol;
|
|
1976
|
-
__publicField(this, "
|
|
2317
|
+
__publicField(this, "queues", /* @__PURE__ */ new Map());
|
|
1977
2318
|
}
|
|
1978
|
-
async send(connection, kind, name, payload, metadata, compress, requestSeq, signal, correlationId, actorSlot) {
|
|
2319
|
+
async send(connection, kind, name, payload, metadata, compress, requestSeq, signal, correlationId, actorSlot, expiry, onAccepted) {
|
|
1979
2320
|
throwIfAborted(signal);
|
|
1980
2321
|
await this.write(
|
|
1981
2322
|
connection,
|
|
@@ -1989,26 +2330,78 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
1989
2330
|
correlationId,
|
|
1990
2331
|
actorSlot
|
|
1991
2332
|
),
|
|
1992
|
-
signal
|
|
2333
|
+
signal,
|
|
2334
|
+
expiry,
|
|
2335
|
+
onAccepted
|
|
1993
2336
|
);
|
|
1994
2337
|
}
|
|
1995
|
-
|
|
1996
|
-
|
|
2338
|
+
/**
|
|
2339
|
+
* Writes a control frame (heartbeat ping or pong). A control frame belongs to
|
|
2340
|
+
* no operation: its write failure ends the connection through the write
|
|
2341
|
+
* queue like any other write (spec stream-connector 32 §9), and a connection
|
|
2342
|
+
* that has already ended does not write it. The promise settles when the
|
|
2343
|
+
* write has ended either way.
|
|
2344
|
+
*/
|
|
2345
|
+
sendControl(connection, name) {
|
|
2346
|
+
const queue = this.queues.get(connection);
|
|
2347
|
+
if (queue === void 0) return Promise.resolve();
|
|
2348
|
+
const frame = this.protocol.encodeControl(name);
|
|
2349
|
+
return new Promise((resolve) => {
|
|
2350
|
+
queue.enqueue({ frame, complete: resolve, fail: () => resolve() });
|
|
2351
|
+
});
|
|
1997
2352
|
}
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2353
|
+
/**
|
|
2354
|
+
* Gives a connection that has just been established its own write queue.
|
|
2355
|
+
* `writeFailed` ends that connection when one of its transport writes fails.
|
|
2356
|
+
*/
|
|
2357
|
+
open(connection, writeFailed) {
|
|
2358
|
+
this.queues.set(connection, new ZlinkStreamConnectionWriteQueue(connection, writeFailed));
|
|
2003
2359
|
}
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2360
|
+
/**
|
|
2361
|
+
* Ends the write queue of a connection that has ended, by close and by
|
|
2362
|
+
* transport loss alike. Every operation still in it fails with `error`.
|
|
2363
|
+
*/
|
|
2364
|
+
failUnwritten(connection, error) {
|
|
2365
|
+
const queue = this.queues.get(connection);
|
|
2366
|
+
if (queue === void 0) return;
|
|
2367
|
+
this.queues.delete(connection);
|
|
2368
|
+
queue.failAll(error);
|
|
2369
|
+
}
|
|
2370
|
+
write(connection, frame, signal, expiry, onAccepted) {
|
|
2371
|
+
throwIfAborted(signal);
|
|
2372
|
+
const queue = this.queues.get(connection);
|
|
2373
|
+
if (queue === void 0) {
|
|
2374
|
+
throw connectorError("disconnected" /* Disconnected */, "Connector is not connected.");
|
|
2011
2375
|
}
|
|
2376
|
+
let operation;
|
|
2377
|
+
let settled = false;
|
|
2378
|
+
const promise = new Promise((resolve, reject) => {
|
|
2379
|
+
const cleanup = () => signal == null ? void 0 : signal.removeEventListener("abort", onAbort);
|
|
2380
|
+
const onAbort = () => queue.cancel(
|
|
2381
|
+
operation,
|
|
2382
|
+
connectorError("disconnected" /* Disconnected */, "Operation canceled.")
|
|
2383
|
+
);
|
|
2384
|
+
operation = {
|
|
2385
|
+
frame,
|
|
2386
|
+
complete: () => {
|
|
2387
|
+
if (settled) return;
|
|
2388
|
+
settled = true;
|
|
2389
|
+
cleanup();
|
|
2390
|
+
resolve();
|
|
2391
|
+
},
|
|
2392
|
+
fail: (error) => {
|
|
2393
|
+
if (settled) return;
|
|
2394
|
+
settled = true;
|
|
2395
|
+
cleanup();
|
|
2396
|
+
reject(error);
|
|
2397
|
+
}
|
|
2398
|
+
};
|
|
2399
|
+
signal == null ? void 0 : signal.addEventListener("abort", onAbort, { once: true });
|
|
2400
|
+
onAccepted == null ? void 0 : onAccepted();
|
|
2401
|
+
expiry == null ? void 0 : expiry.then(void 0, (error) => queue.cancel(operation, error));
|
|
2402
|
+
queue.enqueue(operation);
|
|
2403
|
+
});
|
|
2404
|
+
return promise;
|
|
2012
2405
|
}
|
|
2013
2406
|
};
|
|
2014
2407
|
|
|
@@ -2034,177 +2427,16 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
2034
2427
|
return { closeReason, diagnostic };
|
|
2035
2428
|
}
|
|
2036
2429
|
|
|
2037
|
-
// packages/stream-connector/src/Runtime/
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
var
|
|
2042
|
-
constructor(
|
|
2043
|
-
|
|
2044
|
-
this.
|
|
2045
|
-
this.slot = slot;
|
|
2046
|
-
__publicField(this, "bound", true);
|
|
2047
|
-
}
|
|
2048
|
-
get isBound() {
|
|
2049
|
-
return this.bound;
|
|
2050
|
-
}
|
|
2051
|
-
send(payload, messageType) {
|
|
2052
|
-
this.ensureBound();
|
|
2053
|
-
return this.connector.sendForActor(this, payload, messageType);
|
|
2054
|
-
}
|
|
2055
|
-
request(payload, messageType) {
|
|
2056
|
-
this.ensureBound();
|
|
2057
|
-
return this.connector.requestForActor(this, payload, messageType);
|
|
2058
|
-
}
|
|
2059
|
-
on(nameOrType, handler, messageType) {
|
|
2060
|
-
return this.connector.onActorMessage(this, nameOrType, handler, messageType);
|
|
2061
|
-
}
|
|
2062
|
-
ensureBound() {
|
|
2063
|
-
if (!this.bound) {
|
|
2064
|
-
throw connectorError(
|
|
2065
|
-
"validationFailed" /* ValidationFailed */,
|
|
2066
|
-
`Actor '${this.actorId}' is no longer bound.`
|
|
2067
|
-
);
|
|
2068
|
-
}
|
|
2069
|
-
}
|
|
2070
|
-
close() {
|
|
2071
|
-
this.bound = false;
|
|
2072
|
-
}
|
|
2073
|
-
};
|
|
2074
|
-
var ZlinkStreamActors = class {
|
|
2075
|
-
constructor(connector, receivedMessages, events) {
|
|
2076
|
-
this.connector = connector;
|
|
2077
|
-
this.receivedMessages = receivedMessages;
|
|
2078
|
-
this.events = events;
|
|
2079
|
-
__publicField(this, "bySlot", /* @__PURE__ */ new Map());
|
|
2080
|
-
__publicField(this, "byId", /* @__PURE__ */ new Map());
|
|
2081
|
-
__publicField(this, "issued", []);
|
|
2082
|
-
__publicField(this, "boundHandlers", /* @__PURE__ */ new Set());
|
|
2083
|
-
__publicField(this, "unboundHandlers", /* @__PURE__ */ new Set());
|
|
2084
|
-
}
|
|
2085
|
-
get snapshot() {
|
|
2086
|
-
return Object.freeze(Array.from(this.bySlot.values()));
|
|
2087
|
-
}
|
|
2088
|
-
find(actorId) {
|
|
2089
|
-
return this.byId.get(actorId);
|
|
2090
|
-
}
|
|
2091
|
-
onBound(handler) {
|
|
2092
|
-
this.boundHandlers.add(handler);
|
|
2093
|
-
return subscription(() => this.boundHandlers.delete(handler));
|
|
2094
|
-
}
|
|
2095
|
-
onUnbound(handler) {
|
|
2096
|
-
this.unboundHandlers.add(handler);
|
|
2097
|
-
return subscription(() => this.unboundHandlers.delete(handler));
|
|
2098
|
-
}
|
|
2099
|
-
processControl(name, payload, signal) {
|
|
2100
|
-
if (name === ACTOR_BOUND) {
|
|
2101
|
-
this.bind(payload, signal);
|
|
2102
|
-
return true;
|
|
2103
|
-
}
|
|
2104
|
-
if (name === ACTOR_UNBOUND) {
|
|
2105
|
-
this.unbind(payload, signal);
|
|
2106
|
-
return true;
|
|
2107
|
-
}
|
|
2108
|
-
return false;
|
|
2109
|
-
}
|
|
2110
|
-
resolve(slot) {
|
|
2111
|
-
const actor = this.bySlot.get(slot);
|
|
2112
|
-
if (actor === void 0) {
|
|
2113
|
-
throw connectorError(
|
|
2114
|
-
"frameDecodeFailed" /* FrameDecodeFailed */,
|
|
2115
|
-
`Actor slot '${slot}' is not bound.`
|
|
2116
|
-
);
|
|
2117
|
-
}
|
|
2118
|
-
return actor;
|
|
2119
|
-
}
|
|
2120
|
-
closeAll(signal) {
|
|
2121
|
-
for (const actor of this.issued) {
|
|
2122
|
-
if (!actor.isBound) continue;
|
|
2123
|
-
this.bySlot.delete(actor.slot);
|
|
2124
|
-
this.byId.delete(actor.actorId);
|
|
2125
|
-
actor.close();
|
|
2126
|
-
this.queue(this.unboundHandlers, actor, signal);
|
|
2127
|
-
}
|
|
2128
|
-
this.issued.length = 0;
|
|
2129
|
-
}
|
|
2130
|
-
bind(payload, signal) {
|
|
2131
|
-
if (payload.length < 5 || payload[0] !== 1) {
|
|
2132
|
-
throw invalidControl("Actor bound payload is invalid.");
|
|
2133
|
-
}
|
|
2134
|
-
const slot = payload[1] << 8 | payload[2];
|
|
2135
|
-
const idLength = payload[3];
|
|
2136
|
-
if (slot === 0 || idLength === 0 || payload.length !== 4 + idLength) {
|
|
2137
|
-
throw invalidControl("Actor bound payload is invalid.");
|
|
2138
|
-
}
|
|
2139
|
-
let actorId;
|
|
2140
|
-
try {
|
|
2141
|
-
actorId = new TextDecoder("utf-8", { fatal: true }).decode(payload.subarray(4));
|
|
2142
|
-
} catch (cause) {
|
|
2143
|
-
throw connectorError(
|
|
2144
|
-
"frameDecodeFailed" /* FrameDecodeFailed */,
|
|
2145
|
-
"Actor id is not valid UTF-8.",
|
|
2146
|
-
cause
|
|
2147
|
-
);
|
|
2148
|
-
}
|
|
2149
|
-
if (actorId.length === 0 || this.bySlot.has(slot) || this.byId.has(actorId)) {
|
|
2150
|
-
throw invalidControl("Actor bound identity is already in use.");
|
|
2151
|
-
}
|
|
2152
|
-
const actor = new DefaultZlinkStreamActor(this.connector, actorId, slot);
|
|
2153
|
-
this.bySlot.set(slot, actor);
|
|
2154
|
-
this.byId.set(actorId, actor);
|
|
2155
|
-
this.issued.push(actor);
|
|
2156
|
-
this.queue(this.boundHandlers, actor, signal);
|
|
2157
|
-
}
|
|
2158
|
-
unbind(payload, signal) {
|
|
2159
|
-
if (payload.length !== 3 || payload[0] !== 1) {
|
|
2160
|
-
throw invalidControl("Actor unbound payload is invalid.");
|
|
2161
|
-
}
|
|
2162
|
-
const slot = payload[1] << 8 | payload[2];
|
|
2163
|
-
const actor = this.bySlot.get(slot);
|
|
2164
|
-
if (slot === 0 || actor === void 0) {
|
|
2165
|
-
throw invalidControl(`Actor slot '${slot}' is not bound.`);
|
|
2166
|
-
}
|
|
2167
|
-
this.bySlot.delete(slot);
|
|
2168
|
-
this.byId.delete(actor.actorId);
|
|
2169
|
-
actor.close();
|
|
2170
|
-
this.queue(this.unboundHandlers, actor, signal);
|
|
2171
|
-
}
|
|
2172
|
-
queue(handlers, actor, signal) {
|
|
2173
|
-
this.receivedMessages.enqueueCallback(() => {
|
|
2174
|
-
for (const handler of Array.from(handlers)) {
|
|
2175
|
-
this.invoke(handler, actor, signal);
|
|
2176
|
-
}
|
|
2177
|
-
});
|
|
2178
|
-
}
|
|
2179
|
-
invoke(handler, actor, signal) {
|
|
2180
|
-
try {
|
|
2181
|
-
Promise.resolve(handler(actor, signal)).catch((cause) => {
|
|
2182
|
-
void this.events.publishError(
|
|
2183
|
-
{
|
|
2184
|
-
code: "userCallbackFailed" /* UserCallbackFailed */,
|
|
2185
|
-
message: "Actor lifecycle handler failed.",
|
|
2186
|
-
cause
|
|
2187
|
-
},
|
|
2188
|
-
signal
|
|
2189
|
-
);
|
|
2190
|
-
});
|
|
2191
|
-
} catch (cause) {
|
|
2192
|
-
void this.events.publishError(
|
|
2193
|
-
{
|
|
2194
|
-
code: "userCallbackFailed" /* UserCallbackFailed */,
|
|
2195
|
-
message: "Actor lifecycle handler failed.",
|
|
2196
|
-
cause
|
|
2197
|
-
},
|
|
2198
|
-
signal
|
|
2199
|
-
);
|
|
2200
|
-
}
|
|
2430
|
+
// packages/stream-connector/src/Runtime/ZlinkStreamReceiveDispatcher.ts
|
|
2431
|
+
function closeReasonFor(error) {
|
|
2432
|
+
return error.code === "frameDecodeFailed" /* FrameDecodeFailed */ || error.code === "frameTooLarge" /* FrameTooLarge */ ? "ProtocolError" : "TransportError";
|
|
2433
|
+
}
|
|
2434
|
+
var ZlinkStreamConnectionEnd = class extends Error {
|
|
2435
|
+
constructor(error) {
|
|
2436
|
+
super(error.message);
|
|
2437
|
+
this.error = error;
|
|
2201
2438
|
}
|
|
2202
2439
|
};
|
|
2203
|
-
function invalidControl(message) {
|
|
2204
|
-
return connectorError("frameDecodeFailed" /* FrameDecodeFailed */, message);
|
|
2205
|
-
}
|
|
2206
|
-
|
|
2207
|
-
// packages/stream-connector/src/Runtime/ZlinkStreamReceiveDispatcher.ts
|
|
2208
2440
|
var ZlinkStreamReceiveDispatcher = class {
|
|
2209
2441
|
constructor(protocol, pendingRequests, receivedMessages, frameSender, events, actors, serverClosing) {
|
|
2210
2442
|
this.protocol = protocol;
|
|
@@ -2224,15 +2456,20 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
2224
2456
|
* the recheck the rest of a dead connection's batch lands on the new
|
|
2225
2457
|
* connection's state, and the §10 arrival counts, which start at 0 when a
|
|
2226
2458
|
* connection is established, take the stale frames on top.
|
|
2227
|
-
* @param connectionForSend Resolves the connection a reply belongs on at the
|
|
2228
|
-
* moment it is written. The captured `connection` is the one the batch was
|
|
2229
|
-
* read from, which a reconnect may already have replaced.
|
|
2230
2459
|
*/
|
|
2231
|
-
async readAndDispatch(connection, signal, isCurrent
|
|
2460
|
+
async readAndDispatch(connection, signal, isCurrent) {
|
|
2232
2461
|
if ((connection == null ? void 0 : connection.read) === void 0) {
|
|
2233
2462
|
return { available: false, inbound: false };
|
|
2234
2463
|
}
|
|
2235
|
-
|
|
2464
|
+
let frameBytes;
|
|
2465
|
+
try {
|
|
2466
|
+
frameBytes = await connection.read(signal);
|
|
2467
|
+
} catch (cause) {
|
|
2468
|
+
if ((signal == null ? void 0 : signal.aborted) === true) throw cause;
|
|
2469
|
+
throw new ZlinkStreamConnectionEnd(
|
|
2470
|
+
toStreamError(cause, "disconnected" /* Disconnected */, "Transport read failed.")
|
|
2471
|
+
);
|
|
2472
|
+
}
|
|
2236
2473
|
if (isCurrent !== void 0 && !isCurrent()) {
|
|
2237
2474
|
return { available: false, inbound: false };
|
|
2238
2475
|
}
|
|
@@ -2243,87 +2480,102 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
2243
2480
|
try {
|
|
2244
2481
|
frames = this.protocol.decodeFrames(frameBytes);
|
|
2245
2482
|
} catch (cause) {
|
|
2246
|
-
throw
|
|
2483
|
+
throw new ZlinkStreamConnectionEnd(
|
|
2484
|
+
toStreamError(cause, "frameDecodeFailed" /* FrameDecodeFailed */, "Frame decode failed.")
|
|
2485
|
+
);
|
|
2247
2486
|
}
|
|
2248
2487
|
for (const frame of frames) {
|
|
2249
2488
|
if (isCurrent !== void 0 && !isCurrent()) {
|
|
2250
2489
|
break;
|
|
2251
2490
|
}
|
|
2252
2491
|
try {
|
|
2253
|
-
await this.dispatch(connection, frame.header, frame.payload, signal
|
|
2492
|
+
await this.dispatch(connection, frame.header, frame.payload, signal);
|
|
2254
2493
|
} catch (cause) {
|
|
2255
|
-
if (
|
|
2256
|
-
throw cause;
|
|
2257
|
-
}
|
|
2494
|
+
if (cause instanceof ZlinkStreamConnectionEnd) throw cause;
|
|
2258
2495
|
const error = toStreamError(
|
|
2259
2496
|
cause,
|
|
2260
2497
|
"frameDecodeFailed" /* FrameDecodeFailed */,
|
|
2261
2498
|
"Frame dispatch failed."
|
|
2262
2499
|
);
|
|
2263
2500
|
if (error.code === "frameDecodeFailed" /* FrameDecodeFailed */) {
|
|
2264
|
-
throw
|
|
2501
|
+
throw new ZlinkStreamConnectionEnd(error);
|
|
2265
2502
|
}
|
|
2266
|
-
|
|
2503
|
+
this.events.publishError(error, signal);
|
|
2267
2504
|
}
|
|
2268
2505
|
}
|
|
2269
2506
|
return { available: true, inbound: true };
|
|
2270
2507
|
}
|
|
2271
|
-
|
|
2508
|
+
/**
|
|
2509
|
+
* Spec stream-connector 32 §4.7 and §9: a decompressed payload over the
|
|
2510
|
+
* receive limit is `FrameTooLarge` and ends the connection as a protocol
|
|
2511
|
+
* error, like a wire payload over the limit. A payload that does not
|
|
2512
|
+
* decompress fails only its packet.
|
|
2513
|
+
*/
|
|
2514
|
+
decodePayload(header, payload) {
|
|
2515
|
+
try {
|
|
2516
|
+
return this.protocol.decodePayload(header, payload);
|
|
2517
|
+
} catch (cause) {
|
|
2518
|
+
const error = toStreamError(
|
|
2519
|
+
cause,
|
|
2520
|
+
"decompressionFailed" /* DecompressionFailed */,
|
|
2521
|
+
"Decompression failed."
|
|
2522
|
+
);
|
|
2523
|
+
if (error.code === "frameTooLarge" /* FrameTooLarge */) {
|
|
2524
|
+
throw new ZlinkStreamConnectionEnd(error);
|
|
2525
|
+
}
|
|
2526
|
+
throw cause;
|
|
2527
|
+
}
|
|
2528
|
+
}
|
|
2529
|
+
async dispatch(connection, header, payload, signal) {
|
|
2272
2530
|
const actor = header.actorSlot === void 0 ? void 0 : this.actors.resolve(header.actorSlot);
|
|
2273
2531
|
if (header.kind === 3 /* Response */ && header.requestSeq !== void 0) {
|
|
2274
2532
|
try {
|
|
2275
|
-
|
|
2533
|
+
this.pendingRequests.resolve(
|
|
2276
2534
|
header.requestSeq,
|
|
2277
|
-
{
|
|
2535
|
+
() => ({
|
|
2278
2536
|
codec: header.codec,
|
|
2279
|
-
payload: this.
|
|
2280
|
-
},
|
|
2537
|
+
payload: this.decodePayload(header, payload)
|
|
2538
|
+
}),
|
|
2281
2539
|
header.metadata
|
|
2282
|
-
)
|
|
2283
|
-
await this.events.publishError(
|
|
2284
|
-
{
|
|
2285
|
-
code: "frameDecodeFailed" /* FrameDecodeFailed */,
|
|
2286
|
-
message: `Response request sequence '${header.requestSeq}' has no pending request.`
|
|
2287
|
-
},
|
|
2288
|
-
signal
|
|
2289
|
-
);
|
|
2290
|
-
}
|
|
2540
|
+
);
|
|
2291
2541
|
} catch (cause) {
|
|
2542
|
+
if (cause instanceof ZlinkStreamConnectionEnd) throw cause;
|
|
2292
2543
|
const decodeError = toStreamError(
|
|
2293
2544
|
cause,
|
|
2294
2545
|
"decompressionFailed" /* DecompressionFailed */,
|
|
2295
2546
|
"Decompression failed."
|
|
2296
2547
|
);
|
|
2297
2548
|
if (!this.pendingRequests.reject(header.requestSeq, decodeError)) {
|
|
2298
|
-
|
|
2549
|
+
this.events.publishError(decodeError, signal);
|
|
2299
2550
|
}
|
|
2300
2551
|
}
|
|
2301
2552
|
return;
|
|
2302
2553
|
}
|
|
2303
2554
|
if (header.kind === 4 /* Error */ && header.requestSeq !== void 0) {
|
|
2304
2555
|
try {
|
|
2305
|
-
const remoteError = decodeRemoteError(this.
|
|
2556
|
+
const remoteError = decodeRemoteError(this.decodePayload(header, payload));
|
|
2306
2557
|
if (!this.pendingRequests.reject(header.requestSeq, remoteError)) {
|
|
2307
|
-
|
|
2558
|
+
this.events.publishError(remoteError, signal);
|
|
2308
2559
|
}
|
|
2309
2560
|
} catch (cause) {
|
|
2561
|
+
if (cause instanceof ZlinkStreamConnectionEnd) throw cause;
|
|
2310
2562
|
const decodeError = toStreamError(
|
|
2311
2563
|
cause,
|
|
2312
2564
|
"frameDecodeFailed" /* FrameDecodeFailed */,
|
|
2313
2565
|
"Remote error payload is invalid."
|
|
2314
2566
|
);
|
|
2315
2567
|
if (!this.pendingRequests.reject(header.requestSeq, decodeError)) {
|
|
2316
|
-
|
|
2568
|
+
this.events.publishError(decodeError, signal);
|
|
2317
2569
|
}
|
|
2318
2570
|
}
|
|
2319
2571
|
return;
|
|
2320
2572
|
}
|
|
2321
2573
|
if (header.kind === 4 /* Error */) {
|
|
2322
|
-
|
|
2574
|
+
this.events.publishError(decodeRemoteError(this.decodePayload(header, payload)), signal);
|
|
2323
2575
|
return;
|
|
2324
2576
|
}
|
|
2325
2577
|
if (header.kind === 5 /* Control */) {
|
|
2326
|
-
await this.dispatchControl(connection, header, payload, signal
|
|
2578
|
+
await this.dispatchControl(connection, header, payload, signal);
|
|
2327
2579
|
return;
|
|
2328
2580
|
}
|
|
2329
2581
|
if (header.kind === 1 /* Send */) {
|
|
@@ -2331,7 +2583,7 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
2331
2583
|
{
|
|
2332
2584
|
name: header.name,
|
|
2333
2585
|
metadata: header.metadata,
|
|
2334
|
-
payload: { codec: header.codec, payload: this.
|
|
2586
|
+
payload: { codec: header.codec, payload: this.decodePayload(header, payload) },
|
|
2335
2587
|
actorId: actor == null ? void 0 : actor.actorId,
|
|
2336
2588
|
[zlinkStreamActorBinding]: actor
|
|
2337
2589
|
},
|
|
@@ -2339,8 +2591,8 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
2339
2591
|
);
|
|
2340
2592
|
}
|
|
2341
2593
|
}
|
|
2342
|
-
async dispatchControl(connection, header, payload, signal
|
|
2343
|
-
var _a
|
|
2594
|
+
async dispatchControl(connection, header, payload, signal) {
|
|
2595
|
+
var _a;
|
|
2344
2596
|
if (this.actors.processControl(header.name, payload, signal)) {
|
|
2345
2597
|
return;
|
|
2346
2598
|
}
|
|
@@ -2356,18 +2608,7 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
2356
2608
|
);
|
|
2357
2609
|
}
|
|
2358
2610
|
if (header.name === ZLINK_STREAM_HEARTBEAT_PING) {
|
|
2359
|
-
|
|
2360
|
-
await this.frameSender.sendControl(
|
|
2361
|
-
(_b = connectionForSend == null ? void 0 : connectionForSend()) != null ? _b : connection,
|
|
2362
|
-
ZLINK_STREAM_HEARTBEAT_PONG,
|
|
2363
|
-
signal
|
|
2364
|
-
);
|
|
2365
|
-
} catch (cause) {
|
|
2366
|
-
throw connectorError(
|
|
2367
|
-
"sendFailed" /* SendFailed */,
|
|
2368
|
-
cause instanceof Error ? cause.message : "Heartbeat pong send failed."
|
|
2369
|
-
);
|
|
2370
|
-
}
|
|
2611
|
+
await this.frameSender.sendControl(connection, ZLINK_STREAM_HEARTBEAT_PONG);
|
|
2371
2612
|
return;
|
|
2372
2613
|
}
|
|
2373
2614
|
if (header.name !== ZLINK_STREAM_HEARTBEAT_PONG) {
|
|
@@ -2375,8 +2616,7 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
2375
2616
|
}
|
|
2376
2617
|
}
|
|
2377
2618
|
};
|
|
2378
|
-
function decodeRemoteError(
|
|
2379
|
-
const decodedPayload = protocol.decodePayload(header, payload);
|
|
2619
|
+
function decodeRemoteError(decodedPayload) {
|
|
2380
2620
|
let decoded;
|
|
2381
2621
|
try {
|
|
2382
2622
|
decoded = JSON.parse(utf8Decode2(decodedPayload));
|
|
@@ -2422,6 +2662,7 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
2422
2662
|
__publicField(this, "lastInboundAt", 0);
|
|
2423
2663
|
__publicField(this, "closeTask");
|
|
2424
2664
|
__publicField(this, "connectTask");
|
|
2665
|
+
__publicField(this, "connectAbort");
|
|
2425
2666
|
__publicField(this, "disconnectTask");
|
|
2426
2667
|
__publicField(this, "closeRequested", false);
|
|
2427
2668
|
__publicField(this, "disconnectedPublished", false);
|
|
@@ -2455,11 +2696,20 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
2455
2696
|
});
|
|
2456
2697
|
return await this.connectTask;
|
|
2457
2698
|
}
|
|
2699
|
+
/**
|
|
2700
|
+
* Spec stream-connector 32 §7: close does not wait for a connect attempt or a
|
|
2701
|
+
* reconnect delay to run its course. The attempts listen to one controller
|
|
2702
|
+
* the lifecycle owns; close aborts it, and the caller's signal is forwarded
|
|
2703
|
+
* to it.
|
|
2704
|
+
*/
|
|
2458
2705
|
async connectOnce(signal) {
|
|
2459
|
-
|
|
2460
|
-
|
|
2706
|
+
const attempts = new AbortController();
|
|
2707
|
+
const forwardAbort = () => attempts.abort();
|
|
2708
|
+
signal == null ? void 0 : signal.addEventListener("abort", forwardAbort, { once: true });
|
|
2709
|
+
this.connectAbort = attempts;
|
|
2710
|
+
this.setState("connecting" /* Connecting */, void 0, signal);
|
|
2461
2711
|
try {
|
|
2462
|
-
const connection = await this.connectWithReconnect(signal);
|
|
2712
|
+
const connection = await this.connectWithReconnect(attempts.signal);
|
|
2463
2713
|
if (this.closeRequested) {
|
|
2464
2714
|
try {
|
|
2465
2715
|
await connection.close(signal);
|
|
@@ -2474,41 +2724,62 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
2474
2724
|
}
|
|
2475
2725
|
this.currentConnection = connection;
|
|
2476
2726
|
this.connectionGeneration += 1;
|
|
2727
|
+
const generation = this.connectionGeneration;
|
|
2728
|
+
this.frameSender.open(connection, (error) => {
|
|
2729
|
+
void this.disconnectForTransportFailure(error, connection, generation);
|
|
2730
|
+
});
|
|
2477
2731
|
this.disconnectedPublished = false;
|
|
2478
2732
|
this.receivedMessages.resetForNewConnection();
|
|
2479
2733
|
this.lastInboundAt = Date.now();
|
|
2480
|
-
|
|
2734
|
+
this.setState("connected" /* Connected */, void 0, signal);
|
|
2481
2735
|
this.startHeartbeat();
|
|
2482
2736
|
this.startReceiveLoop();
|
|
2483
2737
|
} catch (cause) {
|
|
2484
2738
|
if (this.closeRequested) {
|
|
2485
2739
|
const message = cause instanceof Error ? cause.message : "Connector closed while connecting.";
|
|
2486
|
-
|
|
2487
|
-
|
|
2740
|
+
throw connectorError("disconnected" /* Disconnected */, message, cause);
|
|
2741
|
+
}
|
|
2742
|
+
if ((signal == null ? void 0 : signal.aborted) === true) {
|
|
2743
|
+
this.setState("disconnected" /* Disconnected */, void 0, signal);
|
|
2744
|
+
throwIfAborted(signal);
|
|
2488
2745
|
}
|
|
2489
2746
|
const error = toStreamError(cause, "connectTimeout" /* ConnectTimeout */, "Connect failed.");
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
this.
|
|
2747
|
+
this.closeReasonValue = "TransportError";
|
|
2748
|
+
this.setState("disconnected" /* Disconnected */, error, signal);
|
|
2749
|
+
this.disconnectedPublished = false;
|
|
2750
|
+
this.publishDisconnected(signal);
|
|
2493
2751
|
throw new ZlinkStreamException(error);
|
|
2752
|
+
} finally {
|
|
2753
|
+
signal == null ? void 0 : signal.removeEventListener("abort", forwardAbort);
|
|
2754
|
+
this.connectAbort = void 0;
|
|
2494
2755
|
}
|
|
2495
2756
|
}
|
|
2757
|
+
/**
|
|
2758
|
+
* Spec stream-connector 32 §7: a `close` called outside the registered
|
|
2759
|
+
* handlers and callbacks returns once the close work has ended. One called
|
|
2760
|
+
* from inside them returns right after starting it; the result goes to the
|
|
2761
|
+
* outside caller, so a callback never waits for the close of the path that
|
|
2762
|
+
* is running it.
|
|
2763
|
+
*/
|
|
2496
2764
|
async close(signal) {
|
|
2497
|
-
|
|
2498
|
-
this.
|
|
2499
|
-
|
|
2500
|
-
return await this.closeTask;
|
|
2765
|
+
var _a;
|
|
2766
|
+
if (this.currentConnection !== void 0 || this.closeReasonValue === void 0) {
|
|
2767
|
+
this.closeReasonValue = "ClientClose";
|
|
2501
2768
|
}
|
|
2502
|
-
|
|
2769
|
+
this.closeRequested = true;
|
|
2770
|
+
if (this.closeTask === void 0 && this.currentState === "closed" /* Closed */) {
|
|
2503
2771
|
return;
|
|
2504
2772
|
}
|
|
2505
|
-
this.closeTask = this.closeOnce(signal).finally(() => {
|
|
2773
|
+
const closeTask = (_a = this.closeTask) != null ? _a : this.closeTask = this.closeOnce(signal).finally(() => {
|
|
2506
2774
|
this.closeTask = void 0;
|
|
2507
2775
|
});
|
|
2508
|
-
|
|
2776
|
+
if (this.receivedMessages.dispatching) {
|
|
2777
|
+
void closeTask.catch(() => void 0);
|
|
2778
|
+
return;
|
|
2779
|
+
}
|
|
2780
|
+
return await closeTask;
|
|
2509
2781
|
}
|
|
2510
2782
|
async serverClosing(reason) {
|
|
2511
|
-
this.closeReasonValue = reason;
|
|
2512
2783
|
const error = {
|
|
2513
2784
|
code: "disconnected" /* Disconnected */,
|
|
2514
2785
|
message: `Server closed the session: ${reason}.`
|
|
@@ -2516,40 +2787,30 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
2516
2787
|
await this.disconnectForTransportFailure(
|
|
2517
2788
|
error,
|
|
2518
2789
|
this.currentConnection,
|
|
2519
|
-
this.connectionGeneration
|
|
2790
|
+
this.connectionGeneration,
|
|
2791
|
+
reason
|
|
2520
2792
|
);
|
|
2521
2793
|
}
|
|
2522
2794
|
async closeOnce(signal) {
|
|
2523
|
-
var _a, _b;
|
|
2524
|
-
|
|
2525
|
-
await ((_b = this.
|
|
2526
|
-
|
|
2527
|
-
this.stopHeartbeat();
|
|
2528
|
-
this.stopReceiveLoop();
|
|
2529
|
-
this.currentConnection = void 0;
|
|
2795
|
+
var _a, _b, _c;
|
|
2796
|
+
(_a = this.connectAbort) == null ? void 0 : _a.abort();
|
|
2797
|
+
await ((_b = this.connectTask) == null ? void 0 : _b.catch(() => void 0));
|
|
2798
|
+
await ((_c = this.disconnectTask) == null ? void 0 : _c.catch(() => void 0));
|
|
2530
2799
|
const errors = [];
|
|
2531
2800
|
if (this.lateConnectCleanupError !== void 0) {
|
|
2532
2801
|
errors.push(this.lateConnectCleanupError);
|
|
2533
2802
|
this.lateConnectCleanupError = void 0;
|
|
2534
2803
|
}
|
|
2535
2804
|
try {
|
|
2536
|
-
await this.
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
try {
|
|
2541
|
-
await (connection == null ? void 0 : connection.close(signal));
|
|
2805
|
+
await this.tearDownConnection(
|
|
2806
|
+
{ code: "disconnected" /* Disconnected */, message: "Connector closed." },
|
|
2807
|
+
signal
|
|
2808
|
+
);
|
|
2542
2809
|
} catch (error) {
|
|
2543
2810
|
errors.push(error);
|
|
2544
2811
|
}
|
|
2545
|
-
this.
|
|
2546
|
-
|
|
2547
|
-
message: "Connector closed."
|
|
2548
|
-
});
|
|
2549
|
-
this.receivedMessages.connectionEnded();
|
|
2550
|
-
this.actors.closeAll(signal);
|
|
2551
|
-
this.queueState("closed" /* Closed */, void 0, signal);
|
|
2552
|
-
this.queueDisconnected(signal);
|
|
2812
|
+
this.setState("closed" /* Closed */, void 0, signal);
|
|
2813
|
+
this.publishDisconnected(signal);
|
|
2553
2814
|
if (errors.length === 1) throw errors[0];
|
|
2554
2815
|
if (errors.length > 1) throw new AggregateError(errors, "Stream connector close failed.");
|
|
2555
2816
|
}
|
|
@@ -2567,7 +2828,7 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
2567
2828
|
if (this.options.dispatchMode !== "immediate" /* Immediate */) {
|
|
2568
2829
|
await this.settleReceiveLoop();
|
|
2569
2830
|
}
|
|
2570
|
-
|
|
2831
|
+
this.receivedMessages.pump();
|
|
2571
2832
|
}
|
|
2572
2833
|
connectionForSend() {
|
|
2573
2834
|
if (this.currentConnection === void 0 || this.currentState !== "connected" /* Connected */) {
|
|
@@ -2580,8 +2841,7 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
2580
2841
|
const result = await this.receiveDispatcher.readAndDispatch(
|
|
2581
2842
|
connection,
|
|
2582
2843
|
signal,
|
|
2583
|
-
() => this.isCurrentConnection(connection, generation)
|
|
2584
|
-
() => this.connectionForSend()
|
|
2844
|
+
() => this.isCurrentConnection(connection, generation)
|
|
2585
2845
|
);
|
|
2586
2846
|
if (result.inbound && this.isCurrentConnection(connection, generation)) {
|
|
2587
2847
|
this.lastInboundAt = Date.now();
|
|
@@ -2590,7 +2850,10 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
2590
2850
|
}
|
|
2591
2851
|
async connectWithReconnect(signal) {
|
|
2592
2852
|
let attempt = 0;
|
|
2593
|
-
let delayMs =
|
|
2853
|
+
let delayMs = Math.min(
|
|
2854
|
+
this.options.reconnect.initialDelayMs,
|
|
2855
|
+
this.options.reconnect.maxDelayMs
|
|
2856
|
+
);
|
|
2594
2857
|
let lastError;
|
|
2595
2858
|
const maxAttempts = this.options.reconnect.enabled ? this.options.reconnect.maxAttempts : 1;
|
|
2596
2859
|
const unlimited = maxAttempts === null;
|
|
@@ -2600,10 +2863,10 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
2600
2863
|
return await this.options.transportFactory.connect(this.options, signal);
|
|
2601
2864
|
} catch (cause) {
|
|
2602
2865
|
lastError = toStreamError(cause, "connectTimeout" /* ConnectTimeout */, "Connect failed.");
|
|
2603
|
-
if (!this.options.reconnect.enabled || !unlimited && attempt >= maxAttempts) {
|
|
2866
|
+
if (this.closeRequested || !this.options.reconnect.enabled || !unlimited && attempt >= maxAttempts) {
|
|
2604
2867
|
break;
|
|
2605
2868
|
}
|
|
2606
|
-
|
|
2869
|
+
this.setState("reconnecting" /* Reconnecting */, lastError, signal);
|
|
2607
2870
|
await delay(randomizedDelay(delayMs), signal);
|
|
2608
2871
|
delayMs = Math.min(
|
|
2609
2872
|
this.options.reconnect.maxDelayMs,
|
|
@@ -2673,12 +2936,8 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
2673
2936
|
}
|
|
2674
2937
|
} catch (cause) {
|
|
2675
2938
|
if (signal.aborted) return;
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
"frameDecodeFailed" /* FrameDecodeFailed */,
|
|
2679
|
-
"Receive loop failed."
|
|
2680
|
-
);
|
|
2681
|
-
await this.disconnectForTransportFailure(error, connection, generation);
|
|
2939
|
+
if (!(cause instanceof ZlinkStreamConnectionEnd)) throw cause;
|
|
2940
|
+
await this.disconnectForTransportFailure(cause.error, connection, generation);
|
|
2682
2941
|
} finally {
|
|
2683
2942
|
this.receiveLoopSleeping = false;
|
|
2684
2943
|
this.releaseReceiveLoopSettled();
|
|
@@ -2735,37 +2994,35 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
2735
2994
|
return;
|
|
2736
2995
|
}
|
|
2737
2996
|
if (Date.now() - this.lastInboundAt > this.options.heartbeat.timeoutMs) {
|
|
2738
|
-
this.closeReasonValue = "HeartbeatTimeout";
|
|
2739
2997
|
const error = { code: "disconnected" /* Disconnected */, message: "Heartbeat timed out." };
|
|
2740
2998
|
await this.disconnectForTransportFailure(
|
|
2741
2999
|
error,
|
|
2742
3000
|
this.currentConnection,
|
|
2743
|
-
this.connectionGeneration
|
|
3001
|
+
this.connectionGeneration,
|
|
3002
|
+
"HeartbeatTimeout"
|
|
2744
3003
|
);
|
|
2745
3004
|
return;
|
|
2746
3005
|
}
|
|
2747
|
-
|
|
2748
|
-
const generation = this.connectionGeneration;
|
|
2749
|
-
try {
|
|
2750
|
-
await this.frameSender.sendControl(this.connectionForSend(), ZLINK_STREAM_HEARTBEAT_PING);
|
|
2751
|
-
} catch (cause) {
|
|
2752
|
-
const error = toStreamError(cause, "sendFailed" /* SendFailed */, "Heartbeat send failed.");
|
|
2753
|
-
await this.disconnectForTransportFailure(error, connection, generation);
|
|
2754
|
-
}
|
|
3006
|
+
await this.frameSender.sendControl(this.connectionForSend(), ZLINK_STREAM_HEARTBEAT_PING);
|
|
2755
3007
|
}
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
3008
|
+
/**
|
|
3009
|
+
* @param reason Given only where the reason is not read from `error`: a
|
|
3010
|
+
* server `session-closing` and the heartbeat timeout. Every other ending
|
|
3011
|
+
* takes it from {@link closeReasonFor}.
|
|
3012
|
+
*/
|
|
3013
|
+
async disconnectForTransportFailure(error, origin, generation, reason = closeReasonFor(error)) {
|
|
2759
3014
|
if (this.closeRequested || this.currentState === "closed" /* Closed */) {
|
|
2760
3015
|
return;
|
|
2761
3016
|
}
|
|
2762
3017
|
if (origin !== void 0 && !this.isCurrentConnection(origin, generation)) {
|
|
2763
3018
|
return;
|
|
2764
3019
|
}
|
|
3020
|
+
this.closeReasonValue = reason;
|
|
2765
3021
|
if (this.disconnectTask !== void 0) {
|
|
2766
3022
|
return await this.disconnectTask;
|
|
2767
3023
|
}
|
|
2768
|
-
this.disconnectTask = this.tearDownConnection(error).
|
|
3024
|
+
this.disconnectTask = this.tearDownConnection(error).catch(() => {
|
|
3025
|
+
}).finally(() => {
|
|
2769
3026
|
this.disconnectTask = void 0;
|
|
2770
3027
|
});
|
|
2771
3028
|
await this.disconnectTask;
|
|
@@ -2774,19 +3031,30 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
2774
3031
|
isCurrentConnection(connection, generation) {
|
|
2775
3032
|
return !this.closeRequested && this.currentConnection === connection && this.connectionGeneration === generation;
|
|
2776
3033
|
}
|
|
2777
|
-
/**
|
|
2778
|
-
|
|
3034
|
+
/**
|
|
3035
|
+
* Ends the current connection, for close and for transport loss alike. No
|
|
3036
|
+
* application callback runs from here. Spec stream-connector 32 §7 and §9:
|
|
3037
|
+
* every operation the ending connection fails (the frames it has not
|
|
3038
|
+
* written, the one it is writing and the pending requests) fails with
|
|
3039
|
+
* `Disconnected`, whatever ended it; the cause stays in the close reason.
|
|
3040
|
+
* The transport is closed without waiting for the frames.
|
|
3041
|
+
*/
|
|
3042
|
+
async tearDownConnection(error, signal) {
|
|
2779
3043
|
this.stopHeartbeat();
|
|
2780
3044
|
this.stopReceiveLoop();
|
|
2781
3045
|
const connection = this.currentConnection;
|
|
2782
3046
|
this.currentConnection = void 0;
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
3047
|
+
const disconnected = { code: "disconnected" /* Disconnected */, message: error.message };
|
|
3048
|
+
if (connection !== void 0) {
|
|
3049
|
+
this.frameSender.failUnwritten(
|
|
3050
|
+
connection,
|
|
3051
|
+
connectorError(disconnected.code, disconnected.message)
|
|
3052
|
+
);
|
|
2789
3053
|
}
|
|
3054
|
+
this.pendingRequests.failAll(disconnected);
|
|
3055
|
+
this.receivedMessages.connectionEnded();
|
|
3056
|
+
this.actors.closeAll(signal);
|
|
3057
|
+
await (connection == null ? void 0 : connection.close(signal));
|
|
2790
3058
|
}
|
|
2791
3059
|
/**
|
|
2792
3060
|
* Runs once the teardown promise has settled, so a handler reached from here
|
|
@@ -2798,8 +3066,8 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
2798
3066
|
*/
|
|
2799
3067
|
async announceDisconnect(error) {
|
|
2800
3068
|
if (this.closeRequested) return;
|
|
2801
|
-
this.
|
|
2802
|
-
this.
|
|
3069
|
+
this.setState("disconnected" /* Disconnected */, error);
|
|
3070
|
+
this.publishDisconnected();
|
|
2803
3071
|
if (this.shouldReconnect()) {
|
|
2804
3072
|
queueMicrotask(() => {
|
|
2805
3073
|
void this.connect().catch(() => void 0);
|
|
@@ -2809,79 +3077,35 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
2809
3077
|
shouldReconnect() {
|
|
2810
3078
|
return this.options.reconnect.enabled && !this.closeRequested;
|
|
2811
3079
|
}
|
|
2812
|
-
// Synchronous test-and-set, taken before any await, so the single disconnect
|
|
2813
|
-
// notification the spec promises is claimed by exactly one caller even when
|
|
2814
|
-
// the publishing itself is deferred.
|
|
2815
|
-
claimDisconnectedPublish() {
|
|
2816
|
-
if (this.disconnectedPublished) return false;
|
|
2817
|
-
this.disconnectedPublished = true;
|
|
2818
|
-
return true;
|
|
2819
|
-
}
|
|
2820
|
-
async publishDisconnectedOnce(signal) {
|
|
2821
|
-
if (!this.claimDisconnectedPublish()) return;
|
|
2822
|
-
await this.events.publishDisconnected(signal);
|
|
2823
|
-
}
|
|
2824
3080
|
/**
|
|
2825
|
-
* Spec stream-connector 32 §7:
|
|
2826
|
-
*
|
|
2827
|
-
*
|
|
2828
|
-
*
|
|
2829
|
-
*
|
|
2830
|
-
* Starting the publish without awaiting it still runs every handler right
|
|
2831
|
-
* here: an `async` function body runs synchronously up to its first `await`,
|
|
2832
|
-
* and `publishDisconnected` reaches each handler before that point. So the
|
|
2833
|
-
* handler has run by the time `close` returns, which is what the spec asks
|
|
2834
|
-
* for, while a handler that calls `close` no longer waits for the very
|
|
2835
|
-
* `closeTask` it is running inside. Java and C++ hand the handler to a queue
|
|
2836
|
-
* and return the same way.
|
|
2837
|
-
*
|
|
2838
|
-
* `claimDisconnectedPublish` is taken by the same call and before any await,
|
|
2839
|
-
* so deferring the completion never turns the one notification into two.
|
|
2840
|
-
*
|
|
2841
|
-
* Nothing awaits the promise, so a rejection would reach the process as an
|
|
2842
|
-
* unhandled rejection and kill it. Handler failures are already contained
|
|
2843
|
-
* where they were before this call stopped waiting — the `Promise.allSettled`
|
|
2844
|
-
* in `publishDisconnected` — and this `catch` covers what is left rather than
|
|
2845
|
-
* reporting the same failure a second time on the error surface.
|
|
3081
|
+
* Spec stream-connector 32 §6 and §7: one disconnect notification per
|
|
3082
|
+
* lifecycle event, handed to the dispatch queue. The connector does not wait
|
|
3083
|
+
* for the handler; `Manual` runs it when the application pumps dispatch.
|
|
3084
|
+
* The flag is tested and set synchronously, so concurrent callers for the
|
|
3085
|
+
* same event claim it once.
|
|
2846
3086
|
*/
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
if (!this.claimDisconnectedPublish()) return;
|
|
2852
|
-
this.receivedMessages.enqueueCallback(() => {
|
|
2853
|
-
void this.events.publishDisconnected(signal).catch(() => void 0);
|
|
2854
|
-
});
|
|
2855
|
-
}
|
|
2856
|
-
queueState(current, error, signal) {
|
|
2857
|
-
const change = this.transitionState(current, error);
|
|
2858
|
-
if (change === void 0) return;
|
|
2859
|
-
this.receivedMessages.enqueueCallback(() => {
|
|
2860
|
-
void this.publishStateChange(change, signal).catch(() => void 0);
|
|
2861
|
-
});
|
|
2862
|
-
}
|
|
2863
|
-
async setState(current, error, signal) {
|
|
2864
|
-
const change = this.transitionState(current, error);
|
|
2865
|
-
if (change === void 0) return;
|
|
2866
|
-
await this.publishStateChange(change, signal);
|
|
3087
|
+
publishDisconnected(signal) {
|
|
3088
|
+
if (this.disconnectedPublished) return;
|
|
3089
|
+
this.disconnectedPublished = true;
|
|
3090
|
+
this.events.publishDisconnected(signal);
|
|
2867
3091
|
}
|
|
2868
|
-
|
|
3092
|
+
setState(current, error, signal) {
|
|
2869
3093
|
const previous = this.currentState;
|
|
2870
3094
|
this.currentState = current;
|
|
2871
|
-
if (previous === current && error === void 0)
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
return { previous, current, error };
|
|
2875
|
-
}
|
|
2876
|
-
async publishStateChange(change, signal) {
|
|
2877
|
-
await this.events.publishStateChanged(change, signal);
|
|
2878
|
-
if (change.error !== void 0) await this.events.publishError(change.error, signal);
|
|
3095
|
+
if (previous === current && error === void 0) return;
|
|
3096
|
+
this.events.publishStateChanged({ previous, current, error }, signal);
|
|
3097
|
+
if (error !== void 0) this.events.publishError(error, signal);
|
|
2879
3098
|
}
|
|
2880
3099
|
};
|
|
2881
3100
|
|
|
2882
3101
|
// packages/stream-connector/src/Runtime/ZlinkStreamConnectorEvents.ts
|
|
2883
3102
|
var ZlinkStreamConnectorEvents = class {
|
|
2884
|
-
|
|
3103
|
+
/**
|
|
3104
|
+
* @param enqueueCallback Queues a callback that calls the number of handlers
|
|
3105
|
+
* `callbacks` reports for the handlers registered at that moment.
|
|
3106
|
+
*/
|
|
3107
|
+
constructor(enqueueCallback) {
|
|
3108
|
+
this.enqueueCallback = enqueueCallback;
|
|
2885
3109
|
__publicField(this, "errorHandlers", /* @__PURE__ */ new Set());
|
|
2886
3110
|
__publicField(this, "disconnectedHandlers", /* @__PURE__ */ new Set());
|
|
2887
3111
|
__publicField(this, "stateHandlers", /* @__PURE__ */ new Set());
|
|
@@ -2898,23 +3122,78 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
2898
3122
|
this.stateHandlers.add(handler);
|
|
2899
3123
|
return subscription(() => this.stateHandlers.delete(handler));
|
|
2900
3124
|
}
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
3125
|
+
publishError(error, signal) {
|
|
3126
|
+
this.publish(this.errorHandlers, (handler) => handler(error, signal), signal);
|
|
3127
|
+
}
|
|
3128
|
+
publishDisconnected(signal) {
|
|
3129
|
+
this.publish(this.disconnectedHandlers, (handler) => handler(signal), signal);
|
|
3130
|
+
}
|
|
3131
|
+
publishStateChanged(change, signal) {
|
|
3132
|
+
this.publish(this.stateHandlers, (handler) => handler(change, signal), signal);
|
|
3133
|
+
}
|
|
3134
|
+
/**
|
|
3135
|
+
* Spec stream-connector 32 §7: the connector runs a registered callback and
|
|
3136
|
+
* does not wait for it to finish. A thrown or rejected failure reaches the
|
|
3137
|
+
* error handlers as `UserCallbackFailed`.
|
|
3138
|
+
*/
|
|
3139
|
+
runUserCallback(run, failureMessage, signal) {
|
|
3140
|
+
this.invoke(
|
|
3141
|
+
run,
|
|
3142
|
+
(cause) => this.publishError(
|
|
3143
|
+
{ code: "userCallbackFailed" /* UserCallbackFailed */, message: failureMessage, cause },
|
|
3144
|
+
signal
|
|
3145
|
+
)
|
|
2904
3146
|
);
|
|
2905
3147
|
}
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
3148
|
+
publish(handlers, invoke, signal) {
|
|
3149
|
+
this.enqueueCallback(
|
|
3150
|
+
() => {
|
|
3151
|
+
for (const handler of Array.from(handlers)) {
|
|
3152
|
+
const report = (cause) => this.reportFailure(
|
|
3153
|
+
cause,
|
|
3154
|
+
signal,
|
|
3155
|
+
handlers === this.errorHandlers ? handler : void 0
|
|
3156
|
+
);
|
|
3157
|
+
this.invoke(() => invoke(handler), report);
|
|
3158
|
+
}
|
|
3159
|
+
},
|
|
3160
|
+
() => handlers.size
|
|
2909
3161
|
);
|
|
2910
3162
|
}
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
3163
|
+
reportFailure(cause, signal, failedHandler) {
|
|
3164
|
+
const error = {
|
|
3165
|
+
code: "userCallbackFailed" /* UserCallbackFailed */,
|
|
3166
|
+
message: "Connector event handler failed.",
|
|
3167
|
+
cause
|
|
3168
|
+
};
|
|
3169
|
+
if (failedHandler === void 0) {
|
|
3170
|
+
this.publishError(error, signal);
|
|
3171
|
+
return;
|
|
3172
|
+
}
|
|
3173
|
+
this.reportToRemaining(error, signal, /* @__PURE__ */ new Set([failedHandler]));
|
|
3174
|
+
}
|
|
3175
|
+
reportToRemaining(error, signal, attempted) {
|
|
3176
|
+
const remaining = Array.from(this.errorHandlers).filter(
|
|
3177
|
+
(candidate) => !attempted.has(candidate)
|
|
3178
|
+
);
|
|
3179
|
+
if (remaining.length === 0) return;
|
|
3180
|
+
const nextAttempted = /* @__PURE__ */ new Set([...attempted, ...remaining]);
|
|
3181
|
+
this.enqueueCallback(
|
|
3182
|
+
() => {
|
|
3183
|
+
for (const handler of remaining) {
|
|
3184
|
+
const report = (cause) => this.reportToRemaining({ ...error, cause }, signal, nextAttempted);
|
|
3185
|
+
this.invoke(() => handler(error, signal), report);
|
|
3186
|
+
}
|
|
3187
|
+
},
|
|
3188
|
+
() => remaining.length
|
|
2914
3189
|
);
|
|
2915
3190
|
}
|
|
2916
|
-
|
|
2917
|
-
|
|
3191
|
+
invoke(run, report) {
|
|
3192
|
+
try {
|
|
3193
|
+
Promise.resolve(run()).catch(report);
|
|
3194
|
+
} catch (cause) {
|
|
3195
|
+
report(cause);
|
|
3196
|
+
}
|
|
2918
3197
|
}
|
|
2919
3198
|
};
|
|
2920
3199
|
|
|
@@ -2985,11 +3264,7 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
2985
3264
|
if (this.closed || this.socket.readyState !== 1) {
|
|
2986
3265
|
throw connectorError("disconnected" /* Disconnected */, "Remote stream is not connected.");
|
|
2987
3266
|
}
|
|
2988
|
-
|
|
2989
|
-
this.socket.send(frame);
|
|
2990
|
-
} catch (cause) {
|
|
2991
|
-
throw connectorError("sendFailed" /* SendFailed */, "Send failed.", cause);
|
|
2992
|
-
}
|
|
3267
|
+
this.socket.send(frame);
|
|
2993
3268
|
}
|
|
2994
3269
|
async read(signal) {
|
|
2995
3270
|
throwIfAborted(signal);
|
|
@@ -3007,18 +3282,19 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
3007
3282
|
await this.waitForMessage(signal);
|
|
3008
3283
|
}
|
|
3009
3284
|
}
|
|
3285
|
+
/**
|
|
3286
|
+
* Spec stream-connector 32 §7: closing does not wait for the peer to read or
|
|
3287
|
+
* answer. `WebSocket.close` sends the close frame after the data already
|
|
3288
|
+
* handed to `send`, so a frame whose write completed is not torn.
|
|
3289
|
+
*/
|
|
3010
3290
|
async close(signal) {
|
|
3011
3291
|
throwIfAborted(signal);
|
|
3292
|
+
this.removeListeners();
|
|
3012
3293
|
if (!this.closed) {
|
|
3013
3294
|
this.closed = true;
|
|
3014
3295
|
this.socket.close();
|
|
3015
|
-
this.wakeReader();
|
|
3016
|
-
}
|
|
3017
|
-
try {
|
|
3018
|
-
await waitForClose(this.socket, signal);
|
|
3019
|
-
} finally {
|
|
3020
|
-
this.removeListeners();
|
|
3021
3296
|
}
|
|
3297
|
+
this.wakeReader();
|
|
3022
3298
|
}
|
|
3023
3299
|
waitForMessage(signal) {
|
|
3024
3300
|
if (this.readWaiter !== void 0) {
|
|
@@ -3064,21 +3340,6 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
3064
3340
|
return message;
|
|
3065
3341
|
}
|
|
3066
3342
|
};
|
|
3067
|
-
function waitForClose(socket, signal) {
|
|
3068
|
-
if (socket.readyState === 3) return Promise.resolve();
|
|
3069
|
-
return new Promise((resolve, reject) => {
|
|
3070
|
-
const onClose = () => finish();
|
|
3071
|
-
const onAbort = () => finish(connectorError("disconnected" /* Disconnected */, "Close canceled."));
|
|
3072
|
-
const finish = (error) => {
|
|
3073
|
-
socket.removeEventListener("close", onClose);
|
|
3074
|
-
signal == null ? void 0 : signal.removeEventListener("abort", onAbort);
|
|
3075
|
-
if (error === void 0) resolve();
|
|
3076
|
-
else reject(error);
|
|
3077
|
-
};
|
|
3078
|
-
socket.addEventListener("close", onClose, { once: true });
|
|
3079
|
-
signal == null ? void 0 : signal.addEventListener("abort", onAbort, { once: true });
|
|
3080
|
-
});
|
|
3081
|
-
}
|
|
3082
3343
|
async function waitForOpen(socket, connectTimeoutMs, signal) {
|
|
3083
3344
|
throwIfAborted(signal);
|
|
3084
3345
|
await new Promise((resolve, reject) => {
|
|
@@ -3127,7 +3388,9 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
3127
3388
|
constructor(options) {
|
|
3128
3389
|
__publicField(this, "receivedMessages");
|
|
3129
3390
|
__publicField(this, "lifecycle");
|
|
3130
|
-
__publicField(this, "events", new ZlinkStreamConnectorEvents(
|
|
3391
|
+
__publicField(this, "events", new ZlinkStreamConnectorEvents(
|
|
3392
|
+
(callback, callbacks) => this.receivedMessages.enqueueCallback(callback, callbacks)
|
|
3393
|
+
));
|
|
3131
3394
|
__publicField(this, "correlationCounter", 0n);
|
|
3132
3395
|
__publicField(this, "pendingRequests", new ZlinkStreamPendingRequests());
|
|
3133
3396
|
__publicField(this, "frameSender");
|
|
@@ -3173,7 +3436,7 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
3173
3436
|
return this.lifecycle.state;
|
|
3174
3437
|
}
|
|
3175
3438
|
get pendingDispatchCount() {
|
|
3176
|
-
return this.
|
|
3439
|
+
return this.receivedMessages.pendingCallbacks;
|
|
3177
3440
|
}
|
|
3178
3441
|
get actors() {
|
|
3179
3442
|
return this.boundActors.snapshot;
|
|
@@ -3230,7 +3493,12 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
3230
3493
|
}
|
|
3231
3494
|
request(payload, messageType) {
|
|
3232
3495
|
const encoded = this.encodePayload(payload, messageType);
|
|
3233
|
-
return new ZlinkStreamRequestBuilder(
|
|
3496
|
+
return new ZlinkStreamRequestBuilder(
|
|
3497
|
+
this,
|
|
3498
|
+
this.resolveNameOrDefault(encoded),
|
|
3499
|
+
encoded,
|
|
3500
|
+
(callback) => this.receivedMessages.enqueueCallback(callback)
|
|
3501
|
+
);
|
|
3234
3502
|
}
|
|
3235
3503
|
on(nameOrType, handler, messageType) {
|
|
3236
3504
|
const encodedHandler = (message, signal) => handler(
|
|
@@ -3263,29 +3531,25 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
3263
3531
|
this,
|
|
3264
3532
|
this.resolveNameOrDefault(encoded),
|
|
3265
3533
|
encoded,
|
|
3534
|
+
(callback) => this.receivedMessages.enqueueCallback(callback),
|
|
3266
3535
|
actor.slot,
|
|
3267
3536
|
() => actor.ensureBound()
|
|
3268
3537
|
);
|
|
3269
3538
|
}
|
|
3270
3539
|
onActorMessage(actor, nameOrType, handler, messageType) {
|
|
3271
|
-
const encodedHandler = (message, signal) =>
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
|
|
3280
|
-
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
},
|
|
3285
|
-
signal
|
|
3286
|
-
);
|
|
3287
|
-
};
|
|
3288
|
-
return this.receivedMessages.on(this.observedName(nameOrType), encodedHandler);
|
|
3540
|
+
const encodedHandler = (message, signal) => handler(
|
|
3541
|
+
{
|
|
3542
|
+
name: message.name,
|
|
3543
|
+
metadata: message.metadata,
|
|
3544
|
+
payload: this.decodePayload(
|
|
3545
|
+
message.payload,
|
|
3546
|
+
messageType != null ? messageType : typeof nameOrType === "function" ? nameOrType : void 0
|
|
3547
|
+
),
|
|
3548
|
+
actorId: message.actorId
|
|
3549
|
+
},
|
|
3550
|
+
signal
|
|
3551
|
+
);
|
|
3552
|
+
return this.receivedMessages.on(this.observedName(nameOrType), encodedHandler, actor);
|
|
3289
3553
|
}
|
|
3290
3554
|
waitFor(nameOrType) {
|
|
3291
3555
|
return new ZlinkStreamWaitBuilder(this, this.observedName(nameOrType));
|
|
@@ -3410,7 +3674,7 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
3410
3674
|
}
|
|
3411
3675
|
return payload;
|
|
3412
3676
|
}
|
|
3413
|
-
async sendEncoded(kind, name, payload, metadata, compress, requestSeq, signal, correlationId, actorSlot) {
|
|
3677
|
+
async sendEncoded(kind, name, payload, metadata, compress, requestSeq, signal, correlationId, actorSlot, expiry, onAccepted) {
|
|
3414
3678
|
await this.frameSender.send(
|
|
3415
3679
|
this.lifecycle.connectionForSend(),
|
|
3416
3680
|
kind,
|
|
@@ -3421,7 +3685,9 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
3421
3685
|
requestSeq,
|
|
3422
3686
|
signal,
|
|
3423
3687
|
correlationId,
|
|
3424
|
-
actorSlot
|
|
3688
|
+
actorSlot,
|
|
3689
|
+
expiry,
|
|
3690
|
+
onAccepted
|
|
3425
3691
|
);
|
|
3426
3692
|
}
|
|
3427
3693
|
/**
|
|
@@ -3444,37 +3710,48 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
3444
3710
|
}
|
|
3445
3711
|
};
|
|
3446
3712
|
let pending;
|
|
3713
|
+
let stopCancellation;
|
|
3447
3714
|
try {
|
|
3448
3715
|
throwIfAborted(signal);
|
|
3449
3716
|
for (const handler of Array.from(this.requestSendingHandlers)) {
|
|
3450
3717
|
try {
|
|
3451
3718
|
handler(sendingContext);
|
|
3452
3719
|
} catch (cause) {
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
|
|
3461
|
-
);
|
|
3462
|
-
});
|
|
3720
|
+
this.events.publishError(
|
|
3721
|
+
{
|
|
3722
|
+
code: "userCallbackFailed" /* UserCallbackFailed */,
|
|
3723
|
+
message: "Request sending hook failed.",
|
|
3724
|
+
cause
|
|
3725
|
+
},
|
|
3726
|
+
signal
|
|
3727
|
+
);
|
|
3463
3728
|
}
|
|
3464
3729
|
}
|
|
3465
3730
|
pending = this.pendingRequests.create(name, timeoutMs);
|
|
3466
|
-
|
|
3731
|
+
const accepted = pending;
|
|
3732
|
+
const write = this.sendEncoded(
|
|
3467
3733
|
2 /* Request */,
|
|
3468
3734
|
name,
|
|
3469
3735
|
payload,
|
|
3470
3736
|
requestMetadata,
|
|
3471
3737
|
compress,
|
|
3472
|
-
|
|
3738
|
+
accepted.requestSeq,
|
|
3473
3739
|
signal,
|
|
3474
3740
|
this.nextCorrelationId(),
|
|
3475
|
-
actorSlot
|
|
3741
|
+
actorSlot,
|
|
3742
|
+
accepted.promise,
|
|
3743
|
+
accepted.startTimeout
|
|
3476
3744
|
);
|
|
3477
|
-
const
|
|
3745
|
+
const canceled = new Promise((_, reject) => {
|
|
3746
|
+
const onAbort = () => reject(connectorError("disconnected" /* Disconnected */, "Operation canceled."));
|
|
3747
|
+
signal == null ? void 0 : signal.addEventListener("abort", onAbort, { once: true });
|
|
3748
|
+
stopCancellation = () => signal == null ? void 0 : signal.removeEventListener("abort", onAbort);
|
|
3749
|
+
});
|
|
3750
|
+
const reply = await Promise.race([
|
|
3751
|
+
write.then(() => accepted.promise),
|
|
3752
|
+
accepted.promise,
|
|
3753
|
+
canceled
|
|
3754
|
+
]);
|
|
3478
3755
|
this.publishReplyReceived(
|
|
3479
3756
|
{
|
|
3480
3757
|
requestPacketName: name,
|
|
@@ -3488,6 +3765,7 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
3488
3765
|
return reply.payload;
|
|
3489
3766
|
} catch (error) {
|
|
3490
3767
|
if (pending !== void 0) this.pendingRequests.cancel(pending.requestSeq);
|
|
3768
|
+
if ((signal == null ? void 0 : signal.aborted) === true) throw error;
|
|
3491
3769
|
this.publishReplyReceived(
|
|
3492
3770
|
{
|
|
3493
3771
|
requestPacketName: name,
|
|
@@ -3499,26 +3777,24 @@ var ZlinkStreamConnectorBundle = (() => {
|
|
|
3499
3777
|
signal
|
|
3500
3778
|
);
|
|
3501
3779
|
throw error;
|
|
3780
|
+
} finally {
|
|
3781
|
+
stopCancellation == null ? void 0 : stopCancellation();
|
|
3502
3782
|
}
|
|
3503
3783
|
}
|
|
3504
3784
|
publishReplyReceived(context, signal) {
|
|
3505
3785
|
if (this.replyReceivedHandlers.size === 0) return;
|
|
3506
|
-
this.receivedMessages.enqueueCallback(
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3510
|
-
|
|
3511
|
-
|
|
3512
|
-
toStreamError(
|
|
3513
|
-
cause,
|
|
3514
|
-
"userCallbackFailed" /* UserCallbackFailed */,
|
|
3515
|
-
"Reply received hook failed."
|
|
3516
|
-
),
|
|
3786
|
+
this.receivedMessages.enqueueCallback(
|
|
3787
|
+
() => {
|
|
3788
|
+
for (const handler of Array.from(this.replyReceivedHandlers)) {
|
|
3789
|
+
this.events.runUserCallback(
|
|
3790
|
+
() => handler(context, signal),
|
|
3791
|
+
"Reply received hook failed.",
|
|
3517
3792
|
signal
|
|
3518
3793
|
);
|
|
3519
3794
|
}
|
|
3520
|
-
}
|
|
3521
|
-
|
|
3795
|
+
},
|
|
3796
|
+
() => this.replyReceivedHandlers.size
|
|
3797
|
+
);
|
|
3522
3798
|
}
|
|
3523
3799
|
resolveNameOrDefault(payload) {
|
|
3524
3800
|
if (payload.messageType === void 0) {
|