@bytecodealliance/preview3-shim 0.1.1 → 0.2.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/nodejs/cli.d.ts +51 -0
- package/dist/nodejs/cli.js +106 -0
- package/dist/nodejs/clocks.d.ts +55 -0
- package/dist/nodejs/clocks.js +83 -0
- package/dist/nodejs/filesystem/descriptor.d.ts +443 -0
- package/dist/nodejs/filesystem/descriptor.js +1010 -0
- package/dist/nodejs/filesystem/error.d.ts +61 -0
- package/dist/nodejs/filesystem/error.js +86 -0
- package/dist/nodejs/filesystem/utils.d.ts +8 -0
- package/dist/nodejs/filesystem/utils.js +25 -0
- package/dist/nodejs/filesystem.js +2 -0
- package/dist/nodejs/finalization.d.ts +2 -0
- package/{lib → dist}/nodejs/finalization.js +15 -21
- package/dist/nodejs/future.d.ts +98 -0
- package/dist/nodejs/future.js +176 -0
- package/dist/nodejs/http/client.d.ts +22 -0
- package/dist/nodejs/http/client.js +138 -0
- package/dist/nodejs/http/error.d.ts +18 -0
- package/dist/nodejs/http/error.js +62 -0
- package/dist/nodejs/http/fields.d.ts +144 -0
- package/dist/nodejs/http/fields.js +327 -0
- package/dist/nodejs/http/request.d.ts +256 -0
- package/dist/nodejs/http/request.js +606 -0
- package/dist/nodejs/http/response.d.ts +82 -0
- package/dist/nodejs/http/response.js +202 -0
- package/dist/nodejs/http/server.d.ts +13 -0
- package/dist/nodejs/http/server.js +127 -0
- package/dist/nodejs/http.d.ts +19 -0
- package/{lib → dist}/nodejs/http.js +13 -18
- package/dist/nodejs/index.js +8 -0
- package/dist/nodejs/random.d.ts +5 -0
- package/{lib → dist}/nodejs/random.js +2 -8
- package/dist/nodejs/sockets/address.d.ts +78 -0
- package/dist/nodejs/sockets/address.js +120 -0
- package/dist/nodejs/sockets/error.d.ts +83 -0
- package/dist/nodejs/sockets/error.js +120 -0
- package/dist/nodejs/sockets/ip-name-lookup.d.ts +18 -0
- package/dist/nodejs/sockets/ip-name-lookup.js +84 -0
- package/dist/nodejs/sockets/tcp.d.ts +333 -0
- package/dist/nodejs/sockets/tcp.js +723 -0
- package/dist/nodejs/sockets/udp.d.ts +224 -0
- package/dist/nodejs/sockets/udp.js +475 -0
- package/dist/nodejs/sockets.d.ts +11 -0
- package/{lib → dist}/nodejs/sockets.js +2 -5
- package/dist/nodejs/stream.d.ts +161 -0
- package/dist/nodejs/stream.js +388 -0
- package/dist/nodejs/workers/cli-worker.d.ts +1 -0
- package/dist/nodejs/workers/cli-worker.js +41 -0
- package/dist/nodejs/workers/filesystem-worker.d.ts +1 -0
- package/dist/nodejs/workers/filesystem-worker.js +102 -0
- package/dist/nodejs/workers/http-worker.d.ts +1 -0
- package/dist/nodejs/workers/http-worker.js +355 -0
- package/dist/nodejs/workers/resource-worker.d.ts +13 -0
- package/dist/nodejs/workers/resource-worker.js +152 -0
- package/dist/nodejs/workers/tcp-worker.d.ts +2 -0
- package/dist/nodejs/workers/tcp-worker.js +318 -0
- package/dist/nodejs/workers/udp-worker.d.ts +1 -0
- package/dist/nodejs/workers/udp-worker.js +156 -0
- package/package.json +20 -12
- package/types/interfaces/wasi-cli-environment.d.ts +3 -3
- package/types/interfaces/wasi-cli-exit.d.ts +12 -1
- package/types/interfaces/wasi-cli-run.d.ts +1 -1
- package/types/interfaces/wasi-cli-stderr.d.ts +3 -3
- package/types/interfaces/wasi-cli-stdin.d.ts +5 -5
- package/types/interfaces/wasi-cli-stdout.d.ts +3 -3
- package/types/interfaces/wasi-cli-terminal-input.d.ts +1 -1
- package/types/interfaces/wasi-cli-terminal-output.d.ts +1 -1
- package/types/interfaces/wasi-cli-terminal-stderr.d.ts +1 -1
- package/types/interfaces/wasi-cli-terminal-stdin.d.ts +1 -1
- package/types/interfaces/wasi-cli-terminal-stdout.d.ts +1 -1
- package/types/interfaces/wasi-cli-types.d.ts +5 -5
- package/types/interfaces/wasi-clocks-monotonic-clock.d.ts +3 -3
- package/types/interfaces/wasi-clocks-system-clock.d.ts +6 -6
- package/types/interfaces/wasi-clocks-types.d.ts +1 -1
- package/types/interfaces/wasi-filesystem-preopens.d.ts +1 -1
- package/types/interfaces/wasi-filesystem-types.d.ts +74 -74
- package/types/interfaces/wasi-http-client.d.ts +1 -1
- package/types/interfaces/wasi-http-handler.d.ts +1 -1
- package/types/interfaces/wasi-http-types.d.ts +34 -34
- package/types/interfaces/wasi-random-insecure-seed.d.ts +5 -5
- package/types/interfaces/wasi-random-insecure.d.ts +5 -5
- package/types/interfaces/wasi-random-random.d.ts +5 -5
- package/types/interfaces/wasi-sockets-ip-name-lookup.d.ts +11 -11
- package/types/interfaces/wasi-sockets-types.d.ts +121 -121
- package/types/wasi-cli-command.d.ts +23 -23
- package/types/wasi-http-service.d.ts +14 -14
- package/lib/nodejs/cli.js +0 -127
- package/lib/nodejs/clocks.js +0 -100
- package/lib/nodejs/filesystem/descriptor.js +0 -1093
- package/lib/nodejs/filesystem/error.js +0 -92
- package/lib/nodejs/filesystem/utils.js +0 -19
- package/lib/nodejs/future.js +0 -190
- package/lib/nodejs/http/client.js +0 -161
- package/lib/nodejs/http/error.js +0 -71
- package/lib/nodejs/http/fields.js +0 -373
- package/lib/nodejs/http/request.js +0 -691
- package/lib/nodejs/http/response.js +0 -227
- package/lib/nodejs/http/server.js +0 -157
- package/lib/nodejs/sockets/address.js +0 -146
- package/lib/nodejs/sockets/error.js +0 -123
- package/lib/nodejs/sockets/ip-name-lookup.js +0 -93
- package/lib/nodejs/sockets/tcp.js +0 -801
- package/lib/nodejs/sockets/udp.js +0 -516
- package/lib/nodejs/stream.js +0 -437
- package/lib/nodejs/workers/cli-worker.js +0 -49
- package/lib/nodejs/workers/filesystem-worker.js +0 -119
- package/lib/nodejs/workers/http-worker.js +0 -417
- package/lib/nodejs/workers/resource-worker.js +0 -195
- package/lib/nodejs/workers/tcp-worker.js +0 -370
- package/lib/nodejs/workers/udp-worker.js +0 -194
- /package/{lib/nodejs/filesystem.js → dist/nodejs/filesystem.d.ts} +0 -0
- /package/{lib/nodejs/index.js → dist/nodejs/index.d.ts} +0 -0
|
@@ -1,801 +0,0 @@
|
|
|
1
|
-
import { StreamReader, readableByteStreamFromReader } from "../stream.js";
|
|
2
|
-
import { FutureReader } from "../future.js";
|
|
3
|
-
import { ResourceWorker } from "../workers/resource-worker.js";
|
|
4
|
-
import { SocketError } from "./error.js";
|
|
5
|
-
|
|
6
|
-
import {
|
|
7
|
-
isWildcardIpAddress,
|
|
8
|
-
isUnicastIpAddress,
|
|
9
|
-
isMulticastIpAddress,
|
|
10
|
-
isIpv4MappedAddress,
|
|
11
|
-
isBindableIpAddress,
|
|
12
|
-
IP_ADDRESS_FAMILY,
|
|
13
|
-
} from "./address.js";
|
|
14
|
-
|
|
15
|
-
let WORKER = null;
|
|
16
|
-
const symbolDispose = Symbol.dispose || Symbol.for("dispose");
|
|
17
|
-
function worker() {
|
|
18
|
-
return (WORKER ??= new ResourceWorker(new URL("../workers/tcp-worker.js", import.meta.url)));
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
let TCP_CREATE_TOKEN = null;
|
|
22
|
-
function token() {
|
|
23
|
-
return (TCP_CREATE_TOKEN ??= Symbol("TcpCreateToken"));
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
function invalidRecv() {
|
|
27
|
-
const stream = new ReadableStream({
|
|
28
|
-
start(controller) {
|
|
29
|
-
controller.close();
|
|
30
|
-
},
|
|
31
|
-
});
|
|
32
|
-
const promise = Promise.reject(new SocketError("invalid-state"));
|
|
33
|
-
return [new StreamReader(stream, { preventCancel: false }), new FutureReader(promise)];
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const STATE = {
|
|
37
|
-
UNBOUND: "unbound",
|
|
38
|
-
BOUND: "bound",
|
|
39
|
-
LISTENING: "listening",
|
|
40
|
-
CONNECTING: "connecting",
|
|
41
|
-
CONNECTED: "connected",
|
|
42
|
-
CLOSED: "closed",
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
/**
|
|
46
|
-
* Creates a new TCP socket
|
|
47
|
-
* WIT: createTcpSocket: func(address-family: ip-address-family) -> result<tcp-socket, error-code>
|
|
48
|
-
*
|
|
49
|
-
* @param {IP_ADDRESS_FAMILY} addressFamily - The IP address family (IPv4 or IPv6)
|
|
50
|
-
* @returns {TcpSocket>} A new TCP socket instance
|
|
51
|
-
* @throws {SocketError} with payload.tag 'invalid-argument' if `addressFamily` is not IPV4 or IPV6
|
|
52
|
-
* @throws {SocketError} for other errors, payload.tag maps the low-level system error_
|
|
53
|
-
*/
|
|
54
|
-
export function createTcpSocket(addressFamily) {
|
|
55
|
-
if (addressFamily !== IP_ADDRESS_FAMILY.IPV4 && addressFamily !== IP_ADDRESS_FAMILY.IPV6) {
|
|
56
|
-
throw new SocketError("invalid-argument");
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
try {
|
|
60
|
-
const result = worker().runSync({
|
|
61
|
-
op: "tcp-create",
|
|
62
|
-
family: addressFamily,
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
return TcpSocket._create(token(), addressFamily, result.socketId);
|
|
66
|
-
} catch (error) {
|
|
67
|
-
throw SocketError.from(error);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export class TcpSocket {
|
|
72
|
-
#socketId = null;
|
|
73
|
-
#family = null;
|
|
74
|
-
#state = "unbound";
|
|
75
|
-
#sendStarted = false;
|
|
76
|
-
#receiveStarted = false;
|
|
77
|
-
#options = {
|
|
78
|
-
// defaults per https://nodejs.org/docs/latest/api/net.html#socketsetkeepaliveenable-initialdelay
|
|
79
|
-
keepAliveEnabled: false,
|
|
80
|
-
|
|
81
|
-
// Node.js doesn't give us the ability to detect the OS default,
|
|
82
|
-
// therefore we hardcode the default value instead of using the OS default,
|
|
83
|
-
// since we would never be able to report it as a return value otherwise.
|
|
84
|
-
// We could make this configurable as a global JCO implementation configuration
|
|
85
|
-
// instead.
|
|
86
|
-
keepAliveIdleTime: 7200_000_000_000n,
|
|
87
|
-
|
|
88
|
-
// The following options are NOT configurable in Node.js!
|
|
89
|
-
// Any configurations set will respond correctly, but underneath retain
|
|
90
|
-
// system / Node.js defaults.
|
|
91
|
-
keepAliveInterval: 1_000_000_000n,
|
|
92
|
-
keepAliveCount: 10,
|
|
93
|
-
hopLimit: 1,
|
|
94
|
-
receiveBufferSize: 65_536n,
|
|
95
|
-
sendBufferSize: 65_536n,
|
|
96
|
-
};
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* WIT static constructor for `wasi:sockets/types.tcp-socket`.
|
|
100
|
-
*
|
|
101
|
-
* WIT:
|
|
102
|
-
* ```
|
|
103
|
-
* create: static func(address-family: ip-address-family) -> result<tcp-socket, error-code>
|
|
104
|
-
* ```
|
|
105
|
-
*
|
|
106
|
-
* @static
|
|
107
|
-
* @param {IP_ADDRESS_FAMILY} addressFamily - The IP address family (IPv4 or IPv6)
|
|
108
|
-
* @returns {TcpSocket} A new TcpSocket instance
|
|
109
|
-
* @throws {SocketError} with payload.tag 'invalid-argument' if `addressFamily` is not IPV4 or IPV6
|
|
110
|
-
* @throws {SocketError} for other socket creation errors
|
|
111
|
-
*/
|
|
112
|
-
static create(addressFamily) {
|
|
113
|
-
return createTcpSocket(addressFamily);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Creates a new TCP socket
|
|
118
|
-
* WIT:
|
|
119
|
-
* ```
|
|
120
|
-
* constructor(address-family: ip-address-family)
|
|
121
|
-
* ```
|
|
122
|
-
*
|
|
123
|
-
* @static
|
|
124
|
-
* @param {IP_ADDRESS_FAMILY} addressFamily - The IP address family (IPv4 or IPv6)
|
|
125
|
-
* @param {number} socketId - The internal socket identifier
|
|
126
|
-
* @returns {TcpSocket} A new TcpSocket instance
|
|
127
|
-
* @private
|
|
128
|
-
*/
|
|
129
|
-
static _create(t, addressFamily, socketId) {
|
|
130
|
-
if (t !== token()) {
|
|
131
|
-
throw new Error("Use createTcpSocket to create a Socket");
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
if (addressFamily !== IP_ADDRESS_FAMILY.IPV4 && addressFamily !== IP_ADDRESS_FAMILY.IPV6) {
|
|
135
|
-
throw new SocketError("invalid-argument");
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
const socket = new TcpSocket();
|
|
139
|
-
socket.#family = addressFamily;
|
|
140
|
-
socket.#socketId = socketId;
|
|
141
|
-
return socket;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Binds the socket to a local address
|
|
146
|
-
* WIT:
|
|
147
|
-
* ```
|
|
148
|
-
* bind: func(local-address: ip-socket-address) -> result<_, error-code>
|
|
149
|
-
* ```
|
|
150
|
-
*
|
|
151
|
-
* @param {Object} localAddress - The local address to bind to
|
|
152
|
-
* @returns {void}
|
|
153
|
-
* @throws {SocketError} with payload.tag 'invalid-state' if the socket is not in ~STATE.UNBOUND~
|
|
154
|
-
* @throws {SocketError} with payload.tag 'invalid-argument' if ~localAddress~ is invalid
|
|
155
|
-
* @throws {SocketError} for other errors, payload.tag maps the system error
|
|
156
|
-
*/
|
|
157
|
-
bind(localAddress) {
|
|
158
|
-
if (this.#state !== STATE.UNBOUND) {
|
|
159
|
-
throw new SocketError("invalid-state");
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
if (!this.#isValidLocalAddress(localAddress)) {
|
|
163
|
-
throw new SocketError("invalid-argument");
|
|
164
|
-
}
|
|
165
|
-
if (!isBindableIpAddress(localAddress)) {
|
|
166
|
-
throw new SocketError("address-not-bindable");
|
|
167
|
-
}
|
|
168
|
-
try {
|
|
169
|
-
worker().runSync({
|
|
170
|
-
op: "tcp-bind",
|
|
171
|
-
localAddress,
|
|
172
|
-
socketId: this.#socketId,
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
this.#state = STATE.BOUND;
|
|
176
|
-
} catch (error) {
|
|
177
|
-
throw SocketError.from(error);
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Connects to a remote endpoint
|
|
183
|
-
* WIT:
|
|
184
|
-
* ```
|
|
185
|
-
* connect: async func(remote-address: ip-socket-address) -> result<_, error-code>
|
|
186
|
-
* ```
|
|
187
|
-
*
|
|
188
|
-
* @async
|
|
189
|
-
* @param {Object} remoteAddress - The remote address to connect to
|
|
190
|
-
* @returns {Promise<void>}
|
|
191
|
-
* @throws {SocketError} with payload.tag 'invalid-state' if socket is CONNECTING, CONNECTED, or LISTENING
|
|
192
|
-
* @throws {SocketError} with payload.tag 'invalid-argument' if ~remoteAddress~ is invalid or port == 0
|
|
193
|
-
* @throws {SocketError} for other errors, payload.tag maps the system error
|
|
194
|
-
*/
|
|
195
|
-
async connect(remoteAddress) {
|
|
196
|
-
if (
|
|
197
|
-
this.#state === STATE.CONNECTING ||
|
|
198
|
-
this.#state === STATE.CONNECTED ||
|
|
199
|
-
this.#state === STATE.LISTENING
|
|
200
|
-
) {
|
|
201
|
-
throw new SocketError("invalid-state");
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
if (!this.#isValidRemoteAddress(remoteAddress)) {
|
|
205
|
-
throw new SocketError("invalid-argument");
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
this.#state = STATE.CONNECTING;
|
|
209
|
-
|
|
210
|
-
try {
|
|
211
|
-
await worker().run({
|
|
212
|
-
op: "tcp-connect",
|
|
213
|
-
remoteAddress,
|
|
214
|
-
socketId: this.#socketId,
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
this.#state = STATE.CONNECTED;
|
|
218
|
-
} catch (error) {
|
|
219
|
-
this.#state = STATE.CLOSED;
|
|
220
|
-
throw SocketError.from(error);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* Starts listening for connections
|
|
226
|
-
* WIT:
|
|
227
|
-
* ```
|
|
228
|
-
* listen: func() -> result<stream<tcp-socket>, error-code>
|
|
229
|
-
* ```
|
|
230
|
-
*
|
|
231
|
-
* @returns {StreamReader} A stream of incoming TCP socket connections
|
|
232
|
-
* @throws {SocketError} with payload.tag 'invalid-state' if socket is LISTENING or CONNECTED
|
|
233
|
-
* @throws {SocketError} for other errors, payload.tag maps the system error
|
|
234
|
-
*/
|
|
235
|
-
listen() {
|
|
236
|
-
if (this.#state === STATE.LISTENING || this.#state === STATE.CONNECTED) {
|
|
237
|
-
throw new SocketError("invalid-state");
|
|
238
|
-
}
|
|
239
|
-
try {
|
|
240
|
-
// Convert incoming connections from worker to TcpSocket instances
|
|
241
|
-
const listener = this;
|
|
242
|
-
const transform = new TransformStream({
|
|
243
|
-
transform({ family, socketId }, controller) {
|
|
244
|
-
const socket = TcpSocket._create(token(), family, socketId);
|
|
245
|
-
socket.#state = STATE.CONNECTED;
|
|
246
|
-
socket.#options = { ...listener.#options };
|
|
247
|
-
controller.enqueue(socket);
|
|
248
|
-
},
|
|
249
|
-
});
|
|
250
|
-
|
|
251
|
-
worker().runSync(
|
|
252
|
-
{
|
|
253
|
-
op: "tcp-listen",
|
|
254
|
-
socketId: this.#socketId,
|
|
255
|
-
stream: transform.writable,
|
|
256
|
-
},
|
|
257
|
-
[transform.writable],
|
|
258
|
-
);
|
|
259
|
-
|
|
260
|
-
this.#state = STATE.LISTENING;
|
|
261
|
-
return new StreamReader(transform.readable);
|
|
262
|
-
} catch (error) {
|
|
263
|
-
this.#state = STATE.CLOSED;
|
|
264
|
-
throw SocketError.from(error);
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
/**
|
|
269
|
-
* Sends data to the connected peer
|
|
270
|
-
* WIT:
|
|
271
|
-
* ```
|
|
272
|
-
* send: async func(data: stream<u8>) -> result<_, error-code>
|
|
273
|
-
* ```
|
|
274
|
-
*
|
|
275
|
-
* @async
|
|
276
|
-
* @param {object} data - The byte stream to send.
|
|
277
|
-
* @returns {Promise<void>}
|
|
278
|
-
* @throws {SocketError} With payload.tag 'invalid-state' if socket is not CONNECTED
|
|
279
|
-
* @throws {SocketError} With payload.tag 'invalid-argument' if `data` is not a readable byte stream
|
|
280
|
-
* @throws {SocketError} for other errors, payload.tag maps the system error
|
|
281
|
-
*/
|
|
282
|
-
async send(data) {
|
|
283
|
-
if (this.#state !== STATE.CONNECTED) {
|
|
284
|
-
throw new SocketError("invalid-state");
|
|
285
|
-
}
|
|
286
|
-
if (this.#sendStarted) {
|
|
287
|
-
data?.[symbolDispose]?.();
|
|
288
|
-
throw new SocketError("invalid-state");
|
|
289
|
-
}
|
|
290
|
-
let stream;
|
|
291
|
-
try {
|
|
292
|
-
stream = readableByteStreamFromReader(data, { name: "tcp send data" });
|
|
293
|
-
} catch (error) {
|
|
294
|
-
if (error instanceof TypeError) {
|
|
295
|
-
throw new SocketError("invalid-argument", error.message, undefined, { cause: error });
|
|
296
|
-
}
|
|
297
|
-
throw error;
|
|
298
|
-
}
|
|
299
|
-
this.#sendStarted = true;
|
|
300
|
-
|
|
301
|
-
try {
|
|
302
|
-
// Transfer the stream to the worker
|
|
303
|
-
await worker().run(
|
|
304
|
-
{
|
|
305
|
-
op: "tcp-send",
|
|
306
|
-
socketId: this.#socketId,
|
|
307
|
-
stream,
|
|
308
|
-
},
|
|
309
|
-
[stream],
|
|
310
|
-
);
|
|
311
|
-
} catch (error) {
|
|
312
|
-
throw SocketError.from(error);
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
/**
|
|
317
|
-
* Receives data from the connected peer
|
|
318
|
-
* WIT:
|
|
319
|
-
* ```
|
|
320
|
-
* receive: func() -> tuple<stream<u8>, future<result<_, error-code>>>
|
|
321
|
-
* ```
|
|
322
|
-
*
|
|
323
|
-
* @throws {SocketError} with payload.tag 'invalid-state' if socket is not CONNECTED
|
|
324
|
-
* @throws {SocketError} for other errors, payload.tag maps the system error
|
|
325
|
-
* @returns {{ stream: StreamReader, future: FutureReader }}
|
|
326
|
-
*/
|
|
327
|
-
receive() {
|
|
328
|
-
if (this.#state !== STATE.CONNECTED) {
|
|
329
|
-
return invalidRecv();
|
|
330
|
-
}
|
|
331
|
-
if (this.#receiveStarted) {
|
|
332
|
-
return invalidRecv();
|
|
333
|
-
}
|
|
334
|
-
this.#receiveStarted = true;
|
|
335
|
-
|
|
336
|
-
const transform = new TransformStream();
|
|
337
|
-
const promise = worker()
|
|
338
|
-
.run(
|
|
339
|
-
{
|
|
340
|
-
op: "tcp-receive",
|
|
341
|
-
socketId: this.#socketId,
|
|
342
|
-
stream: transform.writable,
|
|
343
|
-
},
|
|
344
|
-
[transform.writable],
|
|
345
|
-
)
|
|
346
|
-
.catch((err) => {
|
|
347
|
-
throw SocketError.from(err);
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
return [
|
|
351
|
-
new StreamReader(transform.readable, { preventCancel: false }),
|
|
352
|
-
new FutureReader(promise),
|
|
353
|
-
];
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
/**
|
|
357
|
-
* Gets the bound local address
|
|
358
|
-
* WIT:
|
|
359
|
-
* ```
|
|
360
|
-
* local-address: func() -> result<ip-socket-address, error-code>
|
|
361
|
-
* ```
|
|
362
|
-
*
|
|
363
|
-
* @returns {Object} The local socket address
|
|
364
|
-
* @throws {SocketError} with payload.tag 'invalid-state' if socket is not BOUND
|
|
365
|
-
* @throws {SocketError} for other errors, payload.tag maps the system error
|
|
366
|
-
*/
|
|
367
|
-
getLocalAddress() {
|
|
368
|
-
if (this.#state === STATE.UNBOUND) {
|
|
369
|
-
throw new SocketError("invalid-state");
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
try {
|
|
373
|
-
return worker().runSync({
|
|
374
|
-
op: "tcp-get-local-address",
|
|
375
|
-
socketId: this.#socketId,
|
|
376
|
-
});
|
|
377
|
-
} catch (err) {
|
|
378
|
-
throw SocketError.from(err);
|
|
379
|
-
}
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
/**
|
|
383
|
-
* Gets the remote address
|
|
384
|
-
* WIT:
|
|
385
|
-
* ```
|
|
386
|
-
* remote-address: func() -> result<ip-socket-address, error-code>
|
|
387
|
-
* ```
|
|
388
|
-
*
|
|
389
|
-
* @returns {Object} The remote socket address
|
|
390
|
-
* @throws {SocketError} with payload.tag 'invalid-state' if socket is not CONNECTED
|
|
391
|
-
* @throws {SocketError} for other errors, payload.tag maps the system error
|
|
392
|
-
*/
|
|
393
|
-
getRemoteAddress() {
|
|
394
|
-
if (this.#state !== STATE.CONNECTED) {
|
|
395
|
-
throw new SocketError("invalid-state");
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
try {
|
|
399
|
-
return worker().runSync({
|
|
400
|
-
op: "tcp-get-remote-address",
|
|
401
|
-
socketId: this.#socketId,
|
|
402
|
-
});
|
|
403
|
-
} catch (err) {
|
|
404
|
-
throw SocketError.from(err);
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
/**
|
|
409
|
-
* Checks if the socket is in listening state
|
|
410
|
-
* WIT:
|
|
411
|
-
* ```
|
|
412
|
-
* is-listening: func() -> bool
|
|
413
|
-
* ```
|
|
414
|
-
*
|
|
415
|
-
* @returns {boolean} True if socket is listening, false otherwise
|
|
416
|
-
*/
|
|
417
|
-
getIsListening() {
|
|
418
|
-
return this.#state === STATE.LISTENING;
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
/**
|
|
422
|
-
* Gets the address family
|
|
423
|
-
* WIT:
|
|
424
|
-
* ```
|
|
425
|
-
* address-family: func() -> ip-address-family
|
|
426
|
-
* ```
|
|
427
|
-
*
|
|
428
|
-
* @returns {IP_ADDRESS_FAMILY} The IP address family (IPv4 or IPv6)
|
|
429
|
-
*/
|
|
430
|
-
getAddressFamily() {
|
|
431
|
-
return this.#family;
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
/**
|
|
435
|
-
* Sets the listen backlog size
|
|
436
|
-
* WIT:
|
|
437
|
-
* ```
|
|
438
|
-
* set-listen-backlog-size: func(value: u64) -> result<_, error-code>
|
|
439
|
-
* ```
|
|
440
|
-
*
|
|
441
|
-
* @param {bigint} value - The backlog size
|
|
442
|
-
* @returns {void}
|
|
443
|
-
* @throws {SocketError} with payload.tag 'invalid-argument' if `value` is 0
|
|
444
|
-
* @throws {SocketError} with payload.tag 'not-supported' if socket is CONNECTING or CONNECTED
|
|
445
|
-
* @throws {SocketError} with payload.tag 'invalid-state' if socket is not UNBOUND or BOUND
|
|
446
|
-
* @throws {SocketError} for other errors, payload.tag maps the system error
|
|
447
|
-
*/
|
|
448
|
-
setListenBacklogSize(value) {
|
|
449
|
-
if (value <= 0n) {
|
|
450
|
-
throw new SocketError("invalid-argument");
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
if (
|
|
454
|
-
this.#state === STATE.CONNECTING ||
|
|
455
|
-
this.#state === STATE.CONNECTED ||
|
|
456
|
-
this.#state === STATE.LISTENING
|
|
457
|
-
) {
|
|
458
|
-
throw new SocketError("not-supported");
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
if (this.#state !== STATE.UNBOUND && this.#state !== STATE.BOUND) {
|
|
462
|
-
throw new SocketError("invalid-state");
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
this.#options.listenBacklogSize = value;
|
|
466
|
-
try {
|
|
467
|
-
worker().runSync({
|
|
468
|
-
op: "tcp-set-listen-backlog-size",
|
|
469
|
-
socketId: this.#socketId,
|
|
470
|
-
value,
|
|
471
|
-
});
|
|
472
|
-
} catch (err) {
|
|
473
|
-
throw SocketError.from(err);
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
|
|
477
|
-
/**
|
|
478
|
-
* Gets whether keep-alive is enabled
|
|
479
|
-
* WIT:
|
|
480
|
-
* ```
|
|
481
|
-
* keep-alive-enabled: func() -> result<bool, error-code>
|
|
482
|
-
* ```
|
|
483
|
-
*
|
|
484
|
-
* @returns {boolean} True if keep-alive is enabled, false otherwise
|
|
485
|
-
*/
|
|
486
|
-
getKeepAliveEnabled() {
|
|
487
|
-
return this.#options.keepAliveEnabled;
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
/**
|
|
491
|
-
* Sets keep-alive enabled state
|
|
492
|
-
* WIT:
|
|
493
|
-
* ```
|
|
494
|
-
* set-keep-alive-enabled: func(value: bool) -> result<_, error-code>
|
|
495
|
-
* ```
|
|
496
|
-
*
|
|
497
|
-
* @async
|
|
498
|
-
* @param {boolean} value - Whether to enable keep-alive
|
|
499
|
-
* @returns {void}
|
|
500
|
-
* @throws {SocketError} for other errors, payload.tag maps the system error
|
|
501
|
-
*/
|
|
502
|
-
setKeepAliveEnabled(value) {
|
|
503
|
-
try {
|
|
504
|
-
this.#options.keepAliveEnabled = value;
|
|
505
|
-
|
|
506
|
-
worker().runSync({
|
|
507
|
-
op: "tcp-set-keep-alive",
|
|
508
|
-
socketId: this.#socketId,
|
|
509
|
-
keepAliveEnabled: this.#options.keepAliveEnabled,
|
|
510
|
-
keepAliveIdleTime: this.#options.keepAliveIdleTime,
|
|
511
|
-
});
|
|
512
|
-
} catch (err) {
|
|
513
|
-
throw SocketError.from(err);
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
/**
|
|
518
|
-
* Gets the keep-alive idle time
|
|
519
|
-
* WIT:
|
|
520
|
-
* ```
|
|
521
|
-
* keep-alive-idle-time: func() -> result<duration, error-code>
|
|
522
|
-
* ```
|
|
523
|
-
*
|
|
524
|
-
* @returns {bigint} The keep-alive idle time in nanoseconds
|
|
525
|
-
*/
|
|
526
|
-
getKeepAliveIdleTime() {
|
|
527
|
-
return this.#options.keepAliveIdleTime;
|
|
528
|
-
}
|
|
529
|
-
|
|
530
|
-
/**
|
|
531
|
-
* Sets the keep-alive idle time
|
|
532
|
-
* WIT:
|
|
533
|
-
* ```
|
|
534
|
-
* set-keep-alive-idle-time: func(value: duration) -> result<_, error-code>
|
|
535
|
-
* ```
|
|
536
|
-
*
|
|
537
|
-
* @param {bigint} value - The idle time in nanoseconds
|
|
538
|
-
* @returns {void}
|
|
539
|
-
* @throws {SocketError} with payload.tag 'invalid-argument' if `value` is less than 1
|
|
540
|
-
* @throws {SocketError} for other errors, payload.tag maps the system error
|
|
541
|
-
*/
|
|
542
|
-
setKeepAliveIdleTime(value) {
|
|
543
|
-
if (value < 1n) {
|
|
544
|
-
throw new SocketError("invalid-argument");
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
// Ensure that the value passed to the worker never gets rounded down to 0.
|
|
548
|
-
if (value < 1_000_000_000n) {
|
|
549
|
-
value = 1_000_000_000n;
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
if (value === this.#options.keepAliveIdleTime || !this.#options.keepAliveEnabled) {
|
|
553
|
-
this.#options.keepAliveIdleTime = value;
|
|
554
|
-
return;
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
this.#options.keepAliveIdleTime = value;
|
|
558
|
-
|
|
559
|
-
try {
|
|
560
|
-
worker().runSync({
|
|
561
|
-
op: "tcp-set-keep-alive",
|
|
562
|
-
socketId: this.#socketId,
|
|
563
|
-
keepAliveEnabled: this.#options.keepAliveEnabled,
|
|
564
|
-
keepAliveIdleTime: this.#options.keepAliveIdleTime,
|
|
565
|
-
});
|
|
566
|
-
} catch (err) {
|
|
567
|
-
throw SocketError.from(err);
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
/**
|
|
572
|
-
* Gets the keep-alive interval
|
|
573
|
-
* WIT:
|
|
574
|
-
* ```
|
|
575
|
-
* keep-alive-interval: func() -> result<duration, error-code>
|
|
576
|
-
* ```
|
|
577
|
-
*
|
|
578
|
-
* @returns {bigint} The keep-alive interval in nanoseconds
|
|
579
|
-
*/
|
|
580
|
-
getKeepAliveInterval() {
|
|
581
|
-
return this.#options.keepAliveInterval;
|
|
582
|
-
}
|
|
583
|
-
|
|
584
|
-
/**
|
|
585
|
-
* Sets the keep-alive interval
|
|
586
|
-
* WIT:
|
|
587
|
-
* ```
|
|
588
|
-
* set-keep-alive-interval: func(value: duration) -> result<_, error-code>
|
|
589
|
-
* ```
|
|
590
|
-
*
|
|
591
|
-
* @param {bigint} value - The interval in nanoseconds
|
|
592
|
-
* @returns {void}
|
|
593
|
-
* @throws {SocketError} with payload.tag 'invalid-argument' if `value` is less than 1
|
|
594
|
-
*/
|
|
595
|
-
setKeepAliveInterval(value) {
|
|
596
|
-
if (value < 1n) {
|
|
597
|
-
throw new SocketError("invalid-argument");
|
|
598
|
-
}
|
|
599
|
-
this.#options.keepAliveInterval = value;
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
/**
|
|
603
|
-
* Gets the keep-alive count
|
|
604
|
-
* WIT:
|
|
605
|
-
* ```
|
|
606
|
-
* keep-alive-count: func() -> result<u32, error-code>
|
|
607
|
-
* ```
|
|
608
|
-
*
|
|
609
|
-
* @returns {number} The keep-alive count
|
|
610
|
-
*/
|
|
611
|
-
getKeepAliveCount() {
|
|
612
|
-
return this.#options.keepAliveCount;
|
|
613
|
-
}
|
|
614
|
-
|
|
615
|
-
/**
|
|
616
|
-
* Sets the keep-alive count
|
|
617
|
-
* WIT:
|
|
618
|
-
* ```
|
|
619
|
-
* set-keep-alive-count: func(value: u32) -> result<_, error-code>
|
|
620
|
-
* ```
|
|
621
|
-
*
|
|
622
|
-
* @param {number} value - The keep-alive count
|
|
623
|
-
* @returns {void}
|
|
624
|
-
* @throws {SocketError} with payload.tag 'invalid-argument' if `value` is less than 1
|
|
625
|
-
*/
|
|
626
|
-
setKeepAliveCount(value) {
|
|
627
|
-
if (value < 1) {
|
|
628
|
-
throw new SocketError("invalid-argument");
|
|
629
|
-
}
|
|
630
|
-
this.#options.keepAliveCount = value;
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
/**
|
|
634
|
-
* Gets the hop limit
|
|
635
|
-
* WIT:
|
|
636
|
-
* ```
|
|
637
|
-
* hop-limit: func() -> result<u8, error-code>
|
|
638
|
-
* ```
|
|
639
|
-
*
|
|
640
|
-
* @returns {number} The hop limit
|
|
641
|
-
*/
|
|
642
|
-
getHopLimit() {
|
|
643
|
-
return this.#options.hopLimit;
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
/**
|
|
647
|
-
* Sets the hop limit
|
|
648
|
-
* WIT:
|
|
649
|
-
* ```
|
|
650
|
-
* set-hop-limit: func(value: u8) -> result<_, error-code>
|
|
651
|
-
* ```
|
|
652
|
-
*
|
|
653
|
-
* @param {number} value - The hop limit
|
|
654
|
-
* @returns {void}
|
|
655
|
-
* @throws {SocketError} with payload.tag 'invalid-argument' if `value` is less than 1
|
|
656
|
-
*/
|
|
657
|
-
setHopLimit(value) {
|
|
658
|
-
if (value < 1) {
|
|
659
|
-
throw new SocketError("invalid-argument");
|
|
660
|
-
}
|
|
661
|
-
this.#options.hopLimit = value;
|
|
662
|
-
}
|
|
663
|
-
|
|
664
|
-
/**
|
|
665
|
-
* Gets the receive buffer size
|
|
666
|
-
* WIT:
|
|
667
|
-
* ```
|
|
668
|
-
* receive-buffer-size: func() -> result<u64, error-code>
|
|
669
|
-
* ```
|
|
670
|
-
*
|
|
671
|
-
* @returns {bigint} The receive buffer size in bytes
|
|
672
|
-
* @throws {SocketError} for other errors, payload.tag maps the system error
|
|
673
|
-
*/
|
|
674
|
-
getReceiveBufferSize() {
|
|
675
|
-
if (this.#options.receiveBufferSize) {
|
|
676
|
-
return this.#options.receiveBufferSize;
|
|
677
|
-
}
|
|
678
|
-
|
|
679
|
-
try {
|
|
680
|
-
const result = worker().runSync({
|
|
681
|
-
op: "tcp-recv-buffer-size",
|
|
682
|
-
socketId: this.#socketId,
|
|
683
|
-
});
|
|
684
|
-
|
|
685
|
-
this.#options.receiveBufferSize = result;
|
|
686
|
-
return result;
|
|
687
|
-
} catch (err) {
|
|
688
|
-
throw SocketError.from(err);
|
|
689
|
-
}
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
/**
|
|
693
|
-
* Sets the receive buffer size
|
|
694
|
-
* WIT:
|
|
695
|
-
* ```
|
|
696
|
-
* set-receive-buffer-size: func(value: u64) -> result<_, error-code>
|
|
697
|
-
* ```
|
|
698
|
-
*
|
|
699
|
-
* @param {bigint} value - The receive buffer size in bytes
|
|
700
|
-
* @returns {void}
|
|
701
|
-
* @throws {SocketError} with payload.tag 'invalid-argument' if `value` is 0
|
|
702
|
-
*/
|
|
703
|
-
setReceiveBufferSize(value) {
|
|
704
|
-
if (value <= 0n) {
|
|
705
|
-
throw new SocketError("invalid-argument");
|
|
706
|
-
}
|
|
707
|
-
this.#options.receiveBufferSize = value;
|
|
708
|
-
}
|
|
709
|
-
|
|
710
|
-
/**
|
|
711
|
-
* Gets the send buffer size
|
|
712
|
-
* WIT:
|
|
713
|
-
* ```
|
|
714
|
-
* send-buffer-size: func() -> result<u64, error-code>
|
|
715
|
-
* ```
|
|
716
|
-
*
|
|
717
|
-
* @returns {bigint} The send buffer size in bytes
|
|
718
|
-
* @throws {SocketError} for other errors, payload.tag maps the system error
|
|
719
|
-
*/
|
|
720
|
-
getSendBufferSize() {
|
|
721
|
-
if (this.#options.sendBufferSize) {
|
|
722
|
-
return this.#options.sendBufferSize;
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
try {
|
|
726
|
-
const result = worker().runSync({
|
|
727
|
-
op: "tcp-send-buffer-size",
|
|
728
|
-
socketId: this.#socketId,
|
|
729
|
-
});
|
|
730
|
-
|
|
731
|
-
this.#options.sendBufferSize = result;
|
|
732
|
-
return result;
|
|
733
|
-
} catch (err) {
|
|
734
|
-
throw SocketError.from(err);
|
|
735
|
-
}
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
/**
|
|
739
|
-
* Sets the send buffer size
|
|
740
|
-
* WIT:
|
|
741
|
-
* ```
|
|
742
|
-
* set-send-buffer-size: func(value: u64) -> result<_, error-code>
|
|
743
|
-
* ```
|
|
744
|
-
*
|
|
745
|
-
* @param {bigint} value - The send buffer size in bytes
|
|
746
|
-
* @returns {void}
|
|
747
|
-
* @throws {SocketError} with payload.tag 'invalid-argument' if `value` is 0
|
|
748
|
-
*/
|
|
749
|
-
setSendBufferSize(value) {
|
|
750
|
-
if (value <= 0n) {
|
|
751
|
-
throw new SocketError("invalid-argument");
|
|
752
|
-
}
|
|
753
|
-
this.#options.sendBufferSize = value;
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
/**
|
|
757
|
-
* Disposes the socket
|
|
758
|
-
*/
|
|
759
|
-
[Symbol.dispose]() {
|
|
760
|
-
if (this.#socketId) {
|
|
761
|
-
worker().runSync({
|
|
762
|
-
op: "tcp-dispose",
|
|
763
|
-
socketId: this.#socketId,
|
|
764
|
-
});
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
this.#socketId = null;
|
|
768
|
-
this.#state = STATE.CLOSED;
|
|
769
|
-
}
|
|
770
|
-
|
|
771
|
-
/**
|
|
772
|
-
* Validates if a local address is valid for this socket
|
|
773
|
-
* @param {Object} localAddress - The local address to validate
|
|
774
|
-
* @returns {boolean} True if the address is valid, false otherwise
|
|
775
|
-
* @private
|
|
776
|
-
*/
|
|
777
|
-
#isValidLocalAddress(localAddress) {
|
|
778
|
-
return (
|
|
779
|
-
this.#family === localAddress.tag &&
|
|
780
|
-
(isUnicastIpAddress(localAddress) || isWildcardIpAddress(localAddress)) &&
|
|
781
|
-
!isIpv4MappedAddress(localAddress)
|
|
782
|
-
);
|
|
783
|
-
}
|
|
784
|
-
|
|
785
|
-
/**
|
|
786
|
-
* Validates if a remote address is valid for this socket
|
|
787
|
-
* @param {Object} remoteAddress - The remote address to validate
|
|
788
|
-
* @returns {boolean} True if the address is valid, false otherwise
|
|
789
|
-
* @private
|
|
790
|
-
*/
|
|
791
|
-
#isValidRemoteAddress(remoteAddress) {
|
|
792
|
-
return (
|
|
793
|
-
this.#family === remoteAddress.tag &&
|
|
794
|
-
remoteAddress.val.port !== 0 &&
|
|
795
|
-
isUnicastIpAddress(remoteAddress) &&
|
|
796
|
-
!isWildcardIpAddress(remoteAddress) &&
|
|
797
|
-
!isMulticastIpAddress(remoteAddress) &&
|
|
798
|
-
!isIpv4MappedAddress(remoteAddress)
|
|
799
|
-
);
|
|
800
|
-
}
|
|
801
|
-
}
|