@zlink-systems/framework 0.11.0 → 0.13.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/Configuration/EndpointNotation.d.ts +5 -4
- package/dist/contracts/Configuration/EndpointNotation.js +5 -4
- package/dist/contracts/Configuration/InternalDefaults.d.ts +0 -1
- package/dist/contracts/Configuration/InternalDefaults.js +1 -2
- package/dist/contracts/Configuration/RegistrationNormalizers.js +1 -2
- package/dist/contracts/Configuration/RegistrationTypes.d.ts +2 -5
- package/dist/contracts/Configuration/RegistrationValidators.js +0 -1
- package/dist/contracts/Errors/ZLinkFrameworkException.d.ts +6 -7
- package/dist/contracts/Errors/ZLinkFrameworkException.js +6 -7
- package/dist/runtime/actors/actor-client.js +1 -1
- package/dist/runtime/actors/actor-mailbox.js +1 -5
- package/dist/runtime/backend/contracts/index.d.ts +2 -0
- package/dist/runtime/backend/mesh-completion-table.d.ts +1 -3
- package/dist/runtime/backend/mesh-completion-table.js +11 -15
- package/dist/runtime/backend/mesh-dispatch-pump.d.ts +11 -4
- package/dist/runtime/backend/mesh-dispatch-pump.js +201 -134
- package/dist/runtime/backend/node/node-backend-adapter-factory.d.ts +3 -4
- package/dist/runtime/backend/node/node-backend-adapter-factory.js +51 -37
- package/dist/runtime/backend/node/node-backend-adapter-support.d.ts +2 -2
- package/dist/runtime/backend/node/node-backend-adapter-support.js +2 -2
- package/dist/runtime/backend/node/node-dealer-channel-client-transport.js +2 -2
- package/dist/runtime/backend/node/node-event-loop-poller.d.ts +16 -0
- package/dist/runtime/backend/node/node-event-loop-poller.js +49 -0
- package/dist/runtime/backend/node/node-raw-binding-port.js +24 -41
- package/dist/runtime/backend/node/node-raw-mesh-backend.d.ts +8 -8
- package/dist/runtime/backend/node/node-raw-mesh-backend.js +100 -107
- package/dist/runtime/backend/node/node-socket-backend-adapter.d.ts +3 -2
- package/dist/runtime/backend/node/node-socket-backend-adapter.js +18 -67
- package/dist/runtime/backend/raw-binding-port.d.ts +1 -0
- package/dist/runtime/backend/runtime-values.d.ts +5 -1
- package/dist/runtime/channels/channel-dispatchers.js +2 -2
- package/dist/runtime/channels/channel-envelope.js +324 -121
- package/dist/runtime/channels/channel-multipart.d.ts +8 -1
- package/dist/runtime/channels/channel-outbound-operations.js +0 -2
- package/dist/runtime/channels/channel-receive-loops.d.ts +1 -3
- package/dist/runtime/channels/channel-receive-loops.js +25 -65
- package/dist/runtime/channels/channel-socket-registry.js +3 -1
- package/dist/runtime/channels/channel-transports.d.ts +2 -1
- package/dist/runtime/channels/channel-transports.js +12 -10
- package/dist/runtime/execution/serial-execution-queue.d.ts +5 -18
- package/dist/runtime/execution/serial-execution-queue.js +16 -80
- package/dist/runtime/foundation/event-loop-resources.d.ts +0 -3
- package/dist/runtime/foundation/event-loop-resources.js +2 -11
- package/dist/runtime/foundation/operation-registry.d.ts +2 -8
- package/dist/runtime/foundation/operation-registry.js +3 -21
- package/dist/runtime/foundation/raw-service-mesh-runtime.d.ts +19 -7
- package/dist/runtime/foundation/raw-service-mesh-runtime.js +56 -10
- package/dist/runtime/foundation/service-mailbox.d.ts +1 -7
- package/dist/runtime/foundation/service-mailbox.js +3 -2
- package/dist/runtime/foundation/service-runtime-contracts.d.ts +2 -1
- package/dist/runtime/foundation/service-stateful-registry.d.ts +1 -1
- package/dist/runtime/foundation/service-stateful-registry.js +2 -2
- package/dist/runtime/foundation/service-stateful-runtime.js +14 -14
- package/dist/runtime/framework-errors-internal.d.ts +4 -4
- package/dist/runtime/framework-errors-internal.js +8 -10
- package/dist/runtime/host/actor-placement-coordinator.js +1 -1
- package/dist/runtime/host/index.js +1 -1
- package/dist/runtime/host/service-relocation-host-runtime.js +0 -4
- package/dist/runtime/host/spot-address-transport.js +1 -1
- package/dist/runtime/host/user-spot-creation-coordinator.js +1 -1
- package/dist/runtime/spots/spot-node-runtime-manager.d.ts +0 -12
- package/dist/runtime/spots/spot-node-runtime-manager.js +6 -166
- package/dist/runtime/spots/spot-serial-turn-executor.js +1 -4
- package/dist/runtime/spots/spot-timer.d.ts +3 -0
- package/dist/runtime/spots/spot-timer.js +87 -18
- package/dist/runtime/streams/session-serial-executor.js +1 -3
- package/dist/runtime/streams/stream-session-runtime.d.ts +2 -2
- package/dist/runtime/streams/stream-session-runtime.js +13 -19
- package/dist/runtime/workers/index.d.ts +0 -1
- package/dist/runtime/workers/index.js +1 -9
- package/package.json +3 -3
- package/src/contracts/Configuration/EndpointNotation.ts +5 -4
- package/src/contracts/Configuration/InternalDefaults.ts +0 -1
- package/src/contracts/Configuration/RegistrationNormalizers.ts +2 -4
- package/src/contracts/Configuration/RegistrationTypes.ts +2 -5
- package/src/contracts/Configuration/RegistrationValidators.ts +0 -1
- package/src/contracts/Errors/ZLinkFrameworkException.ts +6 -7
- package/src/runtime/actors/actor-client.ts +1 -1
- package/src/runtime/actors/actor-mailbox.ts +1 -12
- package/src/runtime/backend/contracts/index.ts +2 -0
- package/src/runtime/backend/mesh-completion-table.ts +12 -23
- package/src/runtime/backend/mesh-dispatch-pump.ts +206 -138
- package/src/runtime/backend/node/node-backend-adapter-factory.ts +66 -35
- package/src/runtime/backend/node/node-backend-adapter-support.ts +4 -4
- package/src/runtime/backend/node/node-dealer-channel-client-transport.ts +2 -2
- package/src/runtime/backend/node/node-event-loop-poller.ts +55 -0
- package/src/runtime/backend/node/node-raw-binding-port.ts +30 -45
- package/src/runtime/backend/node/node-raw-mesh-backend.ts +97 -110
- package/src/runtime/backend/node/node-socket-backend-adapter.ts +23 -69
- package/src/runtime/backend/raw-binding-port.ts +1 -0
- package/src/runtime/backend/runtime-values.ts +7 -1
- package/src/runtime/channels/channel-dispatchers.ts +2 -2
- package/src/runtime/channels/channel-envelope.ts +379 -109
- package/src/runtime/channels/channel-multipart.ts +9 -1
- package/src/runtime/channels/channel-outbound-operations.ts +0 -1
- package/src/runtime/channels/channel-receive-loops.ts +24 -75
- package/src/runtime/channels/channel-socket-registry.ts +4 -1
- package/src/runtime/channels/channel-transports.ts +20 -10
- package/src/runtime/execution/serial-execution-queue.ts +16 -108
- package/src/runtime/foundation/event-loop-resources.ts +2 -11
- package/src/runtime/foundation/operation-registry.ts +2 -22
- package/src/runtime/foundation/raw-service-mesh-runtime.ts +74 -19
- package/src/runtime/foundation/service-mailbox.ts +3 -13
- package/src/runtime/foundation/service-runtime-contracts.ts +2 -1
- package/src/runtime/foundation/service-stateful-registry.ts +2 -2
- package/src/runtime/foundation/service-stateful-runtime.ts +14 -14
- package/src/runtime/framework-errors-internal.ts +8 -10
- package/src/runtime/host/actor-placement-coordinator.ts +1 -1
- package/src/runtime/host/index.ts +2 -1
- package/src/runtime/host/service-relocation-host-runtime.ts +0 -4
- package/src/runtime/host/spot-address-transport.ts +1 -1
- package/src/runtime/host/user-spot-creation-coordinator.ts +1 -1
- package/src/runtime/spots/spot-node-runtime-manager.ts +13 -233
- package/src/runtime/spots/spot-serial-turn-executor.ts +1 -8
- package/src/runtime/spots/spot-timer.ts +109 -18
- package/src/runtime/streams/session-serial-executor.ts +1 -7
- package/src/runtime/streams/stream-session-runtime.ts +13 -17
- package/src/runtime/workers/index.ts +2 -17
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
Context,
|
|
3
3
|
CoreHwmBudgetSnapshot,
|
|
4
|
-
Received,
|
|
5
4
|
TopicMessage
|
|
6
5
|
} from '@zlink-systems/zlink';
|
|
7
6
|
import type { ZLinkCoreHwmOptions } from '../../../contracts/Configuration';
|
|
@@ -11,6 +10,7 @@ import type {
|
|
|
11
10
|
ZLinkBackendDealerSocket,
|
|
12
11
|
ZLinkBackendPublisherSocket,
|
|
13
12
|
ZLinkBackendReadablePoller,
|
|
13
|
+
ZLinkBackendReceived,
|
|
14
14
|
ZLinkBackendRouterSocket,
|
|
15
15
|
ZLinkBackendSocket,
|
|
16
16
|
ZLinkBackendSocketMonitor,
|
|
@@ -24,18 +24,15 @@ import type {
|
|
|
24
24
|
import {
|
|
25
25
|
closeWithBusyRetry,
|
|
26
26
|
isContextTerminatedError,
|
|
27
|
-
isPollerInterruptedError,
|
|
28
27
|
zlink,
|
|
29
28
|
type ZLinkBindingModule
|
|
30
29
|
} from './node-backend-adapter-support';
|
|
31
30
|
import { wrapMonitorSocket } from './node-monitor-backend-adapter';
|
|
32
|
-
import { wrapSocket } from './node-socket-backend-adapter';
|
|
31
|
+
import { nodeEventLoopPollerOf, wrapSocket } from './node-socket-backend-adapter';
|
|
33
32
|
import { ZLinkNodeMeshBackendAdapter } from './node-mesh-backend-adapter';
|
|
34
33
|
|
|
35
|
-
export { isDisconnectRouteNotFoundError } from './node-socket-backend-adapter';
|
|
36
|
-
|
|
37
34
|
export class ZLinkNodeBackendAdapterFactory implements ZLinkBackendAdapterFactory {
|
|
38
|
-
createReceived():
|
|
35
|
+
createReceived(): ZLinkBackendReceived {
|
|
39
36
|
return new zlink.Received();
|
|
40
37
|
}
|
|
41
38
|
|
|
@@ -70,11 +67,17 @@ class ZLinkNodeChannelBackendAdapter implements ZLinkChannelBackendAdapter {
|
|
|
70
67
|
}
|
|
71
68
|
|
|
72
69
|
createDealerSocket(context: ZLinkBackendContext): ZLinkBackendDealerSocket {
|
|
73
|
-
return wrapSocket(
|
|
70
|
+
return wrapSocket(
|
|
71
|
+
zlink.createDealerSocket(asNodeContext(context)),
|
|
72
|
+
true
|
|
73
|
+
) as unknown as ZLinkBackendDealerSocket;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
createRouterSocket(context: ZLinkBackendContext): ZLinkBackendRouterSocket {
|
|
77
|
-
return wrapSocket(
|
|
77
|
+
return wrapSocket(
|
|
78
|
+
zlink.createRouterSocket(asNodeContext(context)),
|
|
79
|
+
true
|
|
80
|
+
) as unknown as ZLinkBackendRouterSocket;
|
|
78
81
|
}
|
|
79
82
|
|
|
80
83
|
createPublisherSocket(context: ZLinkBackendContext): ZLinkBackendPublisherSocket {
|
|
@@ -82,7 +85,10 @@ class ZLinkNodeChannelBackendAdapter implements ZLinkChannelBackendAdapter {
|
|
|
82
85
|
}
|
|
83
86
|
|
|
84
87
|
createSubscriberSocket(context: ZLinkBackendContext): ZLinkBackendSubscriberSocket {
|
|
85
|
-
return wrapSocket(
|
|
88
|
+
return wrapSocket(
|
|
89
|
+
zlink.createSubSocket(asNodeContext(context)),
|
|
90
|
+
false
|
|
91
|
+
) as unknown as ZLinkBackendSubscriberSocket;
|
|
86
92
|
}
|
|
87
93
|
|
|
88
94
|
createReadablePoller(socket: ZLinkBackendSubscriberSocket): ZLinkBackendReadablePoller {
|
|
@@ -94,7 +100,7 @@ class ZLinkNodeStreamBackendAdapter implements ZLinkStreamBackendAdapter {
|
|
|
94
100
|
createStreamSocket(context: ZLinkBackendContext): ZLinkBackendStreamSocket {
|
|
95
101
|
const socket = zlink.createStreamSocket(asNodeContext(context));
|
|
96
102
|
socket.options.recvMode = zlink.StreamRecvMode.Packet;
|
|
97
|
-
return wrapSocket(socket) as unknown as ZLinkBackendStreamSocket;
|
|
103
|
+
return wrapSocket(socket, true) as unknown as ZLinkBackendStreamSocket;
|
|
98
104
|
}
|
|
99
105
|
|
|
100
106
|
createStreamPacket(): ZLinkBackendStreamPacket {
|
|
@@ -167,38 +173,63 @@ function asNodeContext(context: ZLinkBackendContext): Context {
|
|
|
167
173
|
function createNodeReadablePoller(
|
|
168
174
|
socket: { readonly nativeInstance: unknown }
|
|
169
175
|
): ZLinkBackendReadablePoller {
|
|
170
|
-
const
|
|
171
|
-
const events = zlink.createPollEvents(1);
|
|
172
|
-
try {
|
|
173
|
-
poller.add(socket.nativeInstance as never, [zlink.PollEventFlag.PollIn], 0);
|
|
174
|
-
} catch (error) {
|
|
175
|
-
events.close();
|
|
176
|
-
poller.close();
|
|
177
|
-
throw error;
|
|
178
|
-
}
|
|
176
|
+
const eventLoopPoller = nodeEventLoopPollerOf(socket);
|
|
179
177
|
let disposed = false;
|
|
178
|
+
let readable = false;
|
|
179
|
+
let pending: {
|
|
180
|
+
readonly promise: Promise<boolean>;
|
|
181
|
+
readonly resolve: (readable: boolean) => void;
|
|
182
|
+
readonly signal?: AbortSignal;
|
|
183
|
+
readonly onAbort?: () => void;
|
|
184
|
+
} | undefined;
|
|
185
|
+
|
|
186
|
+
const settlePending = (value: boolean): void => {
|
|
187
|
+
const current = pending;
|
|
188
|
+
if (current === undefined) return;
|
|
189
|
+
pending = undefined;
|
|
190
|
+
if (current.signal !== undefined && current.onAbort !== undefined) {
|
|
191
|
+
current.signal.removeEventListener('abort', current.onAbort);
|
|
192
|
+
}
|
|
193
|
+
current.resolve(value);
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
eventLoopPoller.setReadableHandler(() => {
|
|
197
|
+
if (disposed) return;
|
|
198
|
+
readable = true;
|
|
199
|
+
settlePending(true);
|
|
200
|
+
});
|
|
201
|
+
|
|
180
202
|
return {
|
|
181
|
-
wait(
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
203
|
+
wait(_timeoutMs: number): boolean {
|
|
204
|
+
return !disposed && readable;
|
|
205
|
+
},
|
|
206
|
+
waitForReadable(signal?: AbortSignal): Promise<boolean> {
|
|
207
|
+
if (disposed || signal?.aborted === true) return Promise.resolve(false);
|
|
208
|
+
if (readable) return Promise.resolve(true);
|
|
209
|
+
if (pending !== undefined) return pending.promise;
|
|
210
|
+
|
|
211
|
+
let resolvePending!: (value: boolean) => void;
|
|
212
|
+
const promise = new Promise<boolean>((resolve) => {
|
|
213
|
+
resolvePending = resolve;
|
|
214
|
+
});
|
|
215
|
+
const onAbort = signal === undefined
|
|
216
|
+
? undefined
|
|
217
|
+
: (): void => settlePending(false);
|
|
218
|
+
pending = { promise, resolve: resolvePending, signal, onAbort };
|
|
219
|
+
if (signal !== undefined && onAbort !== undefined) {
|
|
220
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
188
221
|
}
|
|
222
|
+
return promise;
|
|
223
|
+
},
|
|
224
|
+
markDrained(): void {
|
|
225
|
+
readable = false;
|
|
189
226
|
},
|
|
190
227
|
dispose(): void {
|
|
191
228
|
if (disposed) return;
|
|
192
229
|
disposed = true;
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
try {
|
|
197
|
-
events.close();
|
|
198
|
-
} finally {
|
|
199
|
-
poller.close();
|
|
200
|
-
}
|
|
201
|
-
}
|
|
230
|
+
readable = false;
|
|
231
|
+
settlePending(false);
|
|
232
|
+
eventLoopPoller.setReadableHandler(() => {});
|
|
202
233
|
}
|
|
203
234
|
};
|
|
204
235
|
}
|
|
@@ -30,7 +30,7 @@ interface ZLinkBindingReplySubmitOperation {
|
|
|
30
30
|
|
|
31
31
|
interface ZLinkBindingAsyncSendSubmitOperation {
|
|
32
32
|
message(message: unknown): ZLinkBindingAsyncSendSubmitOperation;
|
|
33
|
-
submit():
|
|
33
|
+
submit(): import('@zlink-systems/zlink').SendSubmission;
|
|
34
34
|
submit_sync(): void;
|
|
35
35
|
}
|
|
36
36
|
|
|
@@ -41,7 +41,7 @@ export interface ZLinkBindingRequestOperation {
|
|
|
41
41
|
interface ZLinkBindingRequestSubmitOperation {
|
|
42
42
|
message(message: unknown): ZLinkBindingRequestSubmitOperation;
|
|
43
43
|
timeout(timeoutMs: number): ZLinkBindingRequestSubmitOperation;
|
|
44
|
-
submit():
|
|
44
|
+
submit(): import('@zlink-systems/zlink').RequestSubmission;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
47
|
export function isBindingNotFound(error: unknown): boolean {
|
|
@@ -113,7 +113,7 @@ export async function submitBindingAsyncSend(
|
|
|
113
113
|
current = current === undefined ? operation.message(nativePart) : current.message(nativePart);
|
|
114
114
|
}
|
|
115
115
|
current ??= operation.message(Buffer.alloc(0));
|
|
116
|
-
await current.submit();
|
|
116
|
+
await current.submit().admitted;
|
|
117
117
|
} catch (error) {
|
|
118
118
|
throw translateBindingResultError(error);
|
|
119
119
|
}
|
|
@@ -156,7 +156,7 @@ export async function submitBindingRequest(
|
|
|
156
156
|
if (timeoutMs !== undefined) {
|
|
157
157
|
current = current.timeout(timeoutMs);
|
|
158
158
|
}
|
|
159
|
-
return await current.submit();
|
|
159
|
+
return await current.submit().reply;
|
|
160
160
|
} catch (error) {
|
|
161
161
|
throw translateBindingResultError(error);
|
|
162
162
|
}
|
|
@@ -54,7 +54,7 @@ export class ZLinkDealerChannelClientTransport implements ZLinkChannelClientTran
|
|
|
54
54
|
true,
|
|
55
55
|
metadata
|
|
56
56
|
)
|
|
57
|
-
).submit());
|
|
57
|
+
).submit().admitted);
|
|
58
58
|
return { status: ZLinkSubmitStatus.Submitted };
|
|
59
59
|
}
|
|
60
60
|
|
|
@@ -83,7 +83,7 @@ export class ZLinkDealerChannelClientTransport implements ZLinkChannelClientTran
|
|
|
83
83
|
)
|
|
84
84
|
));
|
|
85
85
|
if (timeoutMs !== undefined) operation.timeout(timeoutMs);
|
|
86
|
-
const reply = await submitRequestOperation(operation, 'channel request');
|
|
86
|
+
const reply = await submitRequestOperation({ submit: () => operation.submit().reply }, 'channel request');
|
|
87
87
|
try {
|
|
88
88
|
return decodeChannelReply<TReply>(reply);
|
|
89
89
|
} finally {
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
BaseSocket,
|
|
3
|
+
PollEventFlagValue,
|
|
4
|
+
Socket
|
|
5
|
+
} from '@zlink-systems/zlink';
|
|
6
|
+
import { zlink } from './node-backend-adapter-support';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Owns one binding public Poller and drives it from the socket's libuv
|
|
10
|
+
* readiness callback. PollCompletion is drained only by Poller.wait; the
|
|
11
|
+
* socket callback itself is only the event-loop wakeup.
|
|
12
|
+
*/
|
|
13
|
+
export class ZLinkNodeEventLoopPoller {
|
|
14
|
+
private readonly poller = zlink.createPoller();
|
|
15
|
+
private readonly events = zlink.createPollEvents(1);
|
|
16
|
+
private readableHandler: () => void;
|
|
17
|
+
private disposed = false;
|
|
18
|
+
|
|
19
|
+
constructor(
|
|
20
|
+
socket: Socket,
|
|
21
|
+
pollCompletion: boolean,
|
|
22
|
+
readableHandler: () => void
|
|
23
|
+
) {
|
|
24
|
+
this.readableHandler = readableHandler;
|
|
25
|
+
try {
|
|
26
|
+
const pollEvents: PollEventFlagValue[] = [zlink.PollEventFlag.PollIn];
|
|
27
|
+
if (pollCompletion) pollEvents.push(zlink.PollEventFlag.PollCompletion);
|
|
28
|
+
this.poller.add(socket as BaseSocket, pollEvents, 0);
|
|
29
|
+
socket.setReadableHandler(this.onReady);
|
|
30
|
+
} catch (error) {
|
|
31
|
+
this.events.close();
|
|
32
|
+
this.poller.close();
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
setReadableHandler(handler: () => void): void {
|
|
38
|
+
this.readableHandler = handler;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
dispose(): void {
|
|
42
|
+
if (this.disposed) return;
|
|
43
|
+
this.disposed = true;
|
|
44
|
+
this.events.close();
|
|
45
|
+
this.poller.close();
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private readonly onReady = (): void => {
|
|
49
|
+
if (this.disposed) return;
|
|
50
|
+
const ready = this.poller.wait(this.events, 0);
|
|
51
|
+
if (ready === 0 || this.events.hasEvent(0, zlink.PollEventFlag.PollIn)) {
|
|
52
|
+
this.readableHandler();
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
}
|
|
@@ -5,11 +5,9 @@ import {
|
|
|
5
5
|
RoutingId as BindingRoutingId,
|
|
6
6
|
createContext,
|
|
7
7
|
createDealerSocket,
|
|
8
|
-
createPollEvents,
|
|
9
|
-
createPoller,
|
|
10
8
|
createRouterSocket,
|
|
11
|
-
PollEventFlag,
|
|
12
9
|
ReceiveFlowState,
|
|
10
|
+
SubmitResult,
|
|
13
11
|
type Context,
|
|
14
12
|
type DealerSocket,
|
|
15
13
|
type MonitorEvent,
|
|
@@ -24,8 +22,9 @@ import {
|
|
|
24
22
|
type SendSubmitOperation,
|
|
25
23
|
type Socket
|
|
26
24
|
} from '@zlink-systems/zlink';
|
|
27
|
-
import {
|
|
25
|
+
import { translateBindingResultError } from './node-backend-adapter-support';
|
|
28
26
|
import { isEndpointCloseIgnorableError } from './node-socket-backend-adapter';
|
|
27
|
+
import { ZLinkNodeEventLoopPoller } from './node-event-loop-poller';
|
|
29
28
|
import type {
|
|
30
29
|
ZLinkRawBindingPort,
|
|
31
30
|
ZLinkRawDealerPort,
|
|
@@ -122,12 +121,20 @@ class NodeRawHostPort implements ZLinkRawHostPort {
|
|
|
122
121
|
abstract class NodeRawSocketPort<TSocket extends Socket> implements ZLinkRawSocketPort {
|
|
123
122
|
private readonly endpoints = new Set<string>();
|
|
124
123
|
private readonly monitors = new Set<NodeRawMonitorPort>();
|
|
125
|
-
private readonly
|
|
126
|
-
private readonly readableEvents = createPollEvents(1);
|
|
124
|
+
private readonly eventLoopPoller: ZLinkNodeEventLoopPoller;
|
|
127
125
|
private closed = false;
|
|
128
126
|
|
|
129
127
|
protected constructor(protected readonly socket: TSocket) {
|
|
130
|
-
this.
|
|
128
|
+
this.eventLoopPoller = new ZLinkNodeEventLoopPoller(
|
|
129
|
+
socket,
|
|
130
|
+
true,
|
|
131
|
+
() => {}
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
setReadableHandler(handler: () => void): void {
|
|
136
|
+
this.requireOpen();
|
|
137
|
+
this.eventLoopPoller.setReadableHandler(handler);
|
|
131
138
|
}
|
|
132
139
|
|
|
133
140
|
bind(endpoint: string): void {
|
|
@@ -172,6 +179,11 @@ abstract class NodeRawSocketPort<TSocket extends Socket> implements ZLinkRawSock
|
|
|
172
179
|
close(): void {
|
|
173
180
|
if (this.closed) return;
|
|
174
181
|
const failures: unknown[] = [];
|
|
182
|
+
try {
|
|
183
|
+
this.eventLoopPoller.dispose();
|
|
184
|
+
} catch (error) {
|
|
185
|
+
failures.push(error);
|
|
186
|
+
}
|
|
175
187
|
for (const monitor of [...this.monitors].reverse()) {
|
|
176
188
|
try {
|
|
177
189
|
monitor.close();
|
|
@@ -192,21 +204,6 @@ abstract class NodeRawSocketPort<TSocket extends Socket> implements ZLinkRawSock
|
|
|
192
204
|
}
|
|
193
205
|
}
|
|
194
206
|
this.endpoints.clear();
|
|
195
|
-
try {
|
|
196
|
-
this.readablePoller.remove(this.socket as never);
|
|
197
|
-
} catch (error) {
|
|
198
|
-
failures.push(error);
|
|
199
|
-
}
|
|
200
|
-
try {
|
|
201
|
-
this.readableEvents.close();
|
|
202
|
-
} catch (error) {
|
|
203
|
-
failures.push(error);
|
|
204
|
-
}
|
|
205
|
-
try {
|
|
206
|
-
this.readablePoller.close();
|
|
207
|
-
} catch (error) {
|
|
208
|
-
failures.push(error);
|
|
209
|
-
}
|
|
210
207
|
try {
|
|
211
208
|
this.socket.close();
|
|
212
209
|
} catch (error) {
|
|
@@ -222,24 +219,6 @@ abstract class NodeRawSocketPort<TSocket extends Socket> implements ZLinkRawSock
|
|
|
222
219
|
protected requireOpen(): void {
|
|
223
220
|
if (this.closed) throw new Error('Raw socket is closed.');
|
|
224
221
|
}
|
|
225
|
-
|
|
226
|
-
protected receiveRecord(
|
|
227
|
-
dontWait: boolean
|
|
228
|
-
): ZLinkRawReceivedRecord | undefined {
|
|
229
|
-
const timeoutMs = dontWait ? 0 : -1;
|
|
230
|
-
try {
|
|
231
|
-
if (
|
|
232
|
-
this.readablePoller.wait(this.readableEvents, timeoutMs) <= 0
|
|
233
|
-
|| !this.readableEvents.hasEvent(0, PollEventFlag.PollIn)
|
|
234
|
-
) {
|
|
235
|
-
return undefined;
|
|
236
|
-
}
|
|
237
|
-
} catch (error) {
|
|
238
|
-
if (isPollerInterruptedError(error)) return undefined;
|
|
239
|
-
throw error;
|
|
240
|
-
}
|
|
241
|
-
return receiveRecord(this.socket as never, true);
|
|
242
|
-
}
|
|
243
222
|
}
|
|
244
223
|
|
|
245
224
|
class NodeRawRouterPort extends NodeRawSocketPort<RouterSocket> implements ZLinkRawRouterPort {
|
|
@@ -276,10 +255,13 @@ class NodeRawRouterPort extends NodeRawSocketPort<RouterSocket> implements ZLink
|
|
|
276
255
|
|
|
277
256
|
async send(targetRid: string, parts: readonly Uint8Array[]): Promise<void> {
|
|
278
257
|
this.requireOpen();
|
|
279
|
-
|
|
258
|
+
const submission = appendSendParts(
|
|
280
259
|
this.socket.send(bindingRoutingId(targetRid)),
|
|
281
260
|
parts
|
|
282
261
|
).submit();
|
|
262
|
+
if (submission.result === SubmitResult.Backpressured) {
|
|
263
|
+
await submission.admitted;
|
|
264
|
+
}
|
|
283
265
|
}
|
|
284
266
|
|
|
285
267
|
async request(
|
|
@@ -291,7 +273,7 @@ class NodeRawRouterPort extends NodeRawSocketPort<RouterSocket> implements ZLink
|
|
|
291
273
|
try {
|
|
292
274
|
const replies = await appendRequestParts(this.socket.request(bindingRoutingId(targetRid)), parts)
|
|
293
275
|
.timeout(timeoutMs)
|
|
294
|
-
.submit();
|
|
276
|
+
.submit().reply;
|
|
295
277
|
return copyAndClose(replies);
|
|
296
278
|
} catch (error) {
|
|
297
279
|
throw translateBindingResultError(error);
|
|
@@ -332,18 +314,21 @@ class NodeRawDealerPort extends NodeRawSocketPort<DealerSocket> implements ZLink
|
|
|
332
314
|
|
|
333
315
|
async send(parts: readonly Uint8Array[]): Promise<void> {
|
|
334
316
|
this.requireOpen();
|
|
335
|
-
|
|
317
|
+
const submission = appendSendParts(this.socket.send(), parts).submit();
|
|
318
|
+
if (submission.result === SubmitResult.Backpressured) {
|
|
319
|
+
await submission.admitted;
|
|
320
|
+
}
|
|
336
321
|
}
|
|
337
322
|
|
|
338
323
|
async request(parts: readonly Uint8Array[], timeoutMs: number): Promise<readonly Buffer[]> {
|
|
339
324
|
this.requireOpen();
|
|
340
|
-
const replies = await appendRequestParts(this.socket.request(), parts).timeout(timeoutMs).submit();
|
|
325
|
+
const replies = await appendRequestParts(this.socket.request(), parts).timeout(timeoutMs).submit().reply;
|
|
341
326
|
return copyAndClose(replies);
|
|
342
327
|
}
|
|
343
328
|
|
|
344
329
|
receive(dontWait = false): ZLinkRawReceivedRecord | undefined {
|
|
345
330
|
this.requireOpen();
|
|
346
|
-
return this.
|
|
331
|
+
return receiveRecord(this.socket, dontWait);
|
|
347
332
|
}
|
|
348
333
|
}
|
|
349
334
|
|