@bytecodealliance/preview2-shim 0.14.1 → 0.15.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/README.md +2 -2
- package/lib/browser/filesystem.js +6 -5
- package/lib/browser/random.js +1 -1
- package/lib/browser/sockets.js +0 -14
- package/lib/io/calls.js +80 -16
- package/lib/io/worker-http.js +164 -67
- package/lib/io/worker-io.js +207 -68
- package/lib/io/worker-socket-tcp.js +285 -0
- package/lib/io/worker-socket-udp.js +576 -0
- package/lib/io/worker-sockets.js +371 -0
- package/lib/io/worker-thread.js +793 -399
- package/lib/nodejs/cli.js +29 -13
- package/lib/nodejs/clocks.js +9 -6
- package/lib/nodejs/filesystem.js +170 -57
- package/lib/nodejs/http.js +662 -531
- package/lib/nodejs/index.js +0 -3
- package/lib/nodejs/sockets.js +571 -11
- package/lib/synckit/index.js +25 -41
- package/package.json +2 -2
- package/types/interfaces/wasi-http-types.d.ts +53 -41
- package/types/interfaces/wasi-sockets-tcp.d.ts +5 -0
- package/lib/common/assert.js +0 -7
- package/lib/nodejs/sockets/socket-common.js +0 -116
- package/lib/nodejs/sockets/socketopts-bindings.js +0 -94
- package/lib/nodejs/sockets/tcp-socket-impl.js +0 -794
- package/lib/nodejs/sockets/udp-socket-impl.js +0 -628
- package/lib/nodejs/sockets/wasi-sockets.js +0 -320
- package/lib/synckit/index.d.ts +0 -71
package/lib/nodejs/index.js
CHANGED
package/lib/nodejs/sockets.js
CHANGED
|
@@ -1,11 +1,571 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
import {
|
|
2
|
+
SOCKET_DATAGRAM_STREAM_DISPOSE,
|
|
3
|
+
SOCKET_DATAGRAM_STREAM_SUBSCRIBE,
|
|
4
|
+
SOCKET_INCOMING_DATAGRAM_STREAM_RECEIVE,
|
|
5
|
+
SOCKET_OUTGOING_DATAGRAM_STREAM_CHECK_SEND,
|
|
6
|
+
SOCKET_OUTGOING_DATAGRAM_STREAM_SEND,
|
|
7
|
+
SOCKET_RESOLVE_ADDRESS_CREATE_REQUEST,
|
|
8
|
+
SOCKET_RESOLVE_ADDRESS_DISPOSE_REQUEST,
|
|
9
|
+
SOCKET_RESOLVE_ADDRESS_SUBSCRIBE_REQUEST,
|
|
10
|
+
SOCKET_RESOLVE_ADDRESS_TAKE_REQUEST,
|
|
11
|
+
SOCKET_GET_DEFAULT_RECEIVE_BUFFER_SIZE,
|
|
12
|
+
SOCKET_GET_DEFAULT_SEND_BUFFER_SIZE,
|
|
13
|
+
SOCKET_TCP_ACCEPT,
|
|
14
|
+
SOCKET_TCP_BIND_FINISH,
|
|
15
|
+
SOCKET_TCP_BIND_START,
|
|
16
|
+
SOCKET_TCP_CONNECT_FINISH,
|
|
17
|
+
SOCKET_TCP_CONNECT_START,
|
|
18
|
+
SOCKET_TCP_CREATE_HANDLE,
|
|
19
|
+
SOCKET_TCP_DISPOSE,
|
|
20
|
+
SOCKET_TCP_GET_LOCAL_ADDRESS,
|
|
21
|
+
SOCKET_TCP_GET_REMOTE_ADDRESS,
|
|
22
|
+
SOCKET_TCP_IS_LISTENING,
|
|
23
|
+
SOCKET_TCP_LISTEN_FINISH,
|
|
24
|
+
SOCKET_TCP_LISTEN_START,
|
|
25
|
+
SOCKET_TCP_SET_KEEP_ALIVE,
|
|
26
|
+
SOCKET_TCP_SET_LISTEN_BACKLOG_SIZE,
|
|
27
|
+
SOCKET_TCP_SHUTDOWN,
|
|
28
|
+
SOCKET_TCP_SUBSCRIBE,
|
|
29
|
+
SOCKET_TCP,
|
|
30
|
+
SOCKET_UDP_BIND_FINISH,
|
|
31
|
+
SOCKET_UDP_BIND_START,
|
|
32
|
+
SOCKET_UDP_CREATE_HANDLE,
|
|
33
|
+
SOCKET_UDP_DISPOSE,
|
|
34
|
+
SOCKET_UDP_GET_LOCAL_ADDRESS,
|
|
35
|
+
SOCKET_UDP_GET_RECEIVE_BUFFER_SIZE,
|
|
36
|
+
SOCKET_UDP_GET_REMOTE_ADDRESS,
|
|
37
|
+
SOCKET_UDP_GET_SEND_BUFFER_SIZE,
|
|
38
|
+
SOCKET_UDP_GET_UNICAST_HOP_LIMIT,
|
|
39
|
+
SOCKET_UDP_SET_RECEIVE_BUFFER_SIZE,
|
|
40
|
+
SOCKET_UDP_SET_SEND_BUFFER_SIZE,
|
|
41
|
+
SOCKET_UDP_SET_UNICAST_HOP_LIMIT,
|
|
42
|
+
SOCKET_UDP_STREAM,
|
|
43
|
+
SOCKET_UDP_SUBSCRIBE,
|
|
44
|
+
} from "../io/calls.js";
|
|
45
|
+
import {
|
|
46
|
+
earlyDispose,
|
|
47
|
+
inputStreamCreate,
|
|
48
|
+
ioCall,
|
|
49
|
+
outputStreamCreate,
|
|
50
|
+
pollableCreate,
|
|
51
|
+
registerDispose,
|
|
52
|
+
} from "../io/worker-io.js";
|
|
53
|
+
|
|
54
|
+
const symbolDispose = Symbol.dispose || Symbol.for("dispose");
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @typedef {import("../../types/interfaces/wasi-sockets-network").IpSocketAddress} IpSocketAddress
|
|
58
|
+
* @typedef {import("../../types/interfaces/wasi-sockets-network").IpAddressFamily} IpAddressFamily
|
|
59
|
+
*/
|
|
60
|
+
|
|
61
|
+
// Network class privately stores capabilities
|
|
62
|
+
class Network {
|
|
63
|
+
#allowDnsLookup = true;
|
|
64
|
+
#allowTcp = true;
|
|
65
|
+
#allowUdp = true;
|
|
66
|
+
|
|
67
|
+
static _denyDnsLookup(network = defaultNetwork) {
|
|
68
|
+
network.#allowDnsLookup = false;
|
|
69
|
+
}
|
|
70
|
+
static _denyTcp(network = defaultNetwork) {
|
|
71
|
+
network.#allowTcp = false;
|
|
72
|
+
}
|
|
73
|
+
static _denyUdp(network = defaultNetwork) {
|
|
74
|
+
network.#allowUdp = false;
|
|
75
|
+
}
|
|
76
|
+
static _mayDnsLookup(network = defaultNetwork) {
|
|
77
|
+
return network.#allowDnsLookup;
|
|
78
|
+
}
|
|
79
|
+
static _mayTcp(network = defaultNetwork) {
|
|
80
|
+
return network.#allowTcp;
|
|
81
|
+
}
|
|
82
|
+
static _mayUdp(network = defaultNetwork) {
|
|
83
|
+
return network.#allowUdp;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export const _denyDnsLookup = Network._denyDnsLookup;
|
|
88
|
+
delete Network._denyDnsLookup;
|
|
89
|
+
|
|
90
|
+
export const _denyTcp = Network._denyTcp;
|
|
91
|
+
delete Network._denyTcp;
|
|
92
|
+
|
|
93
|
+
export const _denyUdp = Network._denyUdp;
|
|
94
|
+
delete Network._denyUdp;
|
|
95
|
+
|
|
96
|
+
const mayDnsLookup = Network._mayDnsLookup;
|
|
97
|
+
delete Network._mayDnsLookup;
|
|
98
|
+
|
|
99
|
+
const mayTcp = Network._mayTcp;
|
|
100
|
+
delete Network._mayTcp;
|
|
101
|
+
|
|
102
|
+
const mayUdp = Network._mayUdp;
|
|
103
|
+
delete Network._mayUdp;
|
|
104
|
+
|
|
105
|
+
const defaultNetwork = new Network();
|
|
106
|
+
|
|
107
|
+
export const instanceNetwork = {
|
|
108
|
+
instanceNetwork() {
|
|
109
|
+
return defaultNetwork;
|
|
110
|
+
},
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
export const network = { Network };
|
|
114
|
+
|
|
115
|
+
class ResolveAddressStream {
|
|
116
|
+
#id;
|
|
117
|
+
#data;
|
|
118
|
+
#curItem = 0;
|
|
119
|
+
#error = false;
|
|
120
|
+
#finalizer;
|
|
121
|
+
resolveNextAddress() {
|
|
122
|
+
if (!this.#data) {
|
|
123
|
+
const res = ioCall(SOCKET_RESOLVE_ADDRESS_TAKE_REQUEST, this.#id, null);
|
|
124
|
+
this.#data = res.val;
|
|
125
|
+
this.#error = res.tag === "err";
|
|
126
|
+
}
|
|
127
|
+
if (this.#error) throw this.#data;
|
|
128
|
+
if (this.#curItem < this.#data.length) return this.#data[this.#curItem++];
|
|
129
|
+
return undefined;
|
|
130
|
+
}
|
|
131
|
+
subscribe() {
|
|
132
|
+
return pollableCreate(
|
|
133
|
+
ioCall(SOCKET_RESOLVE_ADDRESS_SUBSCRIBE_REQUEST, this.#id, null),
|
|
134
|
+
this
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
static _resolveAddresses(network, name) {
|
|
138
|
+
if (!mayDnsLookup(network)) throw "permanent-resolver-failure";
|
|
139
|
+
const res = new ResolveAddressStream();
|
|
140
|
+
res.#id = ioCall(SOCKET_RESOLVE_ADDRESS_CREATE_REQUEST, null, name);
|
|
141
|
+
res.#finalizer = registerDispose(
|
|
142
|
+
res,
|
|
143
|
+
null,
|
|
144
|
+
res.#id,
|
|
145
|
+
resolveAddressStreamDispose
|
|
146
|
+
);
|
|
147
|
+
return res;
|
|
148
|
+
}
|
|
149
|
+
[symbolDispose]() {
|
|
150
|
+
if (this.#finalizer) {
|
|
151
|
+
earlyDispose(this.#finalizer);
|
|
152
|
+
this.#finalizer = null;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
function resolveAddressStreamDispose(id) {
|
|
157
|
+
ioCall(SOCKET_RESOLVE_ADDRESS_DISPOSE_REQUEST, id, null);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const resolveAddresses = ResolveAddressStream._resolveAddresses;
|
|
161
|
+
delete ResolveAddressStream._resolveAddresses;
|
|
162
|
+
|
|
163
|
+
export const ipNameLookup = {
|
|
164
|
+
ResolveAddressStream,
|
|
165
|
+
resolveAddresses,
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
class TcpSocket {
|
|
169
|
+
#id;
|
|
170
|
+
#network;
|
|
171
|
+
#family;
|
|
172
|
+
#finalizer;
|
|
173
|
+
#options = {
|
|
174
|
+
// defaults per https://nodejs.org/docs/latest/api/net.html#socketsetkeepaliveenable-initialdelay
|
|
175
|
+
keepAlive: false,
|
|
176
|
+
// Node.js doesn't give us the ability to detect the OS default,
|
|
177
|
+
// therefore we hardcode the default value instead of using the OS default,
|
|
178
|
+
// since we would never be able to report it as a return value otherwise.
|
|
179
|
+
// We could make this configurable as a global JCO implementation configuration
|
|
180
|
+
// instead.
|
|
181
|
+
keepAliveIdleTime: 7200_000_000_000n,
|
|
182
|
+
|
|
183
|
+
// The following options are NOT configurable in Node.js!
|
|
184
|
+
// Any configurations set will respond correctly, but underneath retain
|
|
185
|
+
// system / Node.js defaults.
|
|
186
|
+
keepAliveInterval: 1_000_000_000n,
|
|
187
|
+
keepAliveCount: 10,
|
|
188
|
+
hopLimit: 1,
|
|
189
|
+
|
|
190
|
+
// For sendBufferSize and receiveBufferSize we can at least
|
|
191
|
+
// use the system defaults, but still we can't support setting them.
|
|
192
|
+
sendBufferSize: undefined,
|
|
193
|
+
receiveBufferSize: undefined,
|
|
194
|
+
};
|
|
195
|
+
/**
|
|
196
|
+
* @param {IpAddressFamily} addressFamily
|
|
197
|
+
* @param {number} id
|
|
198
|
+
* @returns {TcpSocket}
|
|
199
|
+
*/
|
|
200
|
+
static _create(addressFamily, id) {
|
|
201
|
+
const socket = new TcpSocket();
|
|
202
|
+
socket.#id = id;
|
|
203
|
+
socket.#family = addressFamily;
|
|
204
|
+
socket.#finalizer = registerDispose(socket, null, id, socketTcpDispose);
|
|
205
|
+
return socket;
|
|
206
|
+
}
|
|
207
|
+
startBind(network, localAddress) {
|
|
208
|
+
if (!mayTcp(network)) throw "access-denied";
|
|
209
|
+
ioCall(SOCKET_TCP_BIND_START, this.#id, {
|
|
210
|
+
localAddress,
|
|
211
|
+
family: this.#family,
|
|
212
|
+
});
|
|
213
|
+
this.#network = network;
|
|
214
|
+
}
|
|
215
|
+
finishBind() {
|
|
216
|
+
ioCall(SOCKET_TCP_BIND_FINISH, this.#id, null);
|
|
217
|
+
}
|
|
218
|
+
startConnect(network, remoteAddress) {
|
|
219
|
+
if (this.#network && network !== this.#network) throw "invalid-argument";
|
|
220
|
+
if (!mayTcp(network)) throw "access-denied";
|
|
221
|
+
ioCall(SOCKET_TCP_CONNECT_START, this.#id, {
|
|
222
|
+
remoteAddress,
|
|
223
|
+
family: this.#family,
|
|
224
|
+
});
|
|
225
|
+
this.#network = network;
|
|
226
|
+
}
|
|
227
|
+
finishConnect() {
|
|
228
|
+
const [inputStreamId, outputStreamId] = ioCall(
|
|
229
|
+
SOCKET_TCP_CONNECT_FINISH,
|
|
230
|
+
this.#id,
|
|
231
|
+
null
|
|
232
|
+
);
|
|
233
|
+
return [
|
|
234
|
+
inputStreamCreate(SOCKET_TCP, inputStreamId),
|
|
235
|
+
outputStreamCreate(SOCKET_TCP, outputStreamId),
|
|
236
|
+
];
|
|
237
|
+
}
|
|
238
|
+
startListen() {
|
|
239
|
+
if (!mayTcp(this.#network)) throw "access-denied";
|
|
240
|
+
ioCall(SOCKET_TCP_LISTEN_START, this.#id, null);
|
|
241
|
+
}
|
|
242
|
+
finishListen() {
|
|
243
|
+
ioCall(SOCKET_TCP_LISTEN_FINISH, this.#id, null);
|
|
244
|
+
}
|
|
245
|
+
accept() {
|
|
246
|
+
if (!mayTcp(this.#network)) throw "access-denied";
|
|
247
|
+
const [socketId, inputStreamId, outputStreamId] = ioCall(
|
|
248
|
+
SOCKET_TCP_ACCEPT,
|
|
249
|
+
this.#id,
|
|
250
|
+
null
|
|
251
|
+
);
|
|
252
|
+
const socket = tcpSocketCreate(this.#family, socketId);
|
|
253
|
+
Object.assign(socket.#options, this.#options);
|
|
254
|
+
return [
|
|
255
|
+
socket,
|
|
256
|
+
inputStreamCreate(SOCKET_TCP, inputStreamId),
|
|
257
|
+
outputStreamCreate(SOCKET_TCP, outputStreamId),
|
|
258
|
+
];
|
|
259
|
+
}
|
|
260
|
+
localAddress() {
|
|
261
|
+
return ioCall(SOCKET_TCP_GET_LOCAL_ADDRESS, this.#id, null);
|
|
262
|
+
}
|
|
263
|
+
remoteAddress() {
|
|
264
|
+
return ioCall(SOCKET_TCP_GET_REMOTE_ADDRESS, this.#id, null);
|
|
265
|
+
}
|
|
266
|
+
isListening() {
|
|
267
|
+
return ioCall(SOCKET_TCP_IS_LISTENING, this.#id, null);
|
|
268
|
+
}
|
|
269
|
+
addressFamily() {
|
|
270
|
+
return this.#family;
|
|
271
|
+
}
|
|
272
|
+
setListenBacklogSize(value) {
|
|
273
|
+
if (value === 0n) throw "invalid-argument";
|
|
274
|
+
ioCall(SOCKET_TCP_SET_LISTEN_BACKLOG_SIZE, this.#id, value);
|
|
275
|
+
}
|
|
276
|
+
keepAliveEnabled() {
|
|
277
|
+
return this.#options.keepAlive;
|
|
278
|
+
}
|
|
279
|
+
setKeepAliveEnabled(value) {
|
|
280
|
+
this.#options.keepAlive = value;
|
|
281
|
+
ioCall(SOCKET_TCP_SET_KEEP_ALIVE, this.#id, {
|
|
282
|
+
keepAlive: value,
|
|
283
|
+
keepAliveIdleTime: this.#options.keepAliveIdleTime,
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
keepAliveIdleTime() {
|
|
287
|
+
return this.#options.keepAliveIdleTime;
|
|
288
|
+
}
|
|
289
|
+
setKeepAliveIdleTime(value) {
|
|
290
|
+
if (value < 1n) throw "invalid-argument";
|
|
291
|
+
if (value < 1_000_000_000n) value = 1_000_000_000n;
|
|
292
|
+
if (value !== this.#options.keepAliveIdleTime) {
|
|
293
|
+
this.#options.keepAliveIdleTime = value;
|
|
294
|
+
if (this.#options.keepAlive) {
|
|
295
|
+
ioCall(SOCKET_TCP_SET_KEEP_ALIVE, this.#id, {
|
|
296
|
+
keepAlive: true,
|
|
297
|
+
keepAliveIdleTime: this.#options.keepAliveIdleTime,
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
keepAliveInterval() {
|
|
303
|
+
return this.#options.keepAliveInterval;
|
|
304
|
+
}
|
|
305
|
+
setKeepAliveInterval(value) {
|
|
306
|
+
if (value < 1n) throw "invalid-argument";
|
|
307
|
+
this.#options.keepAliveInterval = value;
|
|
308
|
+
}
|
|
309
|
+
keepAliveCount() {
|
|
310
|
+
return this.#options.keepAliveCount;
|
|
311
|
+
}
|
|
312
|
+
setKeepAliveCount(value) {
|
|
313
|
+
if (value < 1) throw "invalid-argument";
|
|
314
|
+
this.#options.keepAliveCount = value;
|
|
315
|
+
}
|
|
316
|
+
hopLimit() {
|
|
317
|
+
return this.#options.hopLimit;
|
|
318
|
+
}
|
|
319
|
+
setHopLimit(value) {
|
|
320
|
+
if (value < 1) throw "invalid-argument";
|
|
321
|
+
this.#options.hopLimit = value;
|
|
322
|
+
}
|
|
323
|
+
receiveBufferSize() {
|
|
324
|
+
if (!this.#options.receiveBufferSize)
|
|
325
|
+
this.#options.receiveBufferSize = ioCall(
|
|
326
|
+
SOCKET_GET_DEFAULT_RECEIVE_BUFFER_SIZE,
|
|
327
|
+
null,
|
|
328
|
+
null
|
|
329
|
+
);
|
|
330
|
+
return this.#options.receiveBufferSize;
|
|
331
|
+
}
|
|
332
|
+
setReceiveBufferSize(value) {
|
|
333
|
+
if (value === 0n) throw "invalid-argument";
|
|
334
|
+
this.#options.receiveBufferSize = value;
|
|
335
|
+
}
|
|
336
|
+
sendBufferSize() {
|
|
337
|
+
if (!this.#options.sendBufferSize)
|
|
338
|
+
this.#options.sendBufferSize = ioCall(
|
|
339
|
+
SOCKET_GET_DEFAULT_SEND_BUFFER_SIZE,
|
|
340
|
+
null,
|
|
341
|
+
null
|
|
342
|
+
);
|
|
343
|
+
return this.#options.sendBufferSize;
|
|
344
|
+
}
|
|
345
|
+
setSendBufferSize(value) {
|
|
346
|
+
if (value === 0n) throw "invalid-argument";
|
|
347
|
+
this.#options.sendBufferSize = value;
|
|
348
|
+
}
|
|
349
|
+
subscribe() {
|
|
350
|
+
return pollableCreate(ioCall(SOCKET_TCP_SUBSCRIBE, this.#id, null), this);
|
|
351
|
+
}
|
|
352
|
+
shutdown(shutdownType) {
|
|
353
|
+
ioCall(SOCKET_TCP_SHUTDOWN, this.#id, shutdownType);
|
|
354
|
+
}
|
|
355
|
+
[symbolDispose]() {
|
|
356
|
+
if (this.#finalizer) {
|
|
357
|
+
earlyDispose(this.#finalizer);
|
|
358
|
+
this.#finalizer = null;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
function socketTcpDispose(id) {
|
|
364
|
+
ioCall(SOCKET_TCP_DISPOSE, id, null);
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const tcpSocketCreate = TcpSocket._create;
|
|
368
|
+
delete TcpSocket._create;
|
|
369
|
+
|
|
370
|
+
export const tcpCreateSocket = {
|
|
371
|
+
createTcpSocket(addressFamily) {
|
|
372
|
+
if (addressFamily !== "ipv4" && addressFamily !== "ipv6")
|
|
373
|
+
throw "not-supported";
|
|
374
|
+
return tcpSocketCreate(
|
|
375
|
+
addressFamily,
|
|
376
|
+
ioCall(SOCKET_TCP_CREATE_HANDLE, null, null)
|
|
377
|
+
);
|
|
378
|
+
},
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
export const tcp = {
|
|
382
|
+
TcpSocket,
|
|
383
|
+
};
|
|
384
|
+
|
|
385
|
+
class UdpSocket {
|
|
386
|
+
#id;
|
|
387
|
+
#network;
|
|
388
|
+
#family;
|
|
389
|
+
#finalizer;
|
|
390
|
+
static _create(addressFamily) {
|
|
391
|
+
if (addressFamily !== "ipv4" && addressFamily !== "ipv6")
|
|
392
|
+
throw "not-supported";
|
|
393
|
+
const socket = new UdpSocket();
|
|
394
|
+
socket.#id = ioCall(SOCKET_UDP_CREATE_HANDLE, null, {
|
|
395
|
+
family: addressFamily,
|
|
396
|
+
// we always set the unicastHopLimit, because there is no
|
|
397
|
+
// getter but only a setter for this in Node.js, so it is the
|
|
398
|
+
// only way to guarantee the consistent value
|
|
399
|
+
unicastHopLimit: 64,
|
|
400
|
+
});
|
|
401
|
+
socket.#family = addressFamily;
|
|
402
|
+
socket.#finalizer = registerDispose(
|
|
403
|
+
socket,
|
|
404
|
+
null,
|
|
405
|
+
socket.#id,
|
|
406
|
+
socketUdpDispose
|
|
407
|
+
);
|
|
408
|
+
return socket;
|
|
409
|
+
}
|
|
410
|
+
startBind(network, localAddress) {
|
|
411
|
+
if (!mayUdp(network)) throw "access-denied";
|
|
412
|
+
ioCall(SOCKET_UDP_BIND_START, this.#id, {
|
|
413
|
+
localAddress,
|
|
414
|
+
family: this.#family,
|
|
415
|
+
});
|
|
416
|
+
this.#network = network;
|
|
417
|
+
}
|
|
418
|
+
finishBind() {
|
|
419
|
+
ioCall(SOCKET_UDP_BIND_FINISH, this.#id, null);
|
|
420
|
+
}
|
|
421
|
+
stream(remoteAddress) {
|
|
422
|
+
if (!mayUdp(this.#network)) throw "access-denied";
|
|
423
|
+
const [incomingDatagramStreamId, outgoingDatagramStreamId] = ioCall(
|
|
424
|
+
SOCKET_UDP_STREAM,
|
|
425
|
+
this.#id,
|
|
426
|
+
remoteAddress
|
|
427
|
+
);
|
|
428
|
+
return [
|
|
429
|
+
incomingDatagramStreamCreate(incomingDatagramStreamId),
|
|
430
|
+
outgoingDatagramStreamCreate(outgoingDatagramStreamId),
|
|
431
|
+
];
|
|
432
|
+
}
|
|
433
|
+
localAddress() {
|
|
434
|
+
return ioCall(SOCKET_UDP_GET_LOCAL_ADDRESS, this.#id);
|
|
435
|
+
}
|
|
436
|
+
remoteAddress() {
|
|
437
|
+
return ioCall(SOCKET_UDP_GET_REMOTE_ADDRESS, this.#id);
|
|
438
|
+
}
|
|
439
|
+
addressFamily() {
|
|
440
|
+
return this.#family;
|
|
441
|
+
}
|
|
442
|
+
unicastHopLimit() {
|
|
443
|
+
return ioCall(SOCKET_UDP_GET_UNICAST_HOP_LIMIT, this.#id);
|
|
444
|
+
}
|
|
445
|
+
setUnicastHopLimit(value) {
|
|
446
|
+
if (value < 1) throw "invalid-argument";
|
|
447
|
+
ioCall(SOCKET_UDP_SET_UNICAST_HOP_LIMIT, this.#id, value);
|
|
448
|
+
}
|
|
449
|
+
receiveBufferSize() {
|
|
450
|
+
return ioCall(SOCKET_UDP_GET_RECEIVE_BUFFER_SIZE, this.#id);
|
|
451
|
+
}
|
|
452
|
+
setReceiveBufferSize(value) {
|
|
453
|
+
if (value === 0n) throw "invalid-argument";
|
|
454
|
+
ioCall(SOCKET_UDP_SET_RECEIVE_BUFFER_SIZE, this.#id, value);
|
|
455
|
+
}
|
|
456
|
+
sendBufferSize() {
|
|
457
|
+
return ioCall(SOCKET_UDP_GET_SEND_BUFFER_SIZE, this.#id);
|
|
458
|
+
}
|
|
459
|
+
setSendBufferSize(value) {
|
|
460
|
+
if (value === 0n) throw "invalid-argument";
|
|
461
|
+
ioCall(SOCKET_UDP_SET_SEND_BUFFER_SIZE, this.#id, value);
|
|
462
|
+
}
|
|
463
|
+
subscribe() {
|
|
464
|
+
return pollableCreate(ioCall(SOCKET_UDP_SUBSCRIBE, this.#id, null), this);
|
|
465
|
+
}
|
|
466
|
+
[symbolDispose]() {
|
|
467
|
+
if (this.#finalizer) {
|
|
468
|
+
earlyDispose(this.#finalizer);
|
|
469
|
+
this.#finalizer = null;
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
function socketUdpDispose(id) {
|
|
475
|
+
ioCall(SOCKET_UDP_DISPOSE, id, null);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
const createUdpSocket = UdpSocket._create;
|
|
479
|
+
delete UdpSocket._create;
|
|
480
|
+
|
|
481
|
+
class IncomingDatagramStream {
|
|
482
|
+
#id;
|
|
483
|
+
#finalizer;
|
|
484
|
+
static _create(id) {
|
|
485
|
+
const stream = new IncomingDatagramStream();
|
|
486
|
+
stream.#id = id;
|
|
487
|
+
stream.#finalizer = registerDispose(
|
|
488
|
+
stream,
|
|
489
|
+
null,
|
|
490
|
+
id,
|
|
491
|
+
incomingDatagramStreamDispose
|
|
492
|
+
);
|
|
493
|
+
return stream;
|
|
494
|
+
}
|
|
495
|
+
receive(maxResults) {
|
|
496
|
+
return ioCall(
|
|
497
|
+
SOCKET_INCOMING_DATAGRAM_STREAM_RECEIVE,
|
|
498
|
+
this.#id,
|
|
499
|
+
maxResults
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
subscribe() {
|
|
503
|
+
return pollableCreate(
|
|
504
|
+
ioCall(SOCKET_DATAGRAM_STREAM_SUBSCRIBE, this.#id, null),
|
|
505
|
+
this
|
|
506
|
+
);
|
|
507
|
+
}
|
|
508
|
+
[symbolDispose]() {
|
|
509
|
+
if (this.#finalizer) {
|
|
510
|
+
earlyDispose(this.#finalizer);
|
|
511
|
+
this.#finalizer = null;
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
function incomingDatagramStreamDispose(id) {
|
|
517
|
+
ioCall(SOCKET_DATAGRAM_STREAM_DISPOSE, id, null);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
const incomingDatagramStreamCreate = IncomingDatagramStream._create;
|
|
521
|
+
delete IncomingDatagramStream._create;
|
|
522
|
+
|
|
523
|
+
class OutgoingDatagramStream {
|
|
524
|
+
#id = 0;
|
|
525
|
+
#finalizer;
|
|
526
|
+
static _create(id) {
|
|
527
|
+
const stream = new OutgoingDatagramStream();
|
|
528
|
+
stream.#id = id;
|
|
529
|
+
stream.#finalizer = registerDispose(
|
|
530
|
+
stream,
|
|
531
|
+
null,
|
|
532
|
+
id,
|
|
533
|
+
outgoingDatagramStreamDispose
|
|
534
|
+
);
|
|
535
|
+
return stream;
|
|
536
|
+
}
|
|
537
|
+
checkSend() {
|
|
538
|
+
return ioCall(SOCKET_OUTGOING_DATAGRAM_STREAM_CHECK_SEND, this.#id, null);
|
|
539
|
+
}
|
|
540
|
+
send(datagrams) {
|
|
541
|
+
return ioCall(SOCKET_OUTGOING_DATAGRAM_STREAM_SEND, this.#id, datagrams);
|
|
542
|
+
}
|
|
543
|
+
subscribe() {
|
|
544
|
+
return pollableCreate(
|
|
545
|
+
ioCall(SOCKET_DATAGRAM_STREAM_SUBSCRIBE, this.#id, null),
|
|
546
|
+
this
|
|
547
|
+
);
|
|
548
|
+
}
|
|
549
|
+
[symbolDispose]() {
|
|
550
|
+
if (this.#finalizer) {
|
|
551
|
+
earlyDispose(this.#finalizer);
|
|
552
|
+
this.#finalizer = null;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
function outgoingDatagramStreamDispose(id) {
|
|
557
|
+
ioCall(SOCKET_DATAGRAM_STREAM_DISPOSE, id, null);
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
const outgoingDatagramStreamCreate = OutgoingDatagramStream._create;
|
|
561
|
+
delete OutgoingDatagramStream._create;
|
|
562
|
+
|
|
563
|
+
export const udpCreateSocket = {
|
|
564
|
+
createUdpSocket,
|
|
565
|
+
};
|
|
566
|
+
|
|
567
|
+
export const udp = {
|
|
568
|
+
UdpSocket,
|
|
569
|
+
OutgoingDatagramStream,
|
|
570
|
+
IncomingDatagramStream,
|
|
571
|
+
};
|
package/lib/synckit/index.js
CHANGED
|
@@ -33,7 +33,6 @@ import {
|
|
|
33
33
|
} from "node:worker_threads";
|
|
34
34
|
|
|
35
35
|
const DEFAULT_WORKER_BUFFER_SIZE = 1024;
|
|
36
|
-
const syncFnCache = new Map();
|
|
37
36
|
|
|
38
37
|
function extractProperties(object) {
|
|
39
38
|
if (object && typeof object === "object") {
|
|
@@ -45,61 +44,45 @@ function extractProperties(object) {
|
|
|
45
44
|
}
|
|
46
45
|
}
|
|
47
46
|
|
|
48
|
-
|
|
47
|
+
const CALL_TIMEOUT = undefined;
|
|
48
|
+
|
|
49
|
+
export function createSyncFn(workerPath, debug, callbackHandler) {
|
|
49
50
|
if (!path.isAbsolute(workerPath)) {
|
|
50
51
|
throw new Error("`workerPath` must be absolute");
|
|
51
52
|
}
|
|
52
|
-
const cachedSyncFn = syncFnCache.get(workerPath);
|
|
53
|
-
if (cachedSyncFn) {
|
|
54
|
-
return cachedSyncFn;
|
|
55
|
-
}
|
|
56
|
-
const syncFn = startWorkerThread(
|
|
57
|
-
workerPath,
|
|
58
|
-
typeof bufferSizeOrOptions === "number"
|
|
59
|
-
? { bufferSize: bufferSizeOrOptions, timeout }
|
|
60
|
-
: bufferSizeOrOptions
|
|
61
|
-
);
|
|
62
|
-
syncFnCache.set(workerPath, syncFn);
|
|
63
|
-
return syncFn;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
function startWorkerThread(
|
|
67
|
-
workerPath,
|
|
68
|
-
{
|
|
69
|
-
bufferSize = DEFAULT_WORKER_BUFFER_SIZE,
|
|
70
|
-
timeout = undefined,
|
|
71
|
-
execArgv = [],
|
|
72
|
-
} = {}
|
|
73
|
-
) {
|
|
74
53
|
const { port1: mainPort, port2: workerPort } = new MessageChannel();
|
|
75
54
|
const worker = new Worker(workerPath, {
|
|
76
|
-
workerData: { workerPort },
|
|
55
|
+
workerData: { workerPort, debug },
|
|
77
56
|
transferList: [workerPort],
|
|
78
|
-
execArgv:
|
|
57
|
+
execArgv: []
|
|
58
|
+
});
|
|
59
|
+
worker.on('message', ({ type, id, payload }) => {
|
|
60
|
+
if (!type)
|
|
61
|
+
throw new Error('Internal error: Expected a type of a worker callback');
|
|
62
|
+
callbackHandler(type, id, payload);
|
|
79
63
|
});
|
|
80
64
|
let nextID = 0;
|
|
81
65
|
const syncFn = (...args) => {
|
|
82
|
-
const
|
|
83
|
-
const sharedBuffer = new SharedArrayBuffer(
|
|
66
|
+
const cid = nextID++;
|
|
67
|
+
const sharedBuffer = new SharedArrayBuffer(DEFAULT_WORKER_BUFFER_SIZE);
|
|
84
68
|
const sharedBufferView = new Int32Array(sharedBuffer);
|
|
85
|
-
const msg = { sharedBuffer,
|
|
69
|
+
const msg = { sharedBuffer, cid, args };
|
|
86
70
|
worker.postMessage(msg);
|
|
87
|
-
const status = Atomics.wait(sharedBufferView, 0, 0,
|
|
71
|
+
const status = Atomics.wait(sharedBufferView, 0, 0, CALL_TIMEOUT);
|
|
88
72
|
if (!["ok", "not-equal"].includes(status)) {
|
|
89
73
|
throw new Error("Internal error: Atomics.wait() failed: " + status);
|
|
90
74
|
}
|
|
91
75
|
const {
|
|
92
|
-
|
|
76
|
+
cid: cid2,
|
|
93
77
|
result,
|
|
94
78
|
error,
|
|
95
79
|
properties,
|
|
96
80
|
} = receiveMessageOnPort(mainPort).message;
|
|
97
|
-
if (
|
|
98
|
-
throw new Error(`Internal error: Expected id ${
|
|
81
|
+
if (cid !== cid2) {
|
|
82
|
+
throw new Error(`Internal error: Expected id ${cid} but got id ${cid2}`);
|
|
99
83
|
}
|
|
100
84
|
if (error) {
|
|
101
|
-
if (error instanceof Error)
|
|
102
|
-
throw Object.assign(error, properties);
|
|
85
|
+
if (error instanceof Error) throw Object.assign(error, properties);
|
|
103
86
|
throw error;
|
|
104
87
|
}
|
|
105
88
|
return result;
|
|
@@ -112,16 +95,16 @@ export function runAsWorker(fn) {
|
|
|
112
95
|
if (!workerData) {
|
|
113
96
|
return;
|
|
114
97
|
}
|
|
115
|
-
const { workerPort } = workerData;
|
|
98
|
+
const { workerPort, debug } = workerData;
|
|
116
99
|
try {
|
|
117
|
-
parentPort.on("message", ({ sharedBuffer,
|
|
100
|
+
parentPort.on("message", ({ sharedBuffer, cid, args }) => {
|
|
118
101
|
(async () => {
|
|
119
102
|
const sharedBufferView = new Int32Array(sharedBuffer);
|
|
120
103
|
let msg;
|
|
121
104
|
try {
|
|
122
|
-
msg = {
|
|
105
|
+
msg = { cid, result: await fn(...args) };
|
|
123
106
|
} catch (error) {
|
|
124
|
-
msg = {
|
|
107
|
+
msg = { cid, error, properties: extractProperties(error) };
|
|
125
108
|
}
|
|
126
109
|
workerPort.postMessage(msg);
|
|
127
110
|
Atomics.add(sharedBufferView, 0, 1);
|
|
@@ -129,10 +112,10 @@ export function runAsWorker(fn) {
|
|
|
129
112
|
})();
|
|
130
113
|
});
|
|
131
114
|
} catch (error) {
|
|
132
|
-
parentPort.on("message", ({ sharedBuffer,
|
|
115
|
+
parentPort.on("message", ({ sharedBuffer, cid }) => {
|
|
133
116
|
const sharedBufferView = new Int32Array(sharedBuffer);
|
|
134
117
|
workerPort.postMessage({
|
|
135
|
-
|
|
118
|
+
cid,
|
|
136
119
|
error,
|
|
137
120
|
properties: extractProperties(error),
|
|
138
121
|
});
|
|
@@ -140,4 +123,5 @@ export function runAsWorker(fn) {
|
|
|
140
123
|
Atomics.notify(sharedBufferView, 0);
|
|
141
124
|
});
|
|
142
125
|
}
|
|
126
|
+
return debug;
|
|
143
127
|
}
|