@bytecodealliance/preview3-shim 0.3.2 → 0.4.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.
|
@@ -255,7 +255,13 @@ export class TcpSocket {
|
|
|
255
255
|
}
|
|
256
256
|
let stream;
|
|
257
257
|
try {
|
|
258
|
-
|
|
258
|
+
// A remote error arrives from the TCP worker through a MessagePort. Yield
|
|
259
|
+
// after each chunk so a guest producer that completes writes immediately
|
|
260
|
+
// cannot starve that error (and its stream cancellation) indefinitely.
|
|
261
|
+
stream = readableByteStreamFromReader(data, {
|
|
262
|
+
name: "tcp send data",
|
|
263
|
+
yieldAfterChunk: true,
|
|
264
|
+
});
|
|
259
265
|
}
|
|
260
266
|
catch (error) {
|
|
261
267
|
if (error instanceof TypeError) {
|
package/dist/nodejs/stream.d.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
export declare const DEFAULT_BYTE_STREAM_CHUNK_SIZE: number;
|
|
2
2
|
declare const symbolDispose: symbol;
|
|
3
|
+
interface ReadableByteStreamOptions {
|
|
4
|
+
chunkSize?: number;
|
|
5
|
+
name?: string;
|
|
6
|
+
yieldAfterChunk?: boolean;
|
|
7
|
+
}
|
|
3
8
|
/**
|
|
4
9
|
* Creates a transferable ReadableStream from an async iterator.
|
|
5
10
|
*
|
|
@@ -22,9 +27,10 @@ export declare function readableStreamFromIterator(iterator: any, name?: string)
|
|
|
22
27
|
* @param {object} [opts={}] - Optional adapter settings.
|
|
23
28
|
* @param {number} [opts.chunkSize=DEFAULT_BYTE_STREAM_CHUNK_SIZE] - Maximum bytes to request per generated `read()` call.
|
|
24
29
|
* @param {string} [opts.name="stream reader"] - Reader name used in error messages.
|
|
30
|
+
* @param {boolean} [opts.yieldAfterChunk=false] - Yield one event-loop turn after each chunk.
|
|
25
31
|
* @returns {ReadableStream<Uint8Array>} A transferable stream of byte chunks.
|
|
26
32
|
*/
|
|
27
|
-
export declare function readableByteStreamFromReader(reader: any, opts?:
|
|
33
|
+
export declare function readableByteStreamFromReader(reader: any, opts?: ReadableByteStreamOptions): ReadableStream<any>;
|
|
28
34
|
export declare function _byteChunk(value: any): any;
|
|
29
35
|
/**
|
|
30
36
|
* Creates a bidirectional stream with separate reader and writer interfaces.
|
package/dist/nodejs/stream.js
CHANGED
|
@@ -46,6 +46,7 @@ export function readableStreamFromIterator(iterator, name = "iterator") {
|
|
|
46
46
|
* @param {object} [opts={}] - Optional adapter settings.
|
|
47
47
|
* @param {number} [opts.chunkSize=DEFAULT_BYTE_STREAM_CHUNK_SIZE] - Maximum bytes to request per generated `read()` call.
|
|
48
48
|
* @param {string} [opts.name="stream reader"] - Reader name used in error messages.
|
|
49
|
+
* @param {boolean} [opts.yieldAfterChunk=false] - Yield one event-loop turn after each chunk.
|
|
49
50
|
* @returns {ReadableStream<Uint8Array>} A transferable stream of byte chunks.
|
|
50
51
|
*/
|
|
51
52
|
export function readableByteStreamFromReader(reader, opts = {}) {
|
|
@@ -58,6 +59,9 @@ export function readableByteStreamFromReader(reader, opts = {}) {
|
|
|
58
59
|
return;
|
|
59
60
|
}
|
|
60
61
|
controller.enqueue(_byteChunk(value));
|
|
62
|
+
if (opts.yieldAfterChunk) {
|
|
63
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
64
|
+
}
|
|
61
65
|
},
|
|
62
66
|
cancel(reason) {
|
|
63
67
|
return source.cancel?.(reason);
|
|
@@ -3,7 +3,6 @@ import { Readable } from "stream";
|
|
|
3
3
|
import { pipeline } from "stream/promises";
|
|
4
4
|
import { once } from "node:events";
|
|
5
5
|
import { isMainThread, parentPort } from "worker_threads";
|
|
6
|
-
import process from "node:process";
|
|
7
6
|
//#region dist/nodejs/workers/resource-worker.js
|
|
8
7
|
function Router() {
|
|
9
8
|
const _hooks = {
|
|
@@ -255,7 +254,6 @@ var SocketError = class SocketError extends Error {
|
|
|
255
254
|
};
|
|
256
255
|
//#endregion
|
|
257
256
|
//#region dist/nodejs/workers/tcp-worker.js
|
|
258
|
-
const { TCP, constants: TCPConstants } = process.binding("tcp_wrap");
|
|
259
257
|
const sockets = /* @__PURE__ */ new Map();
|
|
260
258
|
let NEXT_SOCKET_ID = 0n;
|
|
261
259
|
Router().beforeAll((msg) => {
|
|
@@ -263,14 +261,15 @@ Router().beforeAll((msg) => {
|
|
|
263
261
|
}).op("tcp-create", handleTcpCreate).op("tcp-bind", handleTcpBind).op("tcp-connect", handleTcpConnect).op("tcp-listen", handleTcpListen).op("tcp-send", handleTcpSend).op("tcp-receive", handleTcpReceive).op("tcp-get-local-address", handleGetLocalAddress).op("tcp-get-remote-address", handleGetRemoteAddress).op("tcp-set-listen-backlog-size", handleTcpSetBacklogSize).op("tcp-set-keep-alive", handleTcpSetKeepAlive).op("tcp-recv-buffer-size", handleRecvBufferSize).op("tcp-send-buffer-size", handleSendBufferSize).op("tcp-dispose", handleTcpDispose);
|
|
264
262
|
function handleTcpCreate({ family }) {
|
|
265
263
|
const socketId = NEXT_SOCKET_ID++;
|
|
266
|
-
const handle = new TCP(TCPConstants.SOCKET);
|
|
267
264
|
sockets.set(socketId, {
|
|
268
|
-
handle,
|
|
269
265
|
family,
|
|
270
266
|
tcp: null,
|
|
271
267
|
server: null,
|
|
268
|
+
acceptWriter: null,
|
|
272
269
|
backlog: 128,
|
|
273
270
|
localAddress: null,
|
|
271
|
+
keepAliveEnabled: false,
|
|
272
|
+
keepAliveIdleTime: 0,
|
|
274
273
|
disposed: false,
|
|
275
274
|
activeStreams: 0
|
|
276
275
|
});
|
|
@@ -280,74 +279,104 @@ async function handleTcpBind({ socketId, localAddress }) {
|
|
|
280
279
|
const socket = sockets.get(socketId);
|
|
281
280
|
const address = serializeIpAddress(localAddress);
|
|
282
281
|
const port = localAddress.val.port;
|
|
283
|
-
const {
|
|
282
|
+
const { family } = socket;
|
|
284
283
|
if ([...sockets].some(([id, { localAddress: boundAddress }]) => id !== socketId && boundAddress && ipAddressConflict(boundAddress, localAddress))) {
|
|
285
284
|
const err = /* @__PURE__ */ new Error("EADDRINUSE");
|
|
286
285
|
err.code = "EADDRINUSE";
|
|
287
286
|
throw err;
|
|
288
287
|
}
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
288
|
+
const server = socket.server = createTcpServer(socket);
|
|
289
|
+
const onListening = once(server, "listening");
|
|
290
|
+
server.listen({
|
|
291
|
+
host: address,
|
|
292
|
+
port,
|
|
293
|
+
backlog: socket.backlog,
|
|
294
|
+
ipv6Only: family === "ipv6"
|
|
295
295
|
});
|
|
296
|
-
|
|
297
|
-
const
|
|
298
|
-
if (
|
|
299
|
-
socket.localAddress = makeIpAddress(
|
|
296
|
+
await onListening;
|
|
297
|
+
const boundAddress = server.address();
|
|
298
|
+
if (!boundAddress || typeof boundAddress === "string") throw new SocketError("invalid-state");
|
|
299
|
+
socket.localAddress = makeIpAddress(boundAddress.family.toLowerCase(), boundAddress.address, boundAddress.port);
|
|
300
300
|
}
|
|
301
301
|
async function handleTcpConnect({ socketId, remoteAddress }) {
|
|
302
302
|
const socket = sockets.get(socketId);
|
|
303
303
|
const host = serializeIpAddress(remoteAddress);
|
|
304
304
|
const port = remoteAddress.val.port;
|
|
305
|
-
const
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
});
|
|
305
|
+
const localAddress = socket.localAddress;
|
|
306
|
+
await closeTcpServer(socket);
|
|
307
|
+
const tcp = socket.tcp = new Socket({ allowHalfOpen: true });
|
|
308
|
+
tcp.setKeepAlive(socket.keepAliveEnabled, socket.keepAliveIdleTime);
|
|
310
309
|
const onConnect = once(tcp, "connect");
|
|
311
310
|
tcp.connect({
|
|
312
311
|
port,
|
|
313
|
-
host
|
|
312
|
+
host,
|
|
313
|
+
localAddress: localAddress ? serializeIpAddress(localAddress) : void 0,
|
|
314
|
+
localPort: localAddress?.val.port
|
|
314
315
|
});
|
|
315
316
|
await onConnect;
|
|
316
317
|
}
|
|
317
318
|
async function handleTcpListen({ socketId, stream }) {
|
|
318
319
|
const writer = stream.getWriter();
|
|
319
320
|
const socket = sockets.get(socketId);
|
|
320
|
-
const {
|
|
321
|
+
const { backlog, family } = socket;
|
|
322
|
+
socket.acceptWriter = writer;
|
|
323
|
+
let server = socket.server;
|
|
324
|
+
if (!server) {
|
|
325
|
+
server = socket.server = createTcpServer(socket);
|
|
326
|
+
const onListening = once(server, "listening");
|
|
327
|
+
server.listen({
|
|
328
|
+
host: family === "ipv6" ? "::" : "0.0.0.0",
|
|
329
|
+
port: 0,
|
|
330
|
+
backlog,
|
|
331
|
+
ipv6Only: family === "ipv6"
|
|
332
|
+
});
|
|
333
|
+
await onListening;
|
|
334
|
+
}
|
|
335
|
+
const addr = server.address();
|
|
336
|
+
if (addr && typeof addr === "object") socket.localAddress = makeIpAddress(family, addr.address, addr.port);
|
|
337
|
+
}
|
|
338
|
+
function createTcpServer(socket) {
|
|
321
339
|
const server = new Server({
|
|
322
340
|
pauseOnConnect: true,
|
|
323
341
|
allowHalfOpen: true
|
|
324
342
|
});
|
|
325
|
-
const onListening = once(server, "listening");
|
|
326
|
-
server.listen(handle, backlog);
|
|
327
|
-
await onListening;
|
|
328
|
-
const addr = server.address();
|
|
329
|
-
if (addr && typeof addr === "object") socket.localAddress = makeIpAddress(family, addr.address, addr.port);
|
|
330
343
|
server.on("connection", (conn) => {
|
|
344
|
+
const writer = socket.acceptWriter;
|
|
345
|
+
if (!writer) {
|
|
346
|
+
conn.destroy();
|
|
347
|
+
return;
|
|
348
|
+
}
|
|
331
349
|
conn.allowHalfOpen = true;
|
|
350
|
+
conn.setKeepAlive(socket.keepAliveEnabled, socket.keepAliveIdleTime);
|
|
332
351
|
const id = NEXT_SOCKET_ID++;
|
|
333
352
|
sockets.set(id, {
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
backlog,
|
|
353
|
+
family: socket.family,
|
|
354
|
+
backlog: socket.backlog,
|
|
337
355
|
tcp: conn,
|
|
338
356
|
server: null,
|
|
339
|
-
|
|
357
|
+
acceptWriter: null,
|
|
358
|
+
localAddress: makeIpAddress(socket.family, conn.localAddress, conn.localPort),
|
|
359
|
+
keepAliveEnabled: socket.keepAliveEnabled,
|
|
360
|
+
keepAliveIdleTime: socket.keepAliveIdleTime,
|
|
340
361
|
disposed: false,
|
|
341
362
|
activeStreams: 0
|
|
342
363
|
});
|
|
343
364
|
writer.write({
|
|
344
|
-
family,
|
|
365
|
+
family: socket.family,
|
|
345
366
|
socketId: id
|
|
346
367
|
});
|
|
347
368
|
});
|
|
348
|
-
|
|
349
|
-
server.on("
|
|
350
|
-
server
|
|
369
|
+
server.on("error", (err) => socket.acceptWriter?.abort(err));
|
|
370
|
+
server.on("close", () => socket.acceptWriter?.close());
|
|
371
|
+
return server;
|
|
372
|
+
}
|
|
373
|
+
function closeTcpServer(socket) {
|
|
374
|
+
const server = socket.server;
|
|
375
|
+
socket.server = null;
|
|
376
|
+
if (!server) return Promise.resolve();
|
|
377
|
+
return new Promise((resolve, reject) => {
|
|
378
|
+
server.close((err) => err ? reject(err) : resolve());
|
|
379
|
+
});
|
|
351
380
|
}
|
|
352
381
|
async function handleTcpSend({ socketId, stream }) {
|
|
353
382
|
const socket = sockets.get(socketId);
|
|
@@ -422,22 +451,19 @@ function cleanupDisposedSocket(socketId, socket) {
|
|
|
422
451
|
if (!socket.disposed || socket.activeStreams > 0) return;
|
|
423
452
|
if (socket.server) socket.server.close();
|
|
424
453
|
if (socket.tcp) socket.tcp.destroy();
|
|
425
|
-
if (socket.handle) socket.handle.close();
|
|
426
454
|
sockets.delete(socketId);
|
|
427
455
|
}
|
|
428
456
|
async function handleGetLocalAddress({ socketId }) {
|
|
429
457
|
const socket = sockets.get(socketId);
|
|
430
|
-
const
|
|
431
|
-
|
|
432
|
-
if (
|
|
433
|
-
|
|
458
|
+
const address = socket.tcp?.address();
|
|
459
|
+
if (address && typeof address !== "string" && "family" in address) return makeIpAddress(address.family.toLowerCase(), address.address, address.port);
|
|
460
|
+
if (socket.localAddress) return socket.localAddress;
|
|
461
|
+
throw new SocketError("invalid-state");
|
|
434
462
|
}
|
|
435
463
|
async function handleGetRemoteAddress({ socketId }) {
|
|
436
464
|
const socket = sockets.get(socketId);
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
if (code !== 0) throw SocketError.from(-code);
|
|
440
|
-
return makeIpAddress(out.family.toLowerCase(), out.address, out.port);
|
|
465
|
+
if (!socket.tcp?.remoteFamily || !socket.tcp.remoteAddress || !socket.tcp.remotePort) throw new SocketError("invalid-state");
|
|
466
|
+
return makeIpAddress(socket.tcp.remoteFamily.toLowerCase(), socket.tcp.remoteAddress, socket.tcp.remotePort);
|
|
441
467
|
}
|
|
442
468
|
function handleTcpSetBacklogSize({ socketId, value }) {
|
|
443
469
|
const socket = sockets.get(socketId);
|
|
@@ -445,9 +471,9 @@ function handleTcpSetBacklogSize({ socketId, value }) {
|
|
|
445
471
|
}
|
|
446
472
|
async function handleTcpSetKeepAlive({ socketId, keepAliveEnabled, keepAliveIdleTime }) {
|
|
447
473
|
const socket = sockets.get(socketId);
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
474
|
+
socket.keepAliveEnabled = keepAliveEnabled;
|
|
475
|
+
socket.keepAliveIdleTime = Number(keepAliveIdleTime / 1000000000n);
|
|
476
|
+
socket.tcp?.setKeepAlive(socket.keepAliveEnabled, socket.keepAliveIdleTime);
|
|
451
477
|
}
|
|
452
478
|
async function handleRecvBufferSize({ socketId }) {
|
|
453
479
|
const socket = sockets.get(socketId);
|
|
@@ -5,8 +5,6 @@ import { once } from "node:events";
|
|
|
5
5
|
import { Router } from "../workers/resource-worker.js";
|
|
6
6
|
import { serializeIpAddress, makeIpAddress, ipAddressConflict } from "../sockets/address.js";
|
|
7
7
|
import { SocketError } from "../sockets/error.js";
|
|
8
|
-
import process from "node:process";
|
|
9
|
-
const { TCP, constants: TCPConstants } = process.binding("tcp_wrap");
|
|
10
8
|
// Socket instances stored by ID
|
|
11
9
|
const sockets = new Map();
|
|
12
10
|
// Unique IDs for sockets
|
|
@@ -34,14 +32,15 @@ Router()
|
|
|
34
32
|
// Create a new TCP socket
|
|
35
33
|
function handleTcpCreate({ family }) {
|
|
36
34
|
const socketId = NEXT_SOCKET_ID++;
|
|
37
|
-
const handle = new TCP(TCPConstants.SOCKET);
|
|
38
35
|
sockets.set(socketId, {
|
|
39
|
-
handle,
|
|
40
36
|
family,
|
|
41
37
|
tcp: null,
|
|
42
38
|
server: null,
|
|
39
|
+
acceptWriter: null,
|
|
43
40
|
backlog: 128,
|
|
44
41
|
localAddress: null,
|
|
42
|
+
keepAliveEnabled: false,
|
|
43
|
+
keepAliveIdleTime: 0,
|
|
45
44
|
disposed: false,
|
|
46
45
|
activeStreams: 0,
|
|
47
46
|
});
|
|
@@ -52,48 +51,49 @@ async function handleTcpBind({ socketId, localAddress }) {
|
|
|
52
51
|
const socket = sockets.get(socketId);
|
|
53
52
|
const address = serializeIpAddress(localAddress);
|
|
54
53
|
const port = localAddress.val.port;
|
|
55
|
-
const {
|
|
54
|
+
const { family } = socket;
|
|
56
55
|
const hasConflict = [...sockets].some(([id, { localAddress: boundAddress }]) => id !== socketId && boundAddress && ipAddressConflict(boundAddress, localAddress));
|
|
57
56
|
if (hasConflict) {
|
|
58
57
|
const err = new Error("EADDRINUSE");
|
|
59
58
|
err.code = "EADDRINUSE";
|
|
60
59
|
throw err;
|
|
61
60
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
reject(SocketError.from(-code));
|
|
72
|
-
}
|
|
73
|
-
else {
|
|
74
|
-
resolve();
|
|
75
|
-
}
|
|
61
|
+
// node:net has no public standalone TCP bind API. Keep a server open
|
|
62
|
+
// to reserve the endpoint, then reuse it for listen or close it for connect.
|
|
63
|
+
const server = (socket.server = createTcpServer(socket));
|
|
64
|
+
const onListening = once(server, "listening");
|
|
65
|
+
server.listen({
|
|
66
|
+
host: address,
|
|
67
|
+
port,
|
|
68
|
+
backlog: socket.backlog,
|
|
69
|
+
ipv6Only: family === "ipv6",
|
|
76
70
|
});
|
|
77
|
-
|
|
78
|
-
const
|
|
79
|
-
if (
|
|
80
|
-
throw SocketError
|
|
71
|
+
await onListening;
|
|
72
|
+
const boundAddress = server.address();
|
|
73
|
+
if (!boundAddress || typeof boundAddress === "string") {
|
|
74
|
+
throw new SocketError("invalid-state");
|
|
81
75
|
}
|
|
82
|
-
socket.localAddress = makeIpAddress(
|
|
76
|
+
socket.localAddress = makeIpAddress(boundAddress.family.toLowerCase(), boundAddress.address, boundAddress.port);
|
|
83
77
|
}
|
|
84
78
|
// Connect a socket to remote address
|
|
85
79
|
async function handleTcpConnect({ socketId, remoteAddress }) {
|
|
86
80
|
const socket = sockets.get(socketId);
|
|
87
81
|
const host = serializeIpAddress(remoteAddress);
|
|
88
82
|
const port = remoteAddress.val.port;
|
|
83
|
+
const localAddress = socket.localAddress;
|
|
84
|
+
await closeTcpServer(socket);
|
|
89
85
|
const tcp = (socket.tcp = new Socket({
|
|
90
|
-
handle: socket.handle,
|
|
91
|
-
pauseOnCreate: true,
|
|
92
86
|
allowHalfOpen: true,
|
|
93
87
|
}));
|
|
88
|
+
tcp.setKeepAlive(socket.keepAliveEnabled, socket.keepAliveIdleTime);
|
|
94
89
|
// TODO(tandr): Add lookup
|
|
95
90
|
const onConnect = once(tcp, "connect");
|
|
96
|
-
tcp.connect({
|
|
91
|
+
tcp.connect({
|
|
92
|
+
port,
|
|
93
|
+
host,
|
|
94
|
+
localAddress: localAddress ? serializeIpAddress(localAddress) : undefined,
|
|
95
|
+
localPort: localAddress?.val.port,
|
|
96
|
+
});
|
|
97
97
|
// events.once rejects when the emitter produces an error while waiting and
|
|
98
98
|
// removes its temporary listeners after settling. A separate error promise
|
|
99
99
|
// would remain attached after a successful connect and could later reject
|
|
@@ -103,36 +103,68 @@ async function handleTcpConnect({ socketId, remoteAddress }) {
|
|
|
103
103
|
async function handleTcpListen({ socketId, stream }) {
|
|
104
104
|
const writer = stream.getWriter();
|
|
105
105
|
const socket = sockets.get(socketId);
|
|
106
|
-
const {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
106
|
+
const { backlog, family } = socket;
|
|
107
|
+
socket.acceptWriter = writer;
|
|
108
|
+
let server = socket.server;
|
|
109
|
+
if (!server) {
|
|
110
|
+
server = socket.server = createTcpServer(socket);
|
|
111
|
+
const onListening = once(server, "listening");
|
|
112
|
+
server.listen({
|
|
113
|
+
host: family === "ipv6" ? "::" : "0.0.0.0",
|
|
114
|
+
port: 0,
|
|
115
|
+
backlog,
|
|
116
|
+
ipv6Only: family === "ipv6",
|
|
117
|
+
});
|
|
118
|
+
await onListening;
|
|
119
|
+
}
|
|
114
120
|
const addr = server.address();
|
|
115
121
|
if (addr && typeof addr === "object") {
|
|
116
122
|
socket.localAddress = makeIpAddress(family, addr.address, addr.port);
|
|
117
123
|
}
|
|
124
|
+
}
|
|
125
|
+
function createTcpServer(socket) {
|
|
126
|
+
const server = new Server({
|
|
127
|
+
pauseOnConnect: true,
|
|
128
|
+
allowHalfOpen: true,
|
|
129
|
+
});
|
|
118
130
|
server.on("connection", (conn) => {
|
|
131
|
+
const writer = socket.acceptWriter;
|
|
132
|
+
// The reservation is already listening at the OS level, so reject any
|
|
133
|
+
// connections that arrive before the WASI socket enters its listen state.
|
|
134
|
+
if (!writer) {
|
|
135
|
+
conn.destroy();
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
119
138
|
conn.allowHalfOpen = true;
|
|
139
|
+
conn.setKeepAlive(socket.keepAliveEnabled, socket.keepAliveIdleTime);
|
|
120
140
|
const id = NEXT_SOCKET_ID++;
|
|
121
141
|
sockets.set(id, {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
backlog,
|
|
142
|
+
family: socket.family,
|
|
143
|
+
backlog: socket.backlog,
|
|
125
144
|
tcp: conn,
|
|
126
145
|
server: null,
|
|
127
|
-
|
|
146
|
+
acceptWriter: null,
|
|
147
|
+
localAddress: makeIpAddress(socket.family, conn.localAddress, conn.localPort),
|
|
148
|
+
keepAliveEnabled: socket.keepAliveEnabled,
|
|
149
|
+
keepAliveIdleTime: socket.keepAliveIdleTime,
|
|
128
150
|
disposed: false,
|
|
129
151
|
activeStreams: 0,
|
|
130
152
|
});
|
|
131
|
-
writer.write({ family, socketId: id });
|
|
153
|
+
writer.write({ family: socket.family, socketId: id });
|
|
154
|
+
});
|
|
155
|
+
server.on("error", (err) => socket.acceptWriter?.abort(err));
|
|
156
|
+
server.on("close", () => socket.acceptWriter?.close());
|
|
157
|
+
return server;
|
|
158
|
+
}
|
|
159
|
+
function closeTcpServer(socket) {
|
|
160
|
+
const server = socket.server;
|
|
161
|
+
socket.server = null;
|
|
162
|
+
if (!server) {
|
|
163
|
+
return Promise.resolve();
|
|
164
|
+
}
|
|
165
|
+
return new Promise((resolve, reject) => {
|
|
166
|
+
server.close((err) => (err ? reject(err) : resolve()));
|
|
132
167
|
});
|
|
133
|
-
socket.server = server;
|
|
134
|
-
server.on("error", (err) => stream.abort(err));
|
|
135
|
-
server.on("close", () => writer.close());
|
|
136
168
|
}
|
|
137
169
|
async function handleTcpSend({ socketId, stream }) {
|
|
138
170
|
const socket = sockets.get(socketId);
|
|
@@ -229,28 +261,25 @@ function cleanupDisposedSocket(socketId, socket) {
|
|
|
229
261
|
if (socket.tcp) {
|
|
230
262
|
socket.tcp.destroy();
|
|
231
263
|
}
|
|
232
|
-
if (socket.handle) {
|
|
233
|
-
socket.handle.close();
|
|
234
|
-
}
|
|
235
264
|
sockets.delete(socketId);
|
|
236
265
|
}
|
|
237
266
|
async function handleGetLocalAddress({ socketId }) {
|
|
238
267
|
const socket = sockets.get(socketId);
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
268
|
+
const address = socket.tcp?.address();
|
|
269
|
+
if (address && typeof address !== "string" && "family" in address) {
|
|
270
|
+
return makeIpAddress(address.family.toLowerCase(), address.address, address.port);
|
|
271
|
+
}
|
|
272
|
+
if (socket.localAddress) {
|
|
273
|
+
return socket.localAddress;
|
|
243
274
|
}
|
|
244
|
-
|
|
275
|
+
throw new SocketError("invalid-state");
|
|
245
276
|
}
|
|
246
277
|
async function handleGetRemoteAddress({ socketId }) {
|
|
247
278
|
const socket = sockets.get(socketId);
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
if (code !== 0) {
|
|
251
|
-
throw SocketError.from(-code);
|
|
279
|
+
if (!socket.tcp?.remoteFamily || !socket.tcp.remoteAddress || !socket.tcp.remotePort) {
|
|
280
|
+
throw new SocketError("invalid-state");
|
|
252
281
|
}
|
|
253
|
-
return makeIpAddress(
|
|
282
|
+
return makeIpAddress(socket.tcp.remoteFamily.toLowerCase(), socket.tcp.remoteAddress, socket.tcp.remotePort);
|
|
254
283
|
}
|
|
255
284
|
function handleTcpSetBacklogSize({ socketId, value }) {
|
|
256
285
|
const socket = sockets.get(socketId);
|
|
@@ -258,11 +287,9 @@ function handleTcpSetBacklogSize({ socketId, value }) {
|
|
|
258
287
|
}
|
|
259
288
|
async function handleTcpSetKeepAlive({ socketId, keepAliveEnabled, keepAliveIdleTime }) {
|
|
260
289
|
const socket = sockets.get(socketId);
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
throw SocketError.from(-code);
|
|
265
|
-
}
|
|
290
|
+
socket.keepAliveEnabled = keepAliveEnabled;
|
|
291
|
+
socket.keepAliveIdleTime = Number(keepAliveIdleTime / 1000000000n);
|
|
292
|
+
socket.tcp?.setKeepAlive(socket.keepAliveEnabled, socket.keepAliveIdleTime);
|
|
266
293
|
}
|
|
267
294
|
async function handleRecvBufferSize({ socketId }) {
|
|
268
295
|
const socket = sockets.get(socketId);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bytecodealliance/preview3-shim",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "WASI Preview3 shim for JS environments",
|
|
5
5
|
"homepage": "https://github.com/bytecodealliance/jco/blob/main/packages/preview3-shim/#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
}
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@bytecodealliance/preview2-shim": "^0.
|
|
51
|
+
"@bytecodealliance/preview2-shim": "^0.21.0"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@types/node": "^24.12.4",
|