@zlink-systems/framework 0.22.0 → 0.23.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/.tsbuildinfo +1 -1
- package/dist/contracts/Dispatch/ZLinkDispatchOptions.d.ts +1 -0
- package/dist/contracts/Streams/IZLinkSession.d.ts +2 -1
- package/dist/runtime/actors/actor-context.js +4 -4
- package/dist/runtime/actors/actor-join-deferred-scope.d.ts +0 -1
- package/dist/runtime/actors/actor-join-deferred-scope.js +0 -18
- package/dist/runtime/actors/deferred-join-accepted-journal.js +2 -6
- package/dist/runtime/backend/contracts/index.d.ts +1 -0
- package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +3 -0
- package/dist/runtime/backend/node/node-raw-mesh-backend.js +21 -8
- package/dist/runtime/channels/channel-dispatch-pipeline.js +2 -2
- package/dist/runtime/channels/channel-transports.js +3 -9
- package/dist/runtime/channels/dispatch-error-reporter.d.ts +1 -0
- package/dist/runtime/channels/dispatch-error-reporter.js +6 -38
- package/dist/runtime/diagnostics/dispatch-error-details.d.ts +6 -0
- package/dist/runtime/diagnostics/dispatch-error-details.js +55 -0
- package/dist/runtime/diagnostics/flow-context.d.ts +2 -1
- package/dist/runtime/diagnostics/flow-context.js +2 -2
- package/dist/runtime/diagnostics/message-flow.js +11 -3
- package/dist/runtime/foundation/actor-join-recovery-codec.js +0 -4
- package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +4 -2
- package/dist/runtime/foundation/raw-service-mesh-runtime.js +34 -9
- package/dist/runtime/foundation/service-session-binding-ingress-port.d.ts +1 -0
- package/dist/runtime/foundation/service-stateful-runtime.d.ts +4 -0
- package/dist/runtime/foundation/service-stateful-runtime.js +46 -2
- package/dist/runtime/foundation/service-topology-registry.d.ts +1 -0
- package/dist/runtime/foundation/service-topology-registry.js +12 -4
- package/dist/runtime/host/index.js +1 -1
- package/dist/runtime/protocol/service_wire_pilot_codec.generated.js +20 -18
- package/dist/runtime/spots/index.js +1 -1
- package/dist/runtime/spots/spot-actor-packet-dispatch.d.ts +2 -1
- package/dist/runtime/spots/spot-actor-packet-dispatch.js +6 -1
- package/dist/runtime/spots/spot-actor-packet-drain.js +2 -0
- package/dist/runtime/spots/spot-node-runtime-manager.js +5 -1
- package/dist/runtime/spots/spot-route-packet-dispatch.js +1 -1
- package/dist/runtime/spots/spot-routed-bound-session-dispatch.js +1 -1
- package/dist/runtime/spots/spot-subscription-dispatch.js +1 -1
- package/dist/runtime/spots/spot-timer.js +1 -1
- package/dist/runtime/streams/actor-session-binding-registry.d.ts +21 -8
- package/dist/runtime/streams/actor-session-binding-registry.js +71 -42
- package/dist/runtime/streams/actor-session-binding-runtime-owner.d.ts +1 -0
- package/dist/runtime/streams/bound-actor-relay-sender.js +2 -1
- package/dist/runtime/streams/bound-session-response-target.js +8 -1
- package/dist/runtime/streams/bound-session-service.d.ts +1 -0
- package/dist/runtime/streams/bound-session-service.js +6 -3
- package/dist/runtime/streams/index.js +8 -1
- package/dist/runtime/streams/managed-stream.d.ts +3 -0
- package/dist/runtime/streams/managed-stream.js +20 -1
- package/dist/runtime/streams/protocol.d.ts +5 -1
- package/dist/runtime/streams/protocol.js +41 -4
- package/dist/runtime/streams/session-actor-coordinator.js +3 -4
- package/dist/runtime/streams/session-context.d.ts +9 -2
- package/dist/runtime/streams/session-context.js +20 -4
- package/dist/runtime/streams/session-local-actors.d.ts +3 -1
- package/dist/runtime/streams/session-local-actors.js +17 -2
- package/dist/runtime/streams/stream-frame-factory.d.ts +1 -1
- package/dist/runtime/streams/stream-frame-factory.js +3 -2
- package/dist/runtime/streams/stream-session-runtime.js +42 -12
- package/package.json +3 -3
- package/src/contracts/Dispatch/ZLinkDispatchOptions.ts +1 -0
- package/src/contracts/Streams/IZLinkSession.ts +2 -1
- package/src/runtime/actors/actor-context.ts +4 -4
- package/src/runtime/actors/actor-join-deferred-scope.ts +0 -32
- package/src/runtime/actors/deferred-join-accepted-journal.ts +2 -6
- package/src/runtime/backend/contracts/index.ts +4 -0
- package/src/runtime/backend/node/node-raw-mesh-backend.ts +39 -11
- package/src/runtime/channels/channel-dispatch-pipeline.ts +4 -2
- package/src/runtime/channels/channel-transports.ts +3 -9
- package/src/runtime/channels/dispatch-error-reporter.ts +7 -45
- package/src/runtime/diagnostics/dispatch-error-details.ts +62 -0
- package/src/runtime/diagnostics/flow-context.ts +6 -4
- package/src/runtime/diagnostics/message-flow.ts +12 -3
- package/src/runtime/foundation/actor-join-recovery-codec.ts +0 -4
- package/src/runtime/foundation/raw-service-mesh-runtime.ts +54 -13
- package/src/runtime/foundation/service-session-binding-ingress-port.ts +1 -0
- package/src/runtime/foundation/service-stateful-runtime.ts +64 -5
- package/src/runtime/foundation/service-topology-registry.ts +18 -5
- package/src/runtime/host/index.ts +1 -1
- package/src/runtime/protocol/service_wire_pilot_codec.generated.ts +18 -17
- package/src/runtime/spots/index.ts +2 -1
- package/src/runtime/spots/spot-actor-packet-dispatch.ts +20 -3
- package/src/runtime/spots/spot-actor-packet-drain.ts +2 -0
- package/src/runtime/spots/spot-node-runtime-manager.ts +5 -1
- package/src/runtime/spots/spot-route-packet-dispatch.ts +2 -1
- package/src/runtime/spots/spot-routed-bound-session-dispatch.ts +2 -1
- package/src/runtime/spots/spot-subscription-dispatch.ts +2 -1
- package/src/runtime/spots/spot-timer.ts +6 -1
- package/src/runtime/streams/actor-session-binding-registry.ts +150 -63
- package/src/runtime/streams/actor-session-binding-runtime-owner.ts +1 -0
- package/src/runtime/streams/bound-actor-relay-sender.ts +10 -2
- package/src/runtime/streams/bound-session-response-target.ts +10 -1
- package/src/runtime/streams/bound-session-service.ts +13 -3
- package/src/runtime/streams/index.ts +8 -1
- package/src/runtime/streams/managed-stream.ts +34 -12
- package/src/runtime/streams/protocol.ts +44 -5
- package/src/runtime/streams/session-actor-coordinator.ts +12 -4
- package/src/runtime/streams/session-context.ts +31 -4
- package/src/runtime/streams/session-local-actors.ts +19 -3
- package/src/runtime/streams/stream-frame-factory.ts +4 -2
- package/src/runtime/streams/stream-session-runtime.ts +58 -13
|
@@ -1,18 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ZLinkActorSessionBindingRegistry = void 0;
|
|
3
|
+
exports.ZLinkActorSessionBindingRegistry = exports.ZLinkActorSessionBindingTermination = void 0;
|
|
4
4
|
const framework_errors_internal_1 = require("../framework-errors-internal");
|
|
5
5
|
const abort_1 = require("../abort");
|
|
6
6
|
const node_async_hooks_1 = require("node:async_hooks");
|
|
7
7
|
const state_lane_1 = require("../execution/state-lane");
|
|
8
8
|
const routing_id_1 = require("../routing-id");
|
|
9
9
|
const detachedStateLaneResource = new node_async_hooks_1.AsyncResource('zlink:actor-session-binding-registry');
|
|
10
|
+
var ZLinkActorSessionBindingTermination;
|
|
11
|
+
(function (ZLinkActorSessionBindingTermination) {
|
|
12
|
+
ZLinkActorSessionBindingTermination[ZLinkActorSessionBindingTermination["BindingEnd"] = 0] = "BindingEnd";
|
|
13
|
+
ZLinkActorSessionBindingTermination[ZLinkActorSessionBindingTermination["PhysicalDisconnect"] = 1] = "PhysicalDisconnect";
|
|
14
|
+
})(ZLinkActorSessionBindingTermination || (exports.ZLinkActorSessionBindingTermination = ZLinkActorSessionBindingTermination = {}));
|
|
10
15
|
class ZLinkActorSessionBindingRegistry {
|
|
11
16
|
terminalRelocationCapacity;
|
|
12
17
|
outboundCapacity;
|
|
13
18
|
sealWaitTimeoutMs;
|
|
19
|
+
errorSink;
|
|
14
20
|
lane = new state_lane_1.ZLinkStateLane();
|
|
15
21
|
routes = new Map();
|
|
22
|
+
nextActorSlots = new WeakMap();
|
|
16
23
|
sealWaiters = new Map();
|
|
17
24
|
activeFrameWaiters = new Map();
|
|
18
25
|
relocations = new Map();
|
|
@@ -24,10 +31,11 @@ class ZLinkActorSessionBindingRegistry {
|
|
|
24
31
|
// (the sealing side) must observe that bound; an unbounded wait here
|
|
25
32
|
// turns a lost control or a lifecycle interlock into a silent stall
|
|
26
33
|
// (spec 48:205 — transport/deadline limits apply during relocation).
|
|
27
|
-
sealWaitTimeoutMs = 3_000) {
|
|
34
|
+
sealWaitTimeoutMs = 3_000, errorSink) {
|
|
28
35
|
this.terminalRelocationCapacity = terminalRelocationCapacity;
|
|
29
36
|
this.outboundCapacity = outboundCapacity;
|
|
30
37
|
this.sealWaitTimeoutMs = sealWaitTimeoutMs;
|
|
38
|
+
this.errorSink = errorSink;
|
|
31
39
|
if (!Number.isSafeInteger(terminalRelocationCapacity) || terminalRelocationCapacity <= 0) {
|
|
32
40
|
throw new RangeError('Session relocation terminal capacity must be a positive safe integer.');
|
|
33
41
|
}
|
|
@@ -38,61 +46,78 @@ class ZLinkActorSessionBindingRegistry {
|
|
|
38
46
|
throw new RangeError('Session relocation seal timeout must be a positive safe integer.');
|
|
39
47
|
}
|
|
40
48
|
}
|
|
41
|
-
async bind(context, actor, bindingToken, authorityFence, sessionIdentity) {
|
|
42
|
-
await this.lane.run(() => this.
|
|
49
|
+
async bind(context, actor, bindingToken, authorityFence, sessionIdentity, commitActor) {
|
|
50
|
+
await this.lane.run(() => this.commitCore(undefined, context, actor, bindingToken, authorityFence, sessionIdentity, commitActor));
|
|
43
51
|
}
|
|
44
|
-
|
|
45
|
-
this.routes.set(actor.actorId, {
|
|
46
|
-
context,
|
|
47
|
-
actor,
|
|
48
|
-
bindingToken,
|
|
49
|
-
sessionIdentity: sessionIdentity ?? sessionIdentityFromContext(context),
|
|
50
|
-
activeFrames: { count: 0, requests: new Set() },
|
|
51
|
-
authorityFence
|
|
52
|
-
});
|
|
53
|
-
context.bindLocal(actor, bindingToken);
|
|
54
|
-
}
|
|
55
|
-
async replace(previous, context, actor, bindingToken, authorityFence, sessionIdentity) {
|
|
56
|
-
await this.lane.run(() => this.replaceCore(previous, context, actor, bindingToken, authorityFence, sessionIdentity));
|
|
57
|
-
}
|
|
58
|
-
replaceCore(previous, context, actor, bindingToken, authorityFence, sessionIdentity) {
|
|
52
|
+
async commitCore(previous, context, actor, bindingToken, authorityFence, sessionIdentity, commitActor) {
|
|
59
53
|
const current = this.routes.get(actor.actorId);
|
|
60
54
|
if (current !== previous) {
|
|
61
|
-
throw (0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.ActorSessionNotBound, `Actor '${actor.actorId}' session binding changed before route
|
|
55
|
+
throw (0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.ActorSessionNotBound, `Actor '${actor.actorId}' session binding changed before route commit.`, true);
|
|
62
56
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
57
|
+
const sameBinding = previous !== undefined &&
|
|
58
|
+
previous.context === context &&
|
|
59
|
+
previous.bindingToken === bindingToken;
|
|
60
|
+
const actorSlot = sameBinding ? previous.actorSlot : this.issueActorSlot(context);
|
|
61
|
+
commitActor?.();
|
|
62
|
+
context.bindLocal(actor, bindingToken, actorSlot);
|
|
63
|
+
try {
|
|
64
|
+
if (previous !== undefined && !sameBinding) {
|
|
65
|
+
this.routes.delete(actor.actorId);
|
|
67
66
|
previous.context.unbindLocal(actor.actorId, previous.bindingToken);
|
|
67
|
+
if (previous.actorSlot !== undefined) {
|
|
68
|
+
let unbound;
|
|
69
|
+
try {
|
|
70
|
+
unbound = previous.context.actorSlotControls?.enqueueUnbound(previous.actorSlot);
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
unbound = Promise.reject(error);
|
|
74
|
+
}
|
|
75
|
+
void unbound?.catch((error) => this.errorSink?.()?.reportRuntimeTaskException('retired session actor unbound', error));
|
|
76
|
+
}
|
|
68
77
|
}
|
|
69
|
-
|
|
70
|
-
context.
|
|
71
|
-
previous.context.bindLocal(previous.actor, previous.bindingToken);
|
|
72
|
-
throw error;
|
|
78
|
+
if (!sameBinding && actorSlot !== undefined) {
|
|
79
|
+
await context.actorSlotControls.enqueueBound(actorSlot, actor.actorId);
|
|
73
80
|
}
|
|
74
81
|
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
context.unbindLocal(actor.actorId, bindingToken);
|
|
84
|
+
throw error;
|
|
85
|
+
}
|
|
75
86
|
this.routes.set(actor.actorId, {
|
|
76
87
|
context,
|
|
77
88
|
actor,
|
|
78
89
|
bindingToken,
|
|
90
|
+
actorSlot,
|
|
79
91
|
sessionIdentity: sessionIdentity ?? sessionIdentityFromContext(context),
|
|
80
|
-
activeFrames: previous
|
|
81
|
-
sealId: previous
|
|
82
|
-
authorityFence: authorityFence ?? previous
|
|
92
|
+
activeFrames: previous?.activeFrames ?? { count: 0, requests: new Set() },
|
|
93
|
+
sealId: previous?.sealId,
|
|
94
|
+
authorityFence: authorityFence ?? previous?.authorityFence
|
|
83
95
|
});
|
|
84
96
|
}
|
|
85
|
-
|
|
86
|
-
|
|
97
|
+
issueActorSlot(context) {
|
|
98
|
+
if (context.actorSlotControls === undefined)
|
|
99
|
+
return undefined;
|
|
100
|
+
const actorSlot = this.nextActorSlots.get(context) ?? 1;
|
|
101
|
+
if (actorSlot > 0xffff) {
|
|
102
|
+
throw (0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.InvalidOperation, `Stream session '${String(context.routingId)}' exhausted its Actor slots.`);
|
|
103
|
+
}
|
|
104
|
+
this.nextActorSlots.set(context, actorSlot + 1);
|
|
105
|
+
return actorSlot;
|
|
106
|
+
}
|
|
107
|
+
async replace(previous, context, actor, bindingToken, authorityFence, sessionIdentity, commitActor) {
|
|
108
|
+
await this.lane.run(() => this.commitCore(previous, context, actor, bindingToken, authorityFence, sessionIdentity, commitActor));
|
|
87
109
|
}
|
|
88
|
-
|
|
110
|
+
async replaceAndReleaseSeal(previous, context, actor, bindingToken, sealId, authorityFence, sessionIdentity, commitActor) {
|
|
111
|
+
await this.lane.run(() => this.replaceAndReleaseSealCore(previous, context, actor, bindingToken, sealId, authorityFence, sessionIdentity, commitActor));
|
|
112
|
+
}
|
|
113
|
+
async replaceAndReleaseSealCore(previous, context, actor, bindingToken, sealId, authorityFence, sessionIdentity, commitActor) {
|
|
89
114
|
if (previous.sealId !== sealId) {
|
|
90
115
|
throw (0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.ActorLocationStale, `Actor '${actor.actorId}' route switch did not match its relocation seal.`, true);
|
|
91
116
|
}
|
|
92
117
|
// JavaScript cannot interleave another ingress turn between these two
|
|
93
118
|
// synchronous mutations. The replacement preserves the seal, then the
|
|
94
119
|
// exact release publishes the route to held ingress as one owner turn.
|
|
95
|
-
this.
|
|
120
|
+
await this.commitCore(previous, context, actor, bindingToken, authorityFence, sessionIdentity, commitActor);
|
|
96
121
|
if (!this.abortSealCore(actor.actorId, sealId)) {
|
|
97
122
|
throw (0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.ActorLocationStale, `Actor '${actor.actorId}' route switch lost its relocation seal.`, true);
|
|
98
123
|
}
|
|
@@ -119,10 +144,10 @@ class ZLinkActorSessionBindingRegistry {
|
|
|
119
144
|
}
|
|
120
145
|
return Object.freeze({ context: route.context });
|
|
121
146
|
}
|
|
122
|
-
async unbind(actorId, context, bindingToken) {
|
|
123
|
-
await this.lane.run(() => this.unbindCore(actorId, context, bindingToken));
|
|
147
|
+
async unbind(actorId, context, bindingToken, termination = ZLinkActorSessionBindingTermination.BindingEnd) {
|
|
148
|
+
await this.lane.run(() => this.unbindCore(actorId, context, bindingToken, termination));
|
|
124
149
|
}
|
|
125
|
-
unbindCore(actorId, context, bindingToken) {
|
|
150
|
+
async unbindCore(actorId, context, bindingToken, termination) {
|
|
126
151
|
const route = this.routes.get(actorId);
|
|
127
152
|
if (route === undefined || route.context !== context || route.bindingToken !== bindingToken) {
|
|
128
153
|
return;
|
|
@@ -132,24 +157,28 @@ class ZLinkActorSessionBindingRegistry {
|
|
|
132
157
|
this.rejectSealWaiters(actorId, new Error(`Actor '${actorId}' session binding was removed while ingress was held.`));
|
|
133
158
|
this.rejectActiveFrameWaiters(actorId, new Error(`Actor '${actorId}' session binding was removed while accepted frames were active.`));
|
|
134
159
|
this.clearRouteRelocation(actorId, route, new Error(`Actor '${actorId}' session binding was removed.`));
|
|
160
|
+
if (termination === ZLinkActorSessionBindingTermination.BindingEnd &&
|
|
161
|
+
route.actorSlot !== undefined) {
|
|
162
|
+
await context.actorSlotControls?.enqueueUnbound(route.actorSlot);
|
|
163
|
+
}
|
|
135
164
|
}
|
|
136
165
|
async unbindActor(actorId) {
|
|
137
166
|
await this.lane.run(() => this.unbindActorCore(actorId));
|
|
138
167
|
}
|
|
139
|
-
unbindActorCore(actorId) {
|
|
168
|
+
async unbindActorCore(actorId) {
|
|
140
169
|
const route = this.routes.get(actorId);
|
|
141
170
|
if (route === undefined) {
|
|
142
171
|
return;
|
|
143
172
|
}
|
|
144
|
-
this.unbindCore(actorId, route.context, route.bindingToken);
|
|
173
|
+
await this.unbindCore(actorId, route.context, route.bindingToken, ZLinkActorSessionBindingTermination.BindingEnd);
|
|
145
174
|
}
|
|
146
175
|
async cleanup(context) {
|
|
147
176
|
await this.lane.run(() => this.cleanupCore(context));
|
|
148
177
|
}
|
|
149
|
-
cleanupCore(context) {
|
|
178
|
+
async cleanupCore(context) {
|
|
150
179
|
for (const route of [...this.routes.values()]) {
|
|
151
180
|
if (route.context === context) {
|
|
152
|
-
this.unbindCore(route.actor.actorId, context, route.bindingToken);
|
|
181
|
+
await this.unbindCore(route.actor.actorId, context, route.bindingToken, ZLinkActorSessionBindingTermination.PhysicalDisconnect);
|
|
153
182
|
}
|
|
154
183
|
}
|
|
155
184
|
}
|
|
@@ -2,6 +2,7 @@ import type { ActorRef } from '../../contracts';
|
|
|
2
2
|
import type { ServiceSessionBindingAdmissionClaim, ServiceSessionBindingAdmissionResult } from '../foundation/service-session-binding-ingress-port';
|
|
3
3
|
import type { ZLinkActorSessionAuthorityFence, ZLinkActorSessionAcceptedProducerProof, ZLinkActorSessionRelocationClaim, ZLinkActorSessionRelocationSnapshot, ZLinkActorSessionRetainedOutbound, ZLinkActorSessionRouteFence } from './actor-session-binding-registry';
|
|
4
4
|
export interface ZLinkActorSessionBindingRuntimeOwner {
|
|
5
|
+
actorSlot(actorId: string, sessionRid: string): Promise<number | undefined>;
|
|
5
6
|
sealRelocation(claim: ZLinkActorSessionRelocationClaim, expected: ZLinkActorSessionRouteFence, signal?: AbortSignal): Promise<void>;
|
|
6
7
|
relocationSnapshot(actorId: string, sealId: string): Promise<ZLinkActorSessionRelocationSnapshot | undefined>;
|
|
7
8
|
retainRelocationOutbound(actorId: string, operation: ZLinkActorSessionRetainedOutbound, sealId?: string): Promise<ServiceSessionBindingAdmissionResult>;
|
|
@@ -6,6 +6,7 @@ const payload_codec_1 = require("../messaging/payload-codec");
|
|
|
6
6
|
const protocol_1 = require("./protocol");
|
|
7
7
|
const abort_1 = require("../abort");
|
|
8
8
|
const execution_1 = require("../execution");
|
|
9
|
+
const actor_session_binding_registry_1 = require("./actor-session-binding-registry");
|
|
9
10
|
const actor_session_lifecycle_coordinator_1 = require("./actor-session-lifecycle-coordinator");
|
|
10
11
|
const managed_stream_1 = require("./managed-stream");
|
|
11
12
|
class ZLinkBoundActorRelaySender {
|
|
@@ -159,7 +160,7 @@ class ZLinkBoundActorRelaySender {
|
|
|
159
160
|
// The transport is already closed, so remove its exact route before
|
|
160
161
|
// invoking application lifecycle code. A reconnect can then install
|
|
161
162
|
// a successor while this best-effort notification is in flight.
|
|
162
|
-
await this.routes.unbind(actor.actorId, context, actor.bindingToken);
|
|
163
|
+
await this.routes.unbind(actor.actorId, context, actor.bindingToken, actor_session_binding_registry_1.ZLinkActorSessionBindingTermination.PhysicalDisconnect);
|
|
163
164
|
return true;
|
|
164
165
|
});
|
|
165
166
|
if (!detached)
|
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.DefaultZLinkBoundSessionResponseTarget = void 0;
|
|
4
4
|
exports.boundSessionErrorPayload = boundSessionErrorPayload;
|
|
5
|
+
const contracts_1 = require("../../contracts");
|
|
6
|
+
const channel_envelope_1 = require("../channels/channel-envelope");
|
|
7
|
+
const route_disconnected_error_1 = require("../channels/route-disconnected-error");
|
|
5
8
|
const submission_result_1 = require("../messaging/submission-result");
|
|
6
9
|
const protocol_1 = require("./protocol");
|
|
7
10
|
class DefaultZLinkBoundSessionResponseTarget {
|
|
@@ -36,7 +39,11 @@ class DefaultZLinkBoundSessionResponseTarget {
|
|
|
36
39
|
exports.DefaultZLinkBoundSessionResponseTarget = DefaultZLinkBoundSessionResponseTarget;
|
|
37
40
|
function boundSessionErrorPayload(error) {
|
|
38
41
|
return {
|
|
39
|
-
code: error instanceof
|
|
42
|
+
code: (0, channel_envelope_1.channelErrorCodeName)(error instanceof contracts_1.ZLinkFrameworkException
|
|
43
|
+
? error.kind
|
|
44
|
+
: error instanceof route_disconnected_error_1.ZLinkRouteDisconnectedError
|
|
45
|
+
? contracts_1.ZLinkFrameworkErrorKind.Unavailable
|
|
46
|
+
: contracts_1.ZLinkFrameworkErrorKind.InternalFailure),
|
|
40
47
|
message: errorMessage(error)
|
|
41
48
|
};
|
|
42
49
|
}
|
|
@@ -20,7 +20,7 @@ class ZLinkBoundSessionService {
|
|
|
20
20
|
async sendBoundSession(actorId, message, packetName, metadata, signal) {
|
|
21
21
|
(0, abort_1.throwIfAborted)(signal);
|
|
22
22
|
const route = await this.routes.requireRoute(actorId);
|
|
23
|
-
const frame = this.frameMessages.createJsonFrameMessage(protocol_1.ZLinkStreamMessageKind.Send, (0, protocol_1.resolvePacketName)(message, packetName), metadata, false, undefined, message);
|
|
23
|
+
const frame = this.frameMessages.createJsonFrameMessage(protocol_1.ZLinkStreamMessageKind.Send, (0, protocol_1.resolvePacketName)(message, packetName), metadata, false, undefined, message, undefined, this.actorSlot(route));
|
|
24
24
|
try {
|
|
25
25
|
const result = await this.requireTransport().send(actorId, frame, {
|
|
26
26
|
bindingToken: route.bindingToken,
|
|
@@ -40,7 +40,7 @@ class ZLinkBoundSessionService {
|
|
|
40
40
|
if (route === undefined) {
|
|
41
41
|
return { status: submission_result_1.ZLinkSubmitStatus.TargetNotFound };
|
|
42
42
|
}
|
|
43
|
-
const frame = this.frameMessages.createJsonFrameMessage(protocol_1.ZLinkStreamMessageKind.Send, (0, protocol_1.resolvePacketName)(message, packetName), metadata, false, undefined, message);
|
|
43
|
+
const frame = this.frameMessages.createJsonFrameMessage(protocol_1.ZLinkStreamMessageKind.Send, (0, protocol_1.resolvePacketName)(message, packetName), metadata, false, undefined, message, undefined, this.actorSlot(route));
|
|
44
44
|
try {
|
|
45
45
|
(0, abort_1.throwIfAborted)(signal);
|
|
46
46
|
if ((await this.routes.route(actorId))?.bindingToken !== route.bindingToken) {
|
|
@@ -124,7 +124,7 @@ class ZLinkBoundSessionService {
|
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
async writeLocalBoundSessionFrame(actorId, route, kind, packetName, metadata, compressPayload, requestSeq, payload, operationName) {
|
|
127
|
-
const frame = this.frameMessages.createJsonFrameMessage(kind, packetName, metadata, compressPayload, requestSeq, payload);
|
|
127
|
+
const frame = this.frameMessages.createJsonFrameMessage(kind, packetName, metadata, compressPayload, requestSeq, payload, undefined, this.actorSlot(route));
|
|
128
128
|
try {
|
|
129
129
|
if ((await this.routes.route(actorId))?.bindingToken !== route.bindingToken) {
|
|
130
130
|
return false;
|
|
@@ -165,6 +165,9 @@ class ZLinkBoundSessionService {
|
|
|
165
165
|
}
|
|
166
166
|
return this.options.transport;
|
|
167
167
|
}
|
|
168
|
+
actorSlot(route) {
|
|
169
|
+
return route.actorSlot;
|
|
170
|
+
}
|
|
168
171
|
}
|
|
169
172
|
exports.ZLinkBoundSessionService = ZLinkBoundSessionService;
|
|
170
173
|
function requireBoundSessionGeneration(actorRef) {
|
|
@@ -88,6 +88,7 @@ class ZLinkStreamRuntimeManager {
|
|
|
88
88
|
const service = createService.call(meshNode, socket.nativeInstance);
|
|
89
89
|
const bindingOwner = (0, actor_session_binding_runtime_owner_1.actorSessionBindingRuntimeOwner)(this.options.bindingRuntime);
|
|
90
90
|
(0, service_session_binding_ingress_port_1.registerServiceSessionBindingIngressPort)(service, {
|
|
91
|
+
actorSlot: (actorId, sessionRid) => bindingOwner.actorSlot(actorId, sessionRid),
|
|
91
92
|
retainOutbound: (claim, delivery) => bindingOwner.admitRelocationOutbound(claim, delivery),
|
|
92
93
|
clearOutbound: (actorId, error) => bindingOwner.clearRelocation(actorId, error)
|
|
93
94
|
});
|
|
@@ -206,7 +207,7 @@ class ZLinkStreamBindingRuntime {
|
|
|
206
207
|
...options,
|
|
207
208
|
actorBindTimeoutMs: options.actorBindTimeoutMs ?? DEFAULT_ACTOR_BIND_TIMEOUT_MS
|
|
208
209
|
};
|
|
209
|
-
this.routes = new actor_session_binding_registry_1.ZLinkActorSessionBindingRegistry(4096, 4096, runtimeOptions.sessionRelocationSealTimeoutMs ?? 3_000);
|
|
210
|
+
this.routes = new actor_session_binding_registry_1.ZLinkActorSessionBindingRegistry(4096, 4096, runtimeOptions.sessionRelocationSealTimeoutMs ?? 3_000, runtimeOptions.errorSink);
|
|
210
211
|
this.compressionCodec = (0, stream_frame_factory_1.resolveStreamCompressionCodec)(runtimeOptions.streamCompression);
|
|
211
212
|
this.frameMessages = new stream_frame_factory_1.ZLinkStreamFrameMessageFactory(runtimeOptions);
|
|
212
213
|
this.boundSessions = new bound_session_service_1.ZLinkBoundSessionService(this.routes, this.frameMessages, runtimeOptions);
|
|
@@ -214,6 +215,12 @@ class ZLinkStreamBindingRuntime {
|
|
|
214
215
|
this.sessionActors = new session_actor_coordinator_1.ZLinkSessionActorCoordinator(this.routes, this, runtimeOptions, actorSessionLifecycle);
|
|
215
216
|
this.boundActorRelay = new bound_actor_relay_sender_1.ZLinkBoundActorRelaySender(this.routes, this.frameMessages, runtimeOptions, actorSessionLifecycle);
|
|
216
217
|
(0, actor_session_binding_runtime_owner_1.registerActorSessionBindingRuntimeOwner)(this, {
|
|
218
|
+
actorSlot: async (actorId, sessionRid) => {
|
|
219
|
+
const route = await this.routes.route(actorId);
|
|
220
|
+
return route !== undefined && route.sessionIdentity === sessionRid
|
|
221
|
+
? route.actorSlot
|
|
222
|
+
: undefined;
|
|
223
|
+
},
|
|
217
224
|
sealRelocation: (claim, expected, signal) => this.routes.sealRelocation(claim, expected, signal),
|
|
218
225
|
relocationSnapshot: (actorId, sealId) => this.routes.relocationSnapshot(actorId, sealId),
|
|
219
226
|
retainRelocationOutbound: (actorId, operation, sealId) => this.routes.retainRelocationOutbound(actorId, operation, sealId),
|
|
@@ -43,6 +43,9 @@ export declare class ZLinkManagedStream implements ZLinkStream {
|
|
|
43
43
|
bindActor(actor: ActorRef, timeoutMs: number, signal?: AbortSignal, onBindingReplaced?: (actor: ServiceActorRef, retiredSession: ServiceRetiredBoundSessionRouteFence) => void, authorityFence?: ZLinkActorSessionAuthorityFence): Promise<void>;
|
|
44
44
|
private ensureNativeActorRoute;
|
|
45
45
|
unbindActor(actorId: string, timeoutMs: number, signal?: AbortSignal): Promise<void>;
|
|
46
|
+
enqueueActorBound(actorSlot: number, actorId: string): Promise<void>;
|
|
47
|
+
enqueueActorUnbound(actorSlot: number): Promise<void>;
|
|
48
|
+
private submitActorBindingControl;
|
|
46
49
|
sendBoundActor(actorId: string, parts: readonly Message[], flags?: ZLinkBackendSendFlags): Promise<boolean>;
|
|
47
50
|
updateAddresses(localAddr: string | undefined, remoteAddr: string | undefined): void;
|
|
48
51
|
private hasNativeBinding;
|
|
@@ -122,12 +122,12 @@ class ZLinkManagedStream {
|
|
|
122
122
|
if (this.transportClosed) {
|
|
123
123
|
throw (0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.RouteNotConnected, `Stream session '${this.sessionId}' is disconnected.`);
|
|
124
124
|
}
|
|
125
|
+
const nativeActor = toNativeActorRef(actor);
|
|
125
126
|
const route = this.nativeRoute(actor.meshName);
|
|
126
127
|
if (route !== undefined) {
|
|
127
128
|
if (route.service.status().state === 1) {
|
|
128
129
|
route.service.start();
|
|
129
130
|
}
|
|
130
|
-
const nativeActor = toNativeActorRef(actor);
|
|
131
131
|
await this.ensureNativeActorRoute(route, actor, timeoutMs, signal);
|
|
132
132
|
if (this.isTransportClosed()) {
|
|
133
133
|
throw (0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.RouteNotConnected, `Stream session '${this.sessionId}' is disconnected.`);
|
|
@@ -163,6 +163,7 @@ class ZLinkManagedStream {
|
|
|
163
163
|
return;
|
|
164
164
|
}
|
|
165
165
|
await this.socket.bindActor(this.backendRoutingId(), toBackendActorRef(actor), timeoutMs, signal);
|
|
166
|
+
this.nativeActorBindings.set(actor.actorId, { actor: nativeActor });
|
|
166
167
|
}
|
|
167
168
|
async ensureNativeActorRoute(route, actor, timeoutMs, signal) {
|
|
168
169
|
const completion = await route.completions.submit(() => route.service.lookupActor(actor.nodeRid, actor.actorId, timeoutMs), signal);
|
|
@@ -223,6 +224,24 @@ class ZLinkManagedStream {
|
|
|
223
224
|
return;
|
|
224
225
|
}
|
|
225
226
|
await this.socket.unbindActor(this.backendRoutingId(), actorId, timeoutMs, signal);
|
|
227
|
+
if (binding !== undefined && this.nativeActorBindings.get(actorId) === binding) {
|
|
228
|
+
this.nativeActorBindings.delete(actorId);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
async enqueueActorBound(actorSlot, actorId) {
|
|
232
|
+
await this.submitActorBindingControl((0, protocol_1.encodeActorBoundFrame)(actorSlot, actorId));
|
|
233
|
+
}
|
|
234
|
+
async enqueueActorUnbound(actorSlot) {
|
|
235
|
+
await this.submitActorBindingControl((0, protocol_1.encodeActorUnboundFrame)(actorSlot));
|
|
236
|
+
}
|
|
237
|
+
async submitActorBindingControl(frame) {
|
|
238
|
+
const message = runtime_message_1.ZLinkBufferMessage.from(frame);
|
|
239
|
+
try {
|
|
240
|
+
await this.socket.submit(this.backendRoutingId(), message);
|
|
241
|
+
}
|
|
242
|
+
finally {
|
|
243
|
+
message.close();
|
|
244
|
+
}
|
|
226
245
|
}
|
|
227
246
|
async sendBoundActor(actorId, parts, flags) {
|
|
228
247
|
if (this.transportClosed) {
|
|
@@ -22,7 +22,8 @@ export declare enum ZLinkStreamHeaderFlags {
|
|
|
22
22
|
HasMetadata = 2,
|
|
23
23
|
PayloadCompressed = 4,
|
|
24
24
|
HasCorrelationId = 8,
|
|
25
|
-
HasFlowId = 16
|
|
25
|
+
HasFlowId = 16,
|
|
26
|
+
HasActorSlot = 32
|
|
26
27
|
}
|
|
27
28
|
export declare enum ZLinkStreamCloseReasonCode {
|
|
28
29
|
ClientClose = 1,
|
|
@@ -44,6 +45,7 @@ export interface ZLinkStreamFrameHeader {
|
|
|
44
45
|
readonly correlationId?: string;
|
|
45
46
|
readonly flowId?: string;
|
|
46
47
|
readonly flowOrigin?: ZLinkFlowOrigin;
|
|
48
|
+
readonly actorSlot?: number;
|
|
47
49
|
}
|
|
48
50
|
export type ZLinkStreamReplyMessageKind = ZLinkStreamMessageKind.Response | ZLinkStreamMessageKind.Error;
|
|
49
51
|
export interface ZLinkStreamFrame {
|
|
@@ -54,6 +56,8 @@ export declare function resolvePacketName(message: unknown, explicitPacketName:
|
|
|
54
56
|
export declare function ensureSingleSubmit(executed: boolean): void;
|
|
55
57
|
export declare function encodeStreamFrame(header: ZLinkStreamFrameHeader, payload: Uint8Array): Uint8Array;
|
|
56
58
|
export declare function encodeStreamControlFrame(name: string): Uint8Array;
|
|
59
|
+
export declare function encodeActorBoundFrame(actorSlot: number, actorId: string): Uint8Array;
|
|
60
|
+
export declare function encodeActorUnboundFrame(actorSlot: number): Uint8Array;
|
|
57
61
|
export declare function encodeSessionClosingFrame(diagnostic?: string, reason?: ZLinkStreamCloseReasonCode): Uint8Array;
|
|
58
62
|
export declare function decodeStreamFrame(frame: Uint8Array): ZLinkStreamFrame;
|
|
59
63
|
export declare function tryDecodeStreamFrame(frame: Uint8Array): ZLinkStreamFrame | undefined;
|
|
@@ -7,6 +7,8 @@ exports.resolvePacketName = resolvePacketName;
|
|
|
7
7
|
exports.ensureSingleSubmit = ensureSingleSubmit;
|
|
8
8
|
exports.encodeStreamFrame = encodeStreamFrame;
|
|
9
9
|
exports.encodeStreamControlFrame = encodeStreamControlFrame;
|
|
10
|
+
exports.encodeActorBoundFrame = encodeActorBoundFrame;
|
|
11
|
+
exports.encodeActorUnboundFrame = encodeActorUnboundFrame;
|
|
10
12
|
exports.encodeSessionClosingFrame = encodeSessionClosingFrame;
|
|
11
13
|
exports.decodeStreamFrame = decodeStreamFrame;
|
|
12
14
|
exports.tryDecodeStreamFrame = tryDecodeStreamFrame;
|
|
@@ -78,6 +80,7 @@ var ZLinkStreamHeaderFlags;
|
|
|
78
80
|
ZLinkStreamHeaderFlags[ZLinkStreamHeaderFlags["PayloadCompressed"] = 4] = "PayloadCompressed";
|
|
79
81
|
ZLinkStreamHeaderFlags[ZLinkStreamHeaderFlags["HasCorrelationId"] = 8] = "HasCorrelationId";
|
|
80
82
|
ZLinkStreamHeaderFlags[ZLinkStreamHeaderFlags["HasFlowId"] = 16] = "HasFlowId";
|
|
83
|
+
ZLinkStreamHeaderFlags[ZLinkStreamHeaderFlags["HasActorSlot"] = 32] = "HasActorSlot";
|
|
81
84
|
})(ZLinkStreamHeaderFlags || (exports.ZLinkStreamHeaderFlags = ZLinkStreamHeaderFlags = {}));
|
|
82
85
|
var ZLinkStreamCloseReasonCode;
|
|
83
86
|
(function (ZLinkStreamCloseReasonCode) {
|
|
@@ -114,6 +117,26 @@ function encodeStreamControlFrame(name) {
|
|
|
114
117
|
metadata: EMPTY_STREAM_METADATA
|
|
115
118
|
}, new Uint8Array());
|
|
116
119
|
}
|
|
120
|
+
function encodeActorBoundFrame(actorSlot, actorId) {
|
|
121
|
+
const actorIdBytes = (0, stream_wire_1.utf8Encode)(actorId);
|
|
122
|
+
if (actorIdBytes.length < 1 || actorIdBytes.length > 0xff) {
|
|
123
|
+
throw new Error('Actor id length is invalid for a STREAM binding control packet.');
|
|
124
|
+
}
|
|
125
|
+
const payload = new Uint8Array(4 + actorIdBytes.length);
|
|
126
|
+
payload[0] = 1;
|
|
127
|
+
payload[1] = actorSlot >>> 8;
|
|
128
|
+
payload[2] = actorSlot & 0xff;
|
|
129
|
+
payload[3] = actorIdBytes.length;
|
|
130
|
+
payload.set(actorIdBytes, 4);
|
|
131
|
+
return encodeStreamFrame(controlHeader('$zlink.actor.bound'), payload);
|
|
132
|
+
}
|
|
133
|
+
function encodeActorUnboundFrame(actorSlot) {
|
|
134
|
+
const payload = new Uint8Array(3);
|
|
135
|
+
payload[0] = 1;
|
|
136
|
+
payload[1] = actorSlot >>> 8;
|
|
137
|
+
payload[2] = actorSlot & 0xff;
|
|
138
|
+
return encodeStreamFrame(controlHeader('$zlink.actor.unbound'), payload);
|
|
139
|
+
}
|
|
117
140
|
function encodeSessionClosingFrame(diagnostic = '', reason = ZLinkStreamCloseReasonCode.ServerDrain) {
|
|
118
141
|
const diagnosticBytes = (0, stream_wire_1.utf8Encode)(diagnostic);
|
|
119
142
|
if (diagnosticBytes.length > 512)
|
|
@@ -143,8 +166,9 @@ function encodeStreamHeader(header) {
|
|
|
143
166
|
const hasMetadata = header.metadata.size > 0;
|
|
144
167
|
const hasCorrelation = header.correlationId !== undefined && header.correlationId.length > 0;
|
|
145
168
|
const hasFlow = header.flowId !== undefined || header.flowOrigin !== undefined;
|
|
169
|
+
const hasActorSlot = header.actorSlot !== undefined;
|
|
146
170
|
if (header.kind === ZLinkStreamMessageKind.Control &&
|
|
147
|
-
(hasCorrelation || hasRequestSeq || hasMetadata || hasFlow)) {
|
|
171
|
+
(hasCorrelation || hasRequestSeq || hasMetadata || hasFlow || hasActorSlot)) {
|
|
148
172
|
throw new Error('Control packet must not contain a request sequence, metadata, correlation id, or flow id.');
|
|
149
173
|
}
|
|
150
174
|
// Explicit construction: this runs for every outbound frame, so avoid a
|
|
@@ -158,7 +182,8 @@ function encodeStreamHeader(header) {
|
|
|
158
182
|
metadata: header.metadata,
|
|
159
183
|
correlationId: header.correlationId,
|
|
160
184
|
flowId: header.flowId,
|
|
161
|
-
flowOrigin: encodeFlowOrigin(header.flowOrigin)
|
|
185
|
+
flowOrigin: encodeFlowOrigin(header.flowOrigin),
|
|
186
|
+
actorSlot: header.actorSlot
|
|
162
187
|
});
|
|
163
188
|
}
|
|
164
189
|
function decodeStreamHeader(header, flowEnabled = true) {
|
|
@@ -169,8 +194,9 @@ function decodeStreamHeader(header, flowEnabled = true) {
|
|
|
169
194
|
const hasMetadata = (flags & ZLinkStreamHeaderFlags.HasMetadata) !== 0;
|
|
170
195
|
const hasCorrelation = (flags & ZLinkStreamHeaderFlags.HasCorrelationId) !== 0;
|
|
171
196
|
const hasFlow = (flags & ZLinkStreamHeaderFlags.HasFlowId) !== 0;
|
|
197
|
+
const hasActorSlot = (flags & ZLinkStreamHeaderFlags.HasActorSlot) !== 0;
|
|
172
198
|
if (kind === ZLinkStreamMessageKind.Control &&
|
|
173
|
-
(hasCorrelation || hasRequestSeq || hasMetadata || hasFlow)) {
|
|
199
|
+
(hasCorrelation || hasRequestSeq || hasMetadata || hasFlow || hasActorSlot)) {
|
|
174
200
|
throw new Error('Control packet must not contain a request sequence, metadata, correlation id, or flow id.');
|
|
175
201
|
}
|
|
176
202
|
const metadata = publicStreamMetadata(decoded.metadata);
|
|
@@ -184,7 +210,8 @@ function decodeStreamHeader(header, flowEnabled = true) {
|
|
|
184
210
|
metadata,
|
|
185
211
|
correlationId: decoded.correlationId,
|
|
186
212
|
flowId: decoded.flowId,
|
|
187
|
-
flowOrigin: decodeFlowOrigin(decoded.flowOrigin)
|
|
213
|
+
flowOrigin: decodeFlowOrigin(decoded.flowOrigin),
|
|
214
|
+
actorSlot: decoded.actorSlot
|
|
188
215
|
};
|
|
189
216
|
}
|
|
190
217
|
function actorRequestDeadlineMetadata(deadlineUnixMs) {
|
|
@@ -221,9 +248,19 @@ function createStreamReplyHeader(requestHeader, kind, codec, flags, metadata, in
|
|
|
221
248
|
// observation-only and is not copied into the reply when tracing is Off
|
|
222
249
|
// (spec 27 §4, §7).
|
|
223
250
|
correlationId: requestHeader.correlationId,
|
|
251
|
+
actorSlot: requestHeader.actorSlot,
|
|
224
252
|
...(includeFlow ? { flowId: requestHeader.flowId, flowOrigin: requestHeader.flowOrigin } : {})
|
|
225
253
|
};
|
|
226
254
|
}
|
|
255
|
+
function controlHeader(name) {
|
|
256
|
+
return {
|
|
257
|
+
kind: ZLinkStreamMessageKind.Control,
|
|
258
|
+
codec: ZLinkStreamCodec.Raw,
|
|
259
|
+
flags: ZLinkStreamHeaderFlags.None,
|
|
260
|
+
name,
|
|
261
|
+
metadata: EMPTY_STREAM_METADATA
|
|
262
|
+
};
|
|
263
|
+
}
|
|
227
264
|
function encodeFlowOrigin(origin) {
|
|
228
265
|
return origin === undefined
|
|
229
266
|
? undefined
|
|
@@ -60,18 +60,17 @@ class ZLinkSessionActorCoordinator {
|
|
|
60
60
|
const sessionActor = reuseActor ??
|
|
61
61
|
new session_context_1.DefaultZLinkSessionActor(this.sessionActorRuntime, boundActorRef, bindingToken);
|
|
62
62
|
const sessionIdentity = String(this.actorBindingRoutingId(context));
|
|
63
|
-
sessionActor.updateRef(boundActorRef);
|
|
64
63
|
if (previous === undefined) {
|
|
65
64
|
if (releaseSeal !== undefined) {
|
|
66
65
|
throw (0, framework_errors_internal_1.createInternalFrameworkException)(framework_errors_internal_1.ZLinkFrameworkInternalErrorKind.ActorSessionNotBound, `Actor '${actorRef.actorId}' route switch has no Session binding to release.`, true);
|
|
67
66
|
}
|
|
68
|
-
await this.routes.bind(context, sessionActor, bindingToken, authorityFence, sessionIdentity);
|
|
67
|
+
await this.routes.bind(context, sessionActor, bindingToken, authorityFence, sessionIdentity, () => sessionActor.updateRef(boundActorRef));
|
|
69
68
|
}
|
|
70
69
|
else if (releaseSeal !== undefined) {
|
|
71
|
-
await this.routes.replaceAndReleaseSeal(previous, context, sessionActor, bindingToken, releaseSeal.sealId, authorityFence, sessionIdentity);
|
|
70
|
+
await this.routes.replaceAndReleaseSeal(previous, context, sessionActor, bindingToken, releaseSeal.sealId, authorityFence, sessionIdentity, () => sessionActor.updateRef(boundActorRef));
|
|
72
71
|
}
|
|
73
72
|
else {
|
|
74
|
-
await this.routes.replace(previous, context, sessionActor, bindingToken, authorityFence, sessionIdentity);
|
|
73
|
+
await this.routes.replace(previous, context, sessionActor, bindingToken, authorityFence, sessionIdentity, () => sessionActor.updateRef(boundActorRef));
|
|
75
74
|
}
|
|
76
75
|
if (confirmRemoteSessionBinding !== false &&
|
|
77
76
|
this.options.confirmRemoteActorSessionBinding !== undefined) {
|
|
@@ -10,6 +10,8 @@ import type { ServiceRetiredBoundSessionRouteFence } from '../foundation/service
|
|
|
10
10
|
export interface ZLinkSessionContextStream extends ZLinkStream {
|
|
11
11
|
writeRaw(payload: Message, flags?: number): boolean;
|
|
12
12
|
submitRaw(payload: Message, signal?: AbortSignal, timeoutMs?: number): Promise<ZLinkSubmitResult>;
|
|
13
|
+
enqueueActorBound?(actorSlot: number, actorId: string): Promise<void>;
|
|
14
|
+
enqueueActorUnbound?(actorSlot: number): Promise<void>;
|
|
13
15
|
}
|
|
14
16
|
interface ZLinkSessionContextRuntime {
|
|
15
17
|
cleanup(context: DefaultZLinkSessionContext): Promise<void>;
|
|
@@ -76,7 +78,12 @@ export declare class DefaultZLinkSessionContext implements ZLinkSessionContext {
|
|
|
76
78
|
payloadForHeader(header: ZLinkStreamFrameHeader, payload: Message): Message;
|
|
77
79
|
get boundActors(): readonly DefaultZLinkSessionActor[];
|
|
78
80
|
findBoundActor(actorId: string): DefaultZLinkSessionActor | undefined;
|
|
79
|
-
|
|
81
|
+
actorForSlot(actorSlot: number | undefined): DefaultZLinkSessionActor | undefined;
|
|
82
|
+
get actorSlotControls(): {
|
|
83
|
+
enqueueBound(actorSlot: number, actorId: string): Promise<void>;
|
|
84
|
+
enqueueUnbound(actorSlot: number): Promise<void>;
|
|
85
|
+
} | undefined;
|
|
86
|
+
bindLocal(actor: DefaultZLinkSessionActor, token: string, actorSlot?: number): void;
|
|
80
87
|
unbindLocal(actorId: string, token: string): void;
|
|
81
88
|
completeConfiguration(): void;
|
|
82
89
|
}
|
|
@@ -92,7 +99,7 @@ export declare class DefaultZLinkSessionActor implements ZLinkSessionActor {
|
|
|
92
99
|
relay(dispatch: ZLinkSessionDispatchContext, payload: ZLinkMessage, signal?: AbortSignal): Promise<void>;
|
|
93
100
|
notifyDisconnected(signal?: AbortSignal): Promise<void>;
|
|
94
101
|
}
|
|
95
|
-
export declare function createSessionDispatchContext(header: ZLinkStreamFrameHeader): ZLinkSessionDispatchContext;
|
|
102
|
+
export declare function createSessionDispatchContext(header: ZLinkStreamFrameHeader, actor?: DefaultZLinkSessionActor): ZLinkSessionDispatchContext;
|
|
96
103
|
export declare class DefaultZLinkBoundSession implements ZLinkBoundSession {
|
|
97
104
|
private readonly runtime;
|
|
98
105
|
private readonly actorId;
|
|
@@ -163,8 +163,23 @@ class DefaultZLinkSessionContext {
|
|
|
163
163
|
findBoundActor(actorId) {
|
|
164
164
|
return this.localActors.find(actorId);
|
|
165
165
|
}
|
|
166
|
-
|
|
167
|
-
|
|
166
|
+
actorForSlot(actorSlot) {
|
|
167
|
+
if (actorSlot === undefined)
|
|
168
|
+
return undefined;
|
|
169
|
+
return this.localActors.findBySlot(actorSlot);
|
|
170
|
+
}
|
|
171
|
+
get actorSlotControls() {
|
|
172
|
+
if (this.stream.enqueueActorBound === undefined ||
|
|
173
|
+
this.stream.enqueueActorUnbound === undefined) {
|
|
174
|
+
return undefined;
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
enqueueBound: (actorSlot, actorId) => this.stream.enqueueActorBound(actorSlot, actorId),
|
|
178
|
+
enqueueUnbound: (actorSlot) => this.stream.enqueueActorUnbound(actorSlot)
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
bindLocal(actor, token, actorSlot) {
|
|
182
|
+
this.localActors.bind(actor, token, actorSlot);
|
|
168
183
|
}
|
|
169
184
|
unbindLocal(actorId, token) {
|
|
170
185
|
this.localActors.unbind(actorId, token);
|
|
@@ -313,11 +328,12 @@ class DefaultZLinkSessionActor {
|
|
|
313
328
|
}
|
|
314
329
|
exports.DefaultZLinkSessionActor = DefaultZLinkSessionActor;
|
|
315
330
|
const SESSION_DISPATCH_HEADERS = new WeakMap();
|
|
316
|
-
function createSessionDispatchContext(header) {
|
|
331
|
+
function createSessionDispatchContext(header, actor) {
|
|
317
332
|
const dispatch = {
|
|
318
333
|
packetName: header.name,
|
|
319
334
|
metadata: header.metadata,
|
|
320
|
-
canReply: header.requestSeq !== undefined
|
|
335
|
+
canReply: header.requestSeq !== undefined,
|
|
336
|
+
...(actor === undefined ? {} : { actor })
|
|
321
337
|
};
|
|
322
338
|
SESSION_DISPATCH_HEADERS.set(dispatch, header);
|
|
323
339
|
return dispatch;
|
|
@@ -3,8 +3,10 @@ export interface ZLinkSessionLocalActor {
|
|
|
3
3
|
}
|
|
4
4
|
export declare class ZLinkSessionLocalActorBindings<TActor extends ZLinkSessionLocalActor> {
|
|
5
5
|
private readonly actors;
|
|
6
|
+
private readonly actorIdsBySlot;
|
|
6
7
|
snapshot(): readonly TActor[];
|
|
7
8
|
find(actorId: string): TActor | undefined;
|
|
8
|
-
|
|
9
|
+
findBySlot(actorSlot: number): TActor | undefined;
|
|
10
|
+
bind(actor: TActor, token: string, actorSlot?: number): void;
|
|
9
11
|
unbind(actorId: string, token: string): void;
|
|
10
12
|
}
|