@zlink-systems/framework 0.30.0 → 0.30.1
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/LICENSE +150 -68
- package/dist/.tsbuildinfo +1 -1
- package/dist/contracts/Actors/ZLinkActorClient.d.ts +2 -1
- package/dist/contracts/Channels/Calls.d.ts +2 -1
- package/dist/contracts/Common/ZLinkMessageMetadata.js +11 -5
- package/dist/contracts/Handlers/Attributes.d.ts +5 -13
- package/dist/contracts/Handlers/Attributes.js +7 -11
- package/dist/contracts/Handlers/JsonContract.d.ts +2 -46
- package/dist/contracts/Handlers/JsonContract.js +4 -153
- package/dist/contracts/Spots/Contracts.d.ts +2 -1
- package/dist/nest-integration.d.ts +1 -1
- package/dist/nest-integration.js +2 -1
- package/dist/runtime/actors/actor-client.d.ts +1 -1
- package/dist/runtime/actors/actor-client.js +14 -12
- package/dist/runtime/actors/actor-handoff.d.ts +1 -1
- package/dist/runtime/actors/actor-handoff.js +7 -4
- package/dist/runtime/actors/actor-join-relocation.d.ts +1 -0
- package/dist/runtime/actors/actor-local-native-join.js +9 -12
- package/dist/runtime/actors/actor-remote-wire.js +15 -0
- package/dist/runtime/actors/actor-routed-join-transport.d.ts +6 -2
- package/dist/runtime/actors/actor-routed-json-request.d.ts +2 -0
- package/dist/runtime/actors/index.d.ts +2 -1
- package/dist/runtime/actors/index.js +18 -6
- package/dist/runtime/actors/spot-actor-dispatch.js +2 -2
- package/dist/runtime/admission.d.ts +1 -1
- package/dist/runtime/admission.js +15 -5
- package/dist/runtime/application-jobs/application-ingress-record-owner.d.ts +6 -8
- package/dist/runtime/application-jobs/application-ingress-record-owner.js +39 -22
- package/dist/runtime/application-jobs/application-job-queue-scope.d.ts +2 -1
- package/dist/runtime/application-jobs/application-job-queue-scope.js +37 -22
- package/dist/runtime/application-jobs/contracts.d.ts +10 -1
- package/dist/runtime/backend/contracts/index.d.ts +18 -9
- package/dist/runtime/backend/mesh-completion-table.d.ts +9 -1
- package/dist/runtime/backend/mesh-completion-table.js +149 -49
- package/dist/runtime/backend/mesh-dispatch-pump.d.ts +3 -0
- package/dist/runtime/backend/mesh-dispatch-pump.js +32 -11
- package/dist/runtime/backend/node/node-backend-adapter-support.d.ts +2 -2
- package/dist/runtime/backend/node/node-backend-adapter-support.js +16 -9
- package/dist/runtime/backend/node/node-dealer-channel-client-transport.d.ts +1 -1
- package/dist/runtime/backend/node/node-dealer-channel-client-transport.js +5 -2
- package/dist/runtime/backend/node/node-raw-binding-port.js +42 -22
- package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +13 -5
- package/dist/runtime/backend/node/node-raw-mesh-backend.js +69 -51
- package/dist/runtime/backend/node/node-socket-backend-adapter.js +6 -6
- package/dist/runtime/backend/raw-binding-port.d.ts +2 -2
- package/dist/runtime/backend/runtime-message.d.ts +1 -0
- package/dist/runtime/backend/runtime-message.js +5 -0
- package/dist/runtime/backend/runtime-values.d.ts +1 -0
- package/dist/runtime/backend/runtime-values.js +2 -1
- package/dist/runtime/channels/channel-clients.d.ts +1 -0
- package/dist/runtime/channels/channel-clients.js +58 -21
- package/dist/runtime/channels/channel-dispatch-pipeline.d.ts +3 -2
- package/dist/runtime/channels/channel-dispatch-pipeline.js +20 -11
- package/dist/runtime/channels/channel-dispatch-services.d.ts +1 -0
- package/dist/runtime/channels/channel-dispatch-services.js +45 -0
- package/dist/runtime/channels/channel-dispatchers.d.ts +1 -1
- package/dist/runtime/channels/channel-dispatchers.js +27 -26
- package/dist/runtime/channels/channel-envelope-inspection.d.ts +1 -2
- package/dist/runtime/channels/channel-envelope-inspection.js +1 -16
- package/dist/runtime/channels/channel-envelope.d.ts +1 -0
- package/dist/runtime/channels/channel-envelope.js +83 -8
- package/dist/runtime/channels/channel-outbound-operations.d.ts +2 -2
- package/dist/runtime/channels/channel-outbound-operations.js +8 -8
- package/dist/runtime/channels/channel-runtime-manager.d.ts +6 -6
- package/dist/runtime/channels/channel-runtime-manager.js +12 -12
- package/dist/runtime/channels/channel-transports.d.ts +18 -15
- package/dist/runtime/channels/channel-transports.js +48 -31
- package/dist/runtime/channels/local-spot-route-transport.d.ts +1 -1
- package/dist/runtime/channels/local-spot-route-transport.js +2 -1
- package/dist/runtime/channels/router-socket-spot-route-transport.d.ts +2 -2
- package/dist/runtime/channels/router-socket-spot-route-transport.js +4 -4
- package/dist/runtime/channels/source-spot-router.d.ts +2 -2
- package/dist/runtime/channels/source-spot-router.js +4 -4
- package/dist/runtime/channels/spot-node-route-transport.d.ts +2 -2
- package/dist/runtime/channels/spot-node-route-transport.js +4 -4
- package/dist/runtime/channels/spot-route-bridge-transport.d.ts +2 -2
- package/dist/runtime/channels/spot-route-bridge-transport.js +4 -4
- package/dist/runtime/channels/spot-route-dispatch-strategy.d.ts +5 -4
- package/dist/runtime/channels/spot-route-dispatch-strategy.js +18 -18
- package/dist/runtime/execution/serial-execution-queue.d.ts +1 -0
- package/dist/runtime/execution/serial-execution-queue.js +1 -0
- package/dist/runtime/foundation/actor-join-recovery-codec.js +2 -2
- package/dist/runtime/foundation/durable-service-request.d.ts +14 -0
- package/dist/runtime/foundation/durable-service-request.js +98 -0
- package/dist/runtime/foundation/operation-identity.d.ts +1 -0
- package/dist/runtime/foundation/operation-identity.js +5 -1
- package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +22 -5
- package/dist/runtime/foundation/raw-service-mesh-runtime.js +356 -232
- package/dist/runtime/foundation/service-relocation-object-owner.d.ts +1 -0
- package/dist/runtime/foundation/service-relocation-object-owner.js +1 -0
- package/dist/runtime/foundation/service-relocation-runtime.d.ts +2 -0
- package/dist/runtime/foundation/service-relocation-runtime.js +13 -1
- package/dist/runtime/foundation/service-runtime-contracts.d.ts +2 -0
- package/dist/runtime/foundation/service-stateful-runtime.d.ts +4 -4
- package/dist/runtime/foundation/service-stateful-runtime.js +44 -103
- package/dist/runtime/foundation/service-stateful-wire-codec.d.ts +0 -5
- package/dist/runtime/foundation/service-topology-registry.d.ts +12 -2
- package/dist/runtime/foundation/service-topology-registry.js +61 -27
- package/dist/runtime/foundation/service-wire-m6a-codec.d.ts +3 -3
- package/dist/runtime/foundation/service-wire-m6a-codec.js +36 -38
- package/dist/runtime/handlers/handler-instance-scope.d.ts +8 -0
- package/dist/runtime/handlers/handler-instance-scope.js +54 -11
- package/dist/runtime/host/actor-runtime-options-factory.js +2 -2
- package/dist/runtime/host/application-job-queue.d.ts +19 -7
- package/dist/runtime/host/application-job-queue.js +150 -42
- package/dist/runtime/host/entry-actor-runtime.d.ts +1 -0
- package/dist/runtime/host/entry-actor-runtime.js +3 -0
- package/dist/runtime/host/index.d.ts +7 -1
- package/dist/runtime/host/index.js +142 -118
- package/dist/runtime/host/remote-bound-session-relay.js +2 -18
- package/dist/runtime/host/route-mesh-runtime.js +1 -1
- package/dist/runtime/host/service-relocation-control.d.ts +1 -0
- package/dist/runtime/host/service-relocation-control.js +10 -4
- package/dist/runtime/host/service-relocation-host-runtime.d.ts +6 -8
- package/dist/runtime/host/service-relocation-host-runtime.js +213 -241
- package/dist/runtime/host/spot-address-transport.js +3 -2
- package/dist/runtime/host/spot-runtime-options-factory.js +1 -0
- package/dist/runtime/locations/actor-location-claims.d.ts +2 -2
- package/dist/runtime/locations/actor-location-claims.js +34 -19
- package/dist/runtime/locations/lifecycle.d.ts +1 -2
- package/dist/runtime/locations/lifecycle.js +2 -5
- package/dist/runtime/locations/runtime.d.ts +1 -1
- package/dist/runtime/locations/runtime.js +24 -23
- package/dist/runtime/messaging/framework-json-v1.d.ts +4 -6
- package/dist/runtime/messaging/framework-json-v1.js +38 -294
- package/dist/runtime/messaging/packet-name.d.ts +1 -1
- package/dist/runtime/messaging/packet-name.js +8 -24
- package/dist/runtime/messaging/request-result.d.ts +2 -0
- package/dist/runtime/messaging/request-result.js +54 -0
- package/dist/runtime/messaging/submission-result.d.ts +1 -0
- package/dist/runtime/messaging/submission-result.js +5 -2
- package/dist/runtime/protocol/service_wire_codec.generated.d.ts +15 -0
- package/dist/runtime/protocol/service_wire_codec.generated.js +144 -0
- package/dist/runtime/protocol/service_wire_pilot_codec.generated.d.ts +9 -0
- package/dist/runtime/protocol/service_wire_pilot_codec.generated.js +14 -1
- package/dist/runtime/spots/formal-remote-actor-admission-registry.d.ts +7 -2
- package/dist/runtime/spots/formal-remote-actor-admission-registry.js +33 -19
- package/dist/runtime/spots/index.d.ts +3 -0
- package/dist/runtime/spots/index.js +9 -2
- package/dist/runtime/spots/spot-activation.d.ts +1 -0
- package/dist/runtime/spots/spot-activation.js +17 -8
- package/dist/runtime/spots/spot-entry-activation.js +6 -2
- package/dist/runtime/spots/spot-handler-registry.d.ts +3 -1
- package/dist/runtime/spots/spot-handler-registry.js +18 -8
- package/dist/runtime/spots/spot-node-autoconnect.js +4 -3
- package/dist/runtime/spots/spot-outbound.d.ts +3 -0
- package/dist/runtime/spots/spot-outbound.js +24 -15
- package/dist/runtime/spots/spot-routed-spot-packet-dispatch.d.ts +1 -0
- package/dist/runtime/spots/spot-routed-spot-packet-dispatch.js +1 -1
- package/dist/runtime/spots/spot-runtime-ports.d.ts +1 -0
- package/dist/runtime/spots/spot-subscription-dispatch.js +0 -3
- package/dist/runtime/spots/spot-timer.js +1 -0
- package/dist/runtime/streams/stream-session-runtime.d.ts +1 -1
- package/dist/runtime/streams/stream-session-runtime.js +13 -27
- package/package.json +2 -2
- package/src/contracts/Actors/ZLinkActorClient.ts +2 -1
- package/src/contracts/Channels/Calls.ts +2 -1
- package/src/contracts/Common/ZLinkMessageMetadata.ts +13 -8
- package/src/contracts/Handlers/Attributes.ts +14 -21
- package/src/contracts/Handlers/JsonContract.ts +8 -216
- package/src/contracts/Spots/Contracts.ts +2 -1
- package/src/nest-integration.ts +1 -0
- package/src/runtime/actors/actor-client.ts +40 -16
- package/src/runtime/actors/actor-handoff.ts +9 -4
- package/src/runtime/actors/actor-join-relocation.ts +1 -0
- package/src/runtime/actors/actor-local-native-join.ts +17 -26
- package/src/runtime/actors/actor-remote-wire.ts +17 -0
- package/src/runtime/actors/actor-routed-join-transport.ts +14 -4
- package/src/runtime/actors/actor-routed-json-request.ts +10 -2
- package/src/runtime/actors/index.ts +19 -5
- package/src/runtime/actors/spot-actor-dispatch.ts +4 -2
- package/src/runtime/admission.ts +18 -5
- package/src/runtime/application-jobs/application-ingress-record-owner.ts +41 -25
- package/src/runtime/application-jobs/application-job-queue-scope.ts +51 -22
- package/src/runtime/application-jobs/contracts.ts +14 -1
- package/src/runtime/backend/contracts/index.ts +53 -14
- package/src/runtime/backend/mesh-completion-table.ts +156 -57
- package/src/runtime/backend/mesh-dispatch-pump.ts +40 -10
- package/src/runtime/backend/node/node-backend-adapter-support.ts +17 -8
- package/src/runtime/backend/node/node-dealer-channel-client-transport.ts +12 -2
- package/src/runtime/backend/node/node-raw-binding-port.ts +57 -30
- package/src/runtime/backend/node/node-raw-mesh-backend.ts +128 -65
- package/src/runtime/backend/node/node-socket-backend-adapter.ts +21 -6
- package/src/runtime/backend/raw-binding-port.ts +7 -2
- package/src/runtime/backend/runtime-message.ts +6 -0
- package/src/runtime/backend/runtime-values.ts +1 -0
- package/src/runtime/channels/channel-clients.ts +90 -41
- package/src/runtime/channels/channel-dispatch-pipeline.ts +69 -34
- package/src/runtime/channels/channel-dispatch-services.ts +69 -1
- package/src/runtime/channels/channel-dispatchers.ts +29 -27
- package/src/runtime/channels/channel-envelope-inspection.ts +2 -16
- package/src/runtime/channels/channel-envelope.ts +133 -8
- package/src/runtime/channels/channel-outbound-operations.ts +22 -8
- package/src/runtime/channels/channel-runtime-manager.ts +29 -12
- package/src/runtime/channels/channel-transports.ts +128 -60
- package/src/runtime/channels/local-spot-route-transport.ts +3 -1
- package/src/runtime/channels/router-socket-spot-route-transport.ts +13 -4
- package/src/runtime/channels/source-spot-router.ts +8 -4
- package/src/runtime/channels/spot-node-route-transport.ts +8 -4
- package/src/runtime/channels/spot-route-bridge-transport.ts +6 -4
- package/src/runtime/channels/spot-route-dispatch-strategy.ts +47 -18
- package/src/runtime/execution/serial-execution-queue.ts +2 -0
- package/src/runtime/foundation/actor-join-recovery-codec.ts +2 -2
- package/src/runtime/foundation/durable-service-request.ts +137 -0
- package/src/runtime/foundation/operation-identity.ts +5 -1
- package/src/runtime/foundation/raw-service-mesh-runtime.ts +484 -293
- package/src/runtime/foundation/service-relocation-object-owner.ts +2 -0
- package/src/runtime/foundation/service-relocation-runtime.ts +18 -1
- package/src/runtime/foundation/service-runtime-contracts.ts +7 -1
- package/src/runtime/foundation/service-stateful-runtime.ts +67 -125
- package/src/runtime/foundation/service-stateful-wire-codec.ts +0 -5
- package/src/runtime/foundation/service-topology-registry.ts +91 -36
- package/src/runtime/foundation/service-wire-m6a-codec.ts +57 -38
- package/src/runtime/handlers/handler-instance-scope.ts +67 -16
- package/src/runtime/host/actor-runtime-options-factory.ts +13 -2
- package/src/runtime/host/application-job-queue.ts +175 -41
- package/src/runtime/host/entry-actor-runtime.ts +4 -0
- package/src/runtime/host/index.ts +201 -156
- package/src/runtime/host/remote-bound-session-relay.ts +2 -23
- package/src/runtime/host/route-mesh-runtime.ts +1 -1
- package/src/runtime/host/service-relocation-control.ts +11 -5
- package/src/runtime/host/service-relocation-host-runtime.ts +315 -291
- package/src/runtime/host/spot-address-transport.ts +4 -2
- package/src/runtime/host/spot-runtime-options-factory.ts +2 -0
- package/src/runtime/locations/actor-location-claims.ts +52 -30
- package/src/runtime/locations/lifecycle.ts +8 -26
- package/src/runtime/locations/runtime.ts +28 -24
- package/src/runtime/messaging/framework-json-v1.ts +5 -325
- package/src/runtime/messaging/packet-name.ts +5 -25
- package/src/runtime/messaging/request-result.ts +58 -0
- package/src/runtime/messaging/submission-result.ts +5 -1
- package/src/runtime/protocol/service_wire_codec.generated.ts +131 -1
- package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +4 -4
- package/src/runtime/spots/formal-remote-actor-admission-registry.ts +43 -23
- package/src/runtime/spots/index.ts +14 -2
- package/src/runtime/spots/spot-activation.ts +28 -10
- package/src/runtime/spots/spot-entry-activation.ts +9 -2
- package/src/runtime/spots/spot-handler-registry.ts +41 -8
- package/src/runtime/spots/spot-node-autoconnect.ts +6 -2
- package/src/runtime/spots/spot-outbound.ts +36 -16
- package/src/runtime/spots/spot-routed-spot-packet-dispatch.ts +2 -1
- package/src/runtime/spots/spot-runtime-ports.ts +1 -0
- package/src/runtime/spots/spot-subscription-dispatch.ts +0 -3
- package/src/runtime/spots/spot-timer.ts +5 -1
- package/src/runtime/streams/stream-session-runtime.ts +12 -29
|
@@ -5,7 +5,7 @@ import type {
|
|
|
5
5
|
ReceiveKindData,
|
|
6
6
|
ReceiveRecord
|
|
7
7
|
} from '../foundation/service-runtime-contracts';
|
|
8
|
-
import { operationIdentityKey } from '../foundation/operation-identity';
|
|
8
|
+
import { operationIdentityKey, validateOperationIdentity } from '../foundation/operation-identity';
|
|
9
9
|
|
|
10
10
|
export interface ZLinkMeshCompletionDiagnostic {
|
|
11
11
|
readonly kind: 'unknownOrLate';
|
|
@@ -21,10 +21,23 @@ export interface ZLinkMeshCompletion {
|
|
|
21
21
|
readonly parts: Message[];
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
24
|
+
const COMPLETION_SLOT_BLOCK_SIZE = 64;
|
|
25
|
+
const COMPLETION_HASH_BUCKETS_PER_SLOT = 2;
|
|
26
|
+
const COMPLETION_HASH_WORD_SCALE = 0x1_0000;
|
|
27
|
+
const COMPLETION_HASH_MULTIPLIER = 0x9e37_79b1;
|
|
28
|
+
const COMPLETION_ABORT_OPTIONS = Object.freeze({ once: true });
|
|
29
|
+
|
|
30
|
+
class CompletionSlot {
|
|
31
|
+
generation = 0;
|
|
32
|
+
next = -1;
|
|
33
|
+
high?: bigint;
|
|
34
|
+
low?: bigint;
|
|
35
|
+
hashNext = -1;
|
|
36
|
+
resolve?: (completion: ZLinkMeshCompletion) => void;
|
|
37
|
+
reject?: (error: unknown) => void;
|
|
38
|
+
signal?: AbortSignal;
|
|
39
|
+
|
|
40
|
+
constructor(readonly abort: () => void) {}
|
|
28
41
|
}
|
|
29
42
|
|
|
30
43
|
export type ZLinkMeshCompletionTerminal = Pick<ReceiveRecord, 'operationId' | 'terminalResult'>;
|
|
@@ -34,12 +47,97 @@ export type ZLinkMeshCompletionHandler = (
|
|
|
34
47
|
) => void;
|
|
35
48
|
|
|
36
49
|
export class ZLinkMeshCompletionTable {
|
|
37
|
-
private
|
|
50
|
+
private buckets = new Int32Array(0);
|
|
51
|
+
private readonly slots: CompletionSlot[] = [];
|
|
52
|
+
private free = -1;
|
|
53
|
+
private activeCount = 0;
|
|
38
54
|
private disposed = false;
|
|
39
55
|
|
|
40
|
-
constructor(
|
|
41
|
-
|
|
42
|
-
|
|
56
|
+
constructor(private readonly onDiagnostic?: (diagnostic: ZLinkMeshCompletionDiagnostic) => void) {
|
|
57
|
+
this.prepareSlots();
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
private prepareSlots(): void {
|
|
61
|
+
const start = this.slots.length;
|
|
62
|
+
for (let index = start; index < start + COMPLETION_SLOT_BLOCK_SIZE; index++) {
|
|
63
|
+
const slot = new CompletionSlot(() => {
|
|
64
|
+
const reject = slot.reject;
|
|
65
|
+
const signal = slot.signal;
|
|
66
|
+
if (reject === undefined) return;
|
|
67
|
+
this.releaseSlot(index);
|
|
68
|
+
reject(signal?.reason ?? new DOMException('The operation was aborted.', 'AbortError'));
|
|
69
|
+
});
|
|
70
|
+
slot.next = this.free;
|
|
71
|
+
this.slots.push(slot);
|
|
72
|
+
this.free = index;
|
|
73
|
+
}
|
|
74
|
+
const minimumBuckets = this.slots.length * COMPLETION_HASH_BUCKETS_PER_SLOT;
|
|
75
|
+
this.buckets = new Int32Array(2 ** Math.ceil(Math.log2(minimumBuckets))).fill(-1);
|
|
76
|
+
for (let index = 0; index < this.slots.length; index++) {
|
|
77
|
+
const slot = this.slots[index]!;
|
|
78
|
+
if (slot.high === undefined) continue;
|
|
79
|
+
this.indexSlot(index);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private bucket(high: bigint, low: bigint): number {
|
|
84
|
+
const highWord = Number(high);
|
|
85
|
+
const lowWord = Number(low);
|
|
86
|
+
// Bucket selection may collide; the stored 128-bit identity is compared exactly.
|
|
87
|
+
const hash =
|
|
88
|
+
Math.imul(
|
|
89
|
+
highWord ^ Math.trunc(highWord / COMPLETION_HASH_WORD_SCALE),
|
|
90
|
+
COMPLETION_HASH_MULTIPLIER
|
|
91
|
+
) ^
|
|
92
|
+
lowWord ^
|
|
93
|
+
Math.trunc(lowWord / COMPLETION_HASH_WORD_SCALE);
|
|
94
|
+
return hash & (this.buckets.length - 1);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
private indexSlot(index: number): void {
|
|
98
|
+
const slot = this.slots[index]!;
|
|
99
|
+
const bucket = this.bucket(slot.high!, slot.low!);
|
|
100
|
+
slot.hashNext = this.buckets[bucket]!;
|
|
101
|
+
this.buckets[bucket] = index;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private findSlot(operationId: MeshOperationId): number {
|
|
105
|
+
validateOperationIdentity(operationId);
|
|
106
|
+
for (
|
|
107
|
+
let index = this.buckets[this.bucket(operationId.high, operationId.low)]!;
|
|
108
|
+
index !== -1;
|
|
109
|
+
index = this.slots[index]!.hashNext
|
|
110
|
+
) {
|
|
111
|
+
const slot = this.slots[index]!;
|
|
112
|
+
if (slot.high === operationId.high && slot.low === operationId.low) return index;
|
|
113
|
+
}
|
|
114
|
+
return -1;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
private releaseSlot(index: number): void {
|
|
118
|
+
const slot = this.slots[index]!;
|
|
119
|
+
if (slot.high !== undefined) {
|
|
120
|
+
const bucket = this.bucket(slot.high, slot.low!);
|
|
121
|
+
let previous = -1;
|
|
122
|
+
let current = this.buckets[bucket]!;
|
|
123
|
+
while (current !== index) {
|
|
124
|
+
previous = current;
|
|
125
|
+
current = this.slots[current]!.hashNext;
|
|
126
|
+
}
|
|
127
|
+
if (previous === -1) this.buckets[bucket] = slot.hashNext;
|
|
128
|
+
else this.slots[previous]!.hashNext = slot.hashNext;
|
|
129
|
+
}
|
|
130
|
+
slot.signal?.removeEventListener('abort', slot.abort);
|
|
131
|
+
slot.high = undefined;
|
|
132
|
+
slot.low = undefined;
|
|
133
|
+
slot.hashNext = -1;
|
|
134
|
+
slot.signal = undefined;
|
|
135
|
+
slot.resolve = undefined;
|
|
136
|
+
slot.reject = undefined;
|
|
137
|
+
slot.next = this.free;
|
|
138
|
+
this.free = index;
|
|
139
|
+
this.activeCount--;
|
|
140
|
+
}
|
|
43
141
|
|
|
44
142
|
/**
|
|
45
143
|
* Reserves the dispatcher slot before transport submission. The backend
|
|
@@ -56,37 +154,30 @@ export class ZLinkMeshCompletionTable {
|
|
|
56
154
|
);
|
|
57
155
|
}
|
|
58
156
|
return new Promise((resolve, reject) => {
|
|
59
|
-
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
signal?.addEventListener('abort', abort, { once: true });
|
|
69
|
-
const entry: PendingCompletion = {
|
|
70
|
-
resolve,
|
|
71
|
-
reject,
|
|
72
|
-
removeAbort:
|
|
73
|
-
signal === undefined ? undefined : () => signal.removeEventListener('abort', abort)
|
|
74
|
-
};
|
|
75
|
-
this.pending.set(key, entry);
|
|
157
|
+
if (this.free === -1) this.prepareSlots();
|
|
158
|
+
const index = this.free;
|
|
159
|
+
const slot = this.slots[index]!;
|
|
160
|
+
this.free = slot.next;
|
|
161
|
+
const generation = ++slot.generation;
|
|
162
|
+
slot.resolve = resolve;
|
|
163
|
+
slot.reject = reject;
|
|
164
|
+
slot.signal = signal;
|
|
165
|
+
this.activeCount++;
|
|
76
166
|
try {
|
|
167
|
+
signal?.addEventListener('abort', slot.abort, COMPLETION_ABORT_OPTIONS);
|
|
77
168
|
const operationId = operation();
|
|
78
|
-
//
|
|
79
|
-
if (
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
169
|
+
// A reentrant abort may release and reuse this slot during submission.
|
|
170
|
+
if (slot.generation !== generation || slot.resolve !== resolve) return;
|
|
171
|
+
if (this.findSlot(operationId) !== -1) {
|
|
172
|
+
throw new Error(
|
|
173
|
+
`Mesh operation '${operationIdentityKey(operationId)}' is already pending.`
|
|
174
|
+
);
|
|
83
175
|
}
|
|
84
|
-
|
|
176
|
+
slot.high = operationId.high;
|
|
177
|
+
slot.low = operationId.low;
|
|
178
|
+
this.indexSlot(index);
|
|
85
179
|
} catch (error) {
|
|
86
|
-
|
|
87
|
-
// the original waiter.
|
|
88
|
-
if (this.pending.get(key) === entry) this.pending.delete(key);
|
|
89
|
-
entry.removeAbort?.();
|
|
180
|
+
if (slot.generation === generation && slot.resolve === resolve) this.releaseSlot(index);
|
|
90
181
|
reject(error);
|
|
91
182
|
}
|
|
92
183
|
});
|
|
@@ -99,9 +190,8 @@ export class ZLinkMeshCompletionTable {
|
|
|
99
190
|
complete(record: ReceiveRecord): void;
|
|
100
191
|
complete(record: ZLinkMeshCompletionTerminal, materialize: () => ReceiveRecord): void;
|
|
101
192
|
complete(record: ZLinkMeshCompletionTerminal, materialize?: () => ReceiveRecord): void {
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
if (pending === undefined) {
|
|
193
|
+
const index = this.findSlot(record.operationId);
|
|
194
|
+
if (index === -1) {
|
|
105
195
|
this.onDiagnostic?.({
|
|
106
196
|
kind: 'unknownOrLate',
|
|
107
197
|
operationId: Object.freeze({ ...record.operationId }),
|
|
@@ -109,14 +199,16 @@ export class ZLinkMeshCompletionTable {
|
|
|
109
199
|
});
|
|
110
200
|
return;
|
|
111
201
|
}
|
|
112
|
-
this.
|
|
113
|
-
|
|
202
|
+
const slot = this.slots[index]!;
|
|
203
|
+
const resolve = slot.resolve!;
|
|
204
|
+
const reject = slot.reject!;
|
|
205
|
+
this.releaseSlot(index);
|
|
114
206
|
try {
|
|
115
|
-
|
|
207
|
+
resolve(
|
|
116
208
|
retainCompletion(materialize === undefined ? (record as ReceiveRecord) : materialize())
|
|
117
209
|
);
|
|
118
210
|
} catch (error) {
|
|
119
|
-
|
|
211
|
+
reject(error);
|
|
120
212
|
}
|
|
121
213
|
}
|
|
122
214
|
|
|
@@ -125,36 +217,43 @@ export class ZLinkMeshCompletionTable {
|
|
|
125
217
|
return;
|
|
126
218
|
}
|
|
127
219
|
this.disposed = true;
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
for (const entry of pending) {
|
|
134
|
-
entry.reject(reason);
|
|
220
|
+
for (let index = 0; index < this.slots.length; index++) {
|
|
221
|
+
const reject = this.slots[index]!.reject;
|
|
222
|
+
if (reject === undefined) continue;
|
|
223
|
+
this.releaseSlot(index);
|
|
224
|
+
reject(reason);
|
|
135
225
|
}
|
|
136
226
|
}
|
|
137
227
|
|
|
138
228
|
get pendingCount(): number {
|
|
139
|
-
return this.
|
|
229
|
+
return this.activeCount;
|
|
140
230
|
}
|
|
141
231
|
}
|
|
142
232
|
|
|
143
233
|
function retainCompletion(record: ReceiveRecord): ZLinkMeshCompletion {
|
|
234
|
+
const parts = retainCompletionParts(record.parts);
|
|
235
|
+
// The retention pass verifies every part is already a managed runtime message.
|
|
236
|
+
if (parts === record.parts) return record as unknown as ZLinkMeshCompletion;
|
|
144
237
|
return {
|
|
145
238
|
terminalResult: record.terminalResult,
|
|
146
239
|
failureErrno: record.failureErrno,
|
|
147
240
|
operationKind: record.operationKind,
|
|
148
241
|
kindData: record.kindData,
|
|
149
|
-
parts
|
|
242
|
+
parts
|
|
150
243
|
};
|
|
151
244
|
}
|
|
152
245
|
|
|
153
|
-
function
|
|
154
|
-
//
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
246
|
+
function retainCompletionParts(parts: readonly ZLinkMessage[]): Message[] {
|
|
247
|
+
// Reuse managed messages and wrap binding payloads in the runtime representation.
|
|
248
|
+
let retained: Message[] | undefined;
|
|
249
|
+
for (let index = 0; index < parts.length; index++) {
|
|
250
|
+
const part = parts[index]!;
|
|
251
|
+
if (!(part instanceof Message)) {
|
|
252
|
+
retained ??= parts.slice() as Message[];
|
|
253
|
+
retained[index] = Message.fromOwned(Message.retainPayload(part));
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return retained ?? (parts as Message[]);
|
|
158
257
|
}
|
|
159
258
|
|
|
160
259
|
export function closeMeshCompletion(completion: ZLinkMeshCompletion): void {
|
|
@@ -58,6 +58,7 @@ export interface ZLinkMeshDispatchFailureContext {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
export class ZLinkMeshDispatchPump {
|
|
61
|
+
private readonly dispatchOwnedRecord = this.dispatchRecord.bind(this);
|
|
61
62
|
private pendingDomains: number = ReadyDomain.None;
|
|
62
63
|
private infrastructureScheduled = false;
|
|
63
64
|
private disposed = false;
|
|
@@ -180,6 +181,36 @@ export class ZLinkMeshDispatchPump {
|
|
|
180
181
|
return new Promise((resolve) => this.idleApplicationWorkers.add(resolve));
|
|
181
182
|
}
|
|
182
183
|
|
|
184
|
+
private dispatchRecord(owner: ReadyRecord, record: ReceiveRecord): void | Promise<void> {
|
|
185
|
+
let result: void | Promise<void>;
|
|
186
|
+
try {
|
|
187
|
+
result = this.options.dispatch(owner, record);
|
|
188
|
+
} catch (error) {
|
|
189
|
+
this.reportDispatchError(error, meshDispatchFailureContext(record));
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
return result === undefined
|
|
193
|
+
? this.finishRecord(record)
|
|
194
|
+
: Promise.resolve(result).then(
|
|
195
|
+
() => this.finishRecord(record),
|
|
196
|
+
(error) => this.reportDispatchError(error, meshDispatchFailureContext(record))
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
private finishRecord(record: ReceiveRecord): void | Promise<void> {
|
|
201
|
+
let result: void | Promise<void>;
|
|
202
|
+
try {
|
|
203
|
+
result = record.onTerminalCompletion?.();
|
|
204
|
+
} catch (error) {
|
|
205
|
+
this.reportDispatchError(error, meshDispatchFailureContext(record));
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
if (result !== undefined)
|
|
209
|
+
return Promise.resolve(result).catch((error) =>
|
|
210
|
+
this.reportDispatchError(error, meshDispatchFailureContext(record))
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
|
|
183
214
|
private reportDispatchError(error: unknown, context?: ZLinkMeshDispatchFailureContext): void {
|
|
184
215
|
this.options.reportError?.(error, context);
|
|
185
216
|
}
|
|
@@ -304,16 +335,9 @@ export class ZLinkMeshDispatchPump {
|
|
|
304
335
|
);
|
|
305
336
|
}
|
|
306
337
|
this.recordsSinceYield += 1;
|
|
307
|
-
const dispatch = async () => {
|
|
308
|
-
try {
|
|
309
|
-
await this.options.dispatch(owner, record);
|
|
310
|
-
await record.onTerminalCompletion?.();
|
|
311
|
-
} catch (error) {
|
|
312
|
-
this.reportDispatchError(error, meshDispatchFailureContext(record));
|
|
313
|
-
}
|
|
314
|
-
};
|
|
315
338
|
if (permit === undefined) {
|
|
316
|
-
|
|
339
|
+
const dispatched = this.dispatchRecord(owner, record);
|
|
340
|
+
if (dispatched !== undefined) await dispatched;
|
|
317
341
|
} else {
|
|
318
342
|
if (
|
|
319
343
|
domain === ReadyDomain.Application &&
|
|
@@ -324,7 +348,13 @@ export class ZLinkMeshDispatchPump {
|
|
|
324
348
|
// and detached handler handoff. Only unused permits remain
|
|
325
349
|
// owned by the receive attempt's finally block.
|
|
326
350
|
if (permit === claimPermit) claimPermit = undefined;
|
|
327
|
-
|
|
351
|
+
const dispatched = runWithApplicationJobPermit(
|
|
352
|
+
permit,
|
|
353
|
+
this.dispatchOwnedRecord,
|
|
354
|
+
owner,
|
|
355
|
+
record
|
|
356
|
+
);
|
|
357
|
+
if (dispatched !== undefined) await dispatched;
|
|
328
358
|
}
|
|
329
359
|
}
|
|
330
360
|
} finally {
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
import { loadBinding } from '../node-backend-adapter';
|
|
8
8
|
import { SubmitResult, ZLinkBackendResultError } from '../runtime-values';
|
|
9
9
|
const nativeErrnoValues = osConstants.errno;
|
|
10
|
+
const completedSend: Promise<void> = Promise.resolve();
|
|
10
11
|
|
|
11
12
|
export type ZLinkBindingModule = typeof import('@zlink-systems/zlink');
|
|
12
13
|
export const zlink = loadBinding() as ZLinkBindingModule;
|
|
@@ -119,12 +120,16 @@ export function submitBindingReply(operation: ZLinkBindingReplyOperation, payloa
|
|
|
119
120
|
}
|
|
120
121
|
}
|
|
121
122
|
|
|
122
|
-
export
|
|
123
|
+
export function submitBindingAsyncSend(
|
|
123
124
|
operation: ZLinkBindingAsyncSendOperation,
|
|
124
125
|
payload: unknown
|
|
125
126
|
): Promise<void> {
|
|
126
|
-
|
|
127
|
-
|
|
127
|
+
try {
|
|
128
|
+
const submission = submitBindingSend(operation, payload);
|
|
129
|
+
return submission.result === SubmitResult.Backpressured ? submission.admitted : completedSend;
|
|
130
|
+
} catch (error) {
|
|
131
|
+
return Promise.reject(error);
|
|
132
|
+
}
|
|
128
133
|
}
|
|
129
134
|
|
|
130
135
|
export function submitBindingSend(
|
|
@@ -152,7 +157,8 @@ export function submitBindingSend(
|
|
|
152
157
|
})
|
|
153
158
|
};
|
|
154
159
|
}
|
|
155
|
-
|
|
160
|
+
// Binding SendSubmission is the closed OK | BACKPRESSURED snapshot.
|
|
161
|
+
return submission as import('../raw-binding-port').ZLinkRawSendSubmission;
|
|
156
162
|
}
|
|
157
163
|
|
|
158
164
|
export function submitBindingSyncSend(
|
|
@@ -177,7 +183,8 @@ export async function submitBindingRequest(
|
|
|
177
183
|
operation: ZLinkBindingRequestOperation,
|
|
178
184
|
payload: unknown,
|
|
179
185
|
timeoutMs: number | undefined,
|
|
180
|
-
recordReceived?: () => void
|
|
186
|
+
recordReceived?: () => void,
|
|
187
|
+
onAdmitted?: () => void
|
|
181
188
|
): Promise<readonly unknown[]> {
|
|
182
189
|
const deadlineMs = timeoutMs === undefined ? undefined : performance.now() + timeoutMs;
|
|
183
190
|
try {
|
|
@@ -195,7 +202,7 @@ export async function submitBindingRequest(
|
|
|
195
202
|
if (timeoutMs !== undefined) {
|
|
196
203
|
current = current.timeout(timeoutMs);
|
|
197
204
|
}
|
|
198
|
-
return await bindingRequestReply(current.submit(), deadlineMs, recordReceived);
|
|
205
|
+
return await bindingRequestReply(current.submit(), deadlineMs, recordReceived, onAdmitted);
|
|
199
206
|
} catch (error) {
|
|
200
207
|
throw translateBindingResultError(error);
|
|
201
208
|
}
|
|
@@ -204,13 +211,14 @@ export async function submitBindingRequest(
|
|
|
204
211
|
export async function bindingRequestReply(
|
|
205
212
|
submission: import('@zlink-systems/zlink').RequestSubmission,
|
|
206
213
|
deadlineMs: number | undefined,
|
|
207
|
-
recordReceived?: () => void
|
|
214
|
+
recordReceived?: () => void,
|
|
215
|
+
onAdmitted?: () => void
|
|
208
216
|
): Promise<import('@zlink-systems/zlink').Message[]> {
|
|
209
217
|
const reply = submission.reply;
|
|
210
218
|
if (submission.result === SubmitResult.Backpressured) {
|
|
211
219
|
try {
|
|
212
220
|
const [, replies] = await waitRequestReply(
|
|
213
|
-
Promise.all([submission.admitted, reply]),
|
|
221
|
+
Promise.all([submission.admitted.then(() => onAdmitted?.()), reply]),
|
|
214
222
|
'Request',
|
|
215
223
|
deadlineMs
|
|
216
224
|
);
|
|
@@ -227,6 +235,7 @@ export async function bindingRequestReply(
|
|
|
227
235
|
throw error;
|
|
228
236
|
}
|
|
229
237
|
}
|
|
238
|
+
onAdmitted?.();
|
|
230
239
|
const replies = await reply;
|
|
231
240
|
recordReceived?.();
|
|
232
241
|
return replies;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { bindingRequestReply } from './node-backend-adapter-support';
|
|
1
2
|
import type { DealerSocket, Message, PubSocket } from '@zlink-systems/zlink';
|
|
2
3
|
import { ZLinkConfigurationException } from '../../configuration';
|
|
3
4
|
import { ZLinkSubmitStatus, type ZLinkSubmitResult } from '../../messaging/submission-result';
|
|
@@ -56,7 +57,8 @@ export class ZLinkDealerChannelClientTransport implements ZLinkChannelClientTran
|
|
|
56
57
|
request: Message,
|
|
57
58
|
timeoutMs: number | undefined,
|
|
58
59
|
signal?: AbortSignal,
|
|
59
|
-
metadata: ReadonlyMap<string, string> = EMPTY_METADATA
|
|
60
|
+
metadata: ReadonlyMap<string, string> = EMPTY_METADATA,
|
|
61
|
+
onAdmitted?: () => void
|
|
60
62
|
): Promise<TReply> {
|
|
61
63
|
throwIfAborted(signal);
|
|
62
64
|
const operation = runWithOutboundFlow(true, () =>
|
|
@@ -78,7 +80,15 @@ export class ZLinkDealerChannelClientTransport implements ZLinkChannelClientTran
|
|
|
78
80
|
);
|
|
79
81
|
if (timeoutMs !== undefined) operation.timeout(timeoutMs);
|
|
80
82
|
const reply = await submitRequestOperation(
|
|
81
|
-
{
|
|
83
|
+
{
|
|
84
|
+
submit: () =>
|
|
85
|
+
bindingRequestReply(
|
|
86
|
+
operation.submit(),
|
|
87
|
+
timeoutMs === undefined ? undefined : performance.now() + timeoutMs,
|
|
88
|
+
undefined,
|
|
89
|
+
onAdmitted
|
|
90
|
+
)
|
|
91
|
+
},
|
|
82
92
|
'channel request'
|
|
83
93
|
);
|
|
84
94
|
try {
|
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
} from './node-backend-adapter-support';
|
|
28
28
|
import { isEndpointCloseIgnorableError } from './node-socket-backend-adapter';
|
|
29
29
|
import { ZLinkNodeEventLoopPoller } from './node-event-loop-poller';
|
|
30
|
+
import { ZLinkBufferMessage } from '../runtime-message';
|
|
30
31
|
import type {
|
|
31
32
|
ZLinkRawBindingPort,
|
|
32
33
|
ZLinkRawDealerPort,
|
|
@@ -226,6 +227,42 @@ abstract class NodeRawSocketPort<TSocket extends Socket> implements ZLinkRawSock
|
|
|
226
227
|
|
|
227
228
|
class NodeRawRouterPort extends NodeRawSocketPort<RouterSocket> implements ZLinkRawRouterPort {
|
|
228
229
|
private nextIncomingRequestSequence = 1n;
|
|
230
|
+
private readonly routingIds = new Map<string, BindingRoutingId>();
|
|
231
|
+
private readonly nextRequestSequence = () => {
|
|
232
|
+
const current = this.nextIncomingRequestSequence;
|
|
233
|
+
this.nextIncomingRequestSequence =
|
|
234
|
+
current === BigInt(Number.MAX_SAFE_INTEGER) ? 1n : current + 1n;
|
|
235
|
+
return current;
|
|
236
|
+
};
|
|
237
|
+
private readonly replyParts = (
|
|
238
|
+
targetRid: string | Uint8Array,
|
|
239
|
+
replyToken: unknown,
|
|
240
|
+
parts: readonly Uint8Array[]
|
|
241
|
+
) => {
|
|
242
|
+
appendReplyParts(
|
|
243
|
+
this.socket.reply(
|
|
244
|
+
this.preparedRoutingId(targetRid),
|
|
245
|
+
replyToken as Parameters<RouterSocket['reply']>[1]
|
|
246
|
+
),
|
|
247
|
+
parts
|
|
248
|
+
).submit();
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
private preparedRoutingId(routingId: string | Uint8Array): BindingRoutingId {
|
|
252
|
+
if (typeof routingId !== 'string') return bindingRoutingId(routingId);
|
|
253
|
+
let prepared = this.routingIds.get(routingId);
|
|
254
|
+
if (prepared === undefined)
|
|
255
|
+
this.routingIds.set(routingId, (prepared = bindingRoutingId(routingId)));
|
|
256
|
+
return prepared;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
override close(): void {
|
|
260
|
+
try {
|
|
261
|
+
super.close();
|
|
262
|
+
} finally {
|
|
263
|
+
this.routingIds.clear();
|
|
264
|
+
}
|
|
265
|
+
}
|
|
229
266
|
|
|
230
267
|
setReceiveFlowState(state: 'running' | 'paused'): void {
|
|
231
268
|
this.requireOpen();
|
|
@@ -240,7 +277,7 @@ class NodeRawRouterPort extends NodeRawSocketPort<RouterSocket> implements ZLink
|
|
|
240
277
|
this.socket as RouterSocket & {
|
|
241
278
|
disconnectRid(value: BindingRoutingId): void;
|
|
242
279
|
}
|
|
243
|
-
).disconnectRid(
|
|
280
|
+
).disconnectRid(this.preparedRoutingId(routingId));
|
|
244
281
|
}
|
|
245
282
|
|
|
246
283
|
constructor(socket: RouterSocket, receiveTimeoutMs?: number) {
|
|
@@ -260,46 +297,47 @@ class NodeRawRouterPort extends NodeRawSocketPort<RouterSocket> implements ZLink
|
|
|
260
297
|
|
|
261
298
|
setRoutingId(routingId: string): void {
|
|
262
299
|
this.requireOpen();
|
|
263
|
-
this.socket.setRoutingId(
|
|
300
|
+
this.socket.setRoutingId(this.preparedRoutingId(routingId));
|
|
264
301
|
}
|
|
265
302
|
|
|
266
303
|
connectToRoutingId(routingId: string, endpoint: string): void {
|
|
267
304
|
this.requireOpen();
|
|
268
|
-
this.socket.options.setConnectRoutingId(
|
|
305
|
+
this.socket.options.setConnectRoutingId(this.preparedRoutingId(routingId));
|
|
269
306
|
this.connect(endpoint);
|
|
270
307
|
}
|
|
271
308
|
|
|
272
309
|
send(targetRid: string, parts: readonly Uint8Array[]): Promise<void> {
|
|
273
310
|
this.requireOpen();
|
|
274
311
|
requireParts(parts);
|
|
275
|
-
return submitBindingAsyncSend(this.socket.send(
|
|
312
|
+
return submitBindingAsyncSend(this.socket.send(this.preparedRoutingId(targetRid)), parts);
|
|
276
313
|
}
|
|
277
314
|
|
|
278
315
|
submitSend(targetRid: string, parts: readonly Uint8Array[]) {
|
|
279
316
|
this.requireOpen();
|
|
280
317
|
requireParts(parts);
|
|
281
|
-
return submitBindingSend(this.socket.send(
|
|
318
|
+
return submitBindingSend(this.socket.send(this.preparedRoutingId(targetRid)), parts);
|
|
282
319
|
}
|
|
283
320
|
|
|
284
321
|
async request(
|
|
285
322
|
targetRid: string,
|
|
286
323
|
parts: readonly Uint8Array[],
|
|
287
324
|
timeoutMs: number,
|
|
288
|
-
recordReceived?: () => void
|
|
325
|
+
recordReceived?: () => void,
|
|
326
|
+
onAdmitted?: () => void
|
|
289
327
|
): Promise<readonly Buffer[]> {
|
|
290
328
|
this.requireOpen();
|
|
291
329
|
const deadlineMs = performance.now() + timeoutMs;
|
|
292
330
|
let submission: ReturnType<RequestSubmitOperation['submit']>;
|
|
293
331
|
try {
|
|
294
|
-
submission = appendRequestParts(this.socket.request(
|
|
332
|
+
submission = appendRequestParts(this.socket.request(this.preparedRoutingId(targetRid)), parts)
|
|
295
333
|
.timeout(timeoutMs)
|
|
296
334
|
.submit();
|
|
297
335
|
} catch (error) {
|
|
298
336
|
throw translateBindingResultError(error, 'submit');
|
|
299
337
|
}
|
|
300
338
|
try {
|
|
301
|
-
const replies = await bindingRequestReply(submission, deadlineMs, recordReceived);
|
|
302
|
-
return
|
|
339
|
+
const replies = await bindingRequestReply(submission, deadlineMs, recordReceived, onAdmitted);
|
|
340
|
+
return retainAndClose(replies);
|
|
303
341
|
} catch (error) {
|
|
304
342
|
throw translateBindingResultError(error, 'completion');
|
|
305
343
|
}
|
|
@@ -315,22 +353,7 @@ class NodeRawRouterPort extends NodeRawSocketPort<RouterSocket> implements ZLink
|
|
|
315
353
|
|
|
316
354
|
receive(dontWait = false): ZLinkRawReceivedRecord | undefined {
|
|
317
355
|
this.requireOpen();
|
|
318
|
-
return receiveRecord(
|
|
319
|
-
this.socket,
|
|
320
|
-
dontWait,
|
|
321
|
-
() => {
|
|
322
|
-
const current = this.nextIncomingRequestSequence;
|
|
323
|
-
this.nextIncomingRequestSequence =
|
|
324
|
-
current === BigInt(Number.MAX_SAFE_INTEGER) ? 1n : current + 1n;
|
|
325
|
-
return current;
|
|
326
|
-
},
|
|
327
|
-
(targetRid, replyToken, parts) => {
|
|
328
|
-
appendReplyParts(
|
|
329
|
-
this.socket.reply(bindingRoutingId(targetRid), replyToken),
|
|
330
|
-
parts
|
|
331
|
-
).submit();
|
|
332
|
-
}
|
|
333
|
-
);
|
|
356
|
+
return receiveRecord(this.socket, dontWait, this.nextRequestSequence, this.replyParts);
|
|
334
357
|
}
|
|
335
358
|
}
|
|
336
359
|
|
|
@@ -350,7 +373,11 @@ class NodeRawDealerPort extends NodeRawSocketPort<DealerSocket> implements ZLink
|
|
|
350
373
|
return submitBindingAsyncSend(this.socket.send(), parts);
|
|
351
374
|
}
|
|
352
375
|
|
|
353
|
-
async request(
|
|
376
|
+
async request(
|
|
377
|
+
parts: readonly Uint8Array[],
|
|
378
|
+
timeoutMs: number,
|
|
379
|
+
onAdmitted?: () => void
|
|
380
|
+
): Promise<readonly Buffer[]> {
|
|
354
381
|
this.requireOpen();
|
|
355
382
|
const deadlineMs = performance.now() + timeoutMs;
|
|
356
383
|
let submission: ReturnType<RequestSubmitOperation['submit']>;
|
|
@@ -360,8 +387,8 @@ class NodeRawDealerPort extends NodeRawSocketPort<DealerSocket> implements ZLink
|
|
|
360
387
|
throw translateBindingResultError(error, 'submit');
|
|
361
388
|
}
|
|
362
389
|
try {
|
|
363
|
-
const replies = await bindingRequestReply(submission, deadlineMs);
|
|
364
|
-
return
|
|
390
|
+
const replies = await bindingRequestReply(submission, deadlineMs, undefined, onAdmitted);
|
|
391
|
+
return retainAndClose(replies);
|
|
365
392
|
} catch (error) {
|
|
366
393
|
throw translateBindingResultError(error, 'completion');
|
|
367
394
|
}
|
|
@@ -493,9 +520,9 @@ function receiveRecord(
|
|
|
493
520
|
}
|
|
494
521
|
}
|
|
495
522
|
|
|
496
|
-
function
|
|
523
|
+
function retainAndClose(messages: readonly Message[]): readonly Buffer[] {
|
|
497
524
|
try {
|
|
498
|
-
return messages.map((message) =>
|
|
525
|
+
return messages.map((message) => ZLinkBufferMessage.retainPayload(message));
|
|
499
526
|
} finally {
|
|
500
527
|
for (const message of messages) message.close();
|
|
501
528
|
}
|