@bytecodealliance/preview2-shim 0.17.7 → 0.17.9
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 +18 -18
- package/lib/browser/cli.js +71 -71
- package/lib/browser/clocks.js +34 -30
- package/lib/browser/config.js +3 -3
- package/lib/browser/environment.js +15 -15
- package/lib/browser/filesystem.js +382 -396
- package/lib/browser/http.js +683 -144
- package/lib/browser/index.js +7 -7
- package/lib/browser/io.js +199 -133
- package/lib/browser/random.js +42 -44
- package/lib/browser/sockets.js +52 -52
- package/lib/common/instantiation.js +147 -151
- package/lib/io/calls.js +7 -9
- package/lib/io/worker-http.js +167 -178
- package/lib/io/worker-io.js +338 -406
- package/lib/io/worker-socket-tcp.js +259 -271
- package/lib/io/worker-socket-udp.js +437 -491
- package/lib/io/worker-sockets.js +230 -251
- package/lib/io/worker-thread.js +774 -822
- package/lib/nodejs/cli.js +53 -65
- package/lib/nodejs/clocks.js +49 -52
- package/lib/nodejs/filesystem.js +726 -785
- package/lib/nodejs/http.js +651 -697
- package/lib/nodejs/index.js +7 -7
- package/lib/nodejs/io.js +1 -1
- package/lib/nodejs/random.js +32 -32
- package/lib/nodejs/sockets.js +468 -538
- package/lib/synckit/index.js +85 -94
- package/package.json +11 -10
package/lib/io/worker-thread.js
CHANGED
|
@@ -1,163 +1,163 @@
|
|
|
1
|
-
import { createReadStream, createWriteStream } from
|
|
2
|
-
import { hrtime, stderr, stdout } from
|
|
3
|
-
import { PassThrough } from
|
|
4
|
-
import { runAsWorker } from
|
|
1
|
+
import { createReadStream, createWriteStream } from "node:fs";
|
|
2
|
+
import { hrtime, stderr, stdout } from "node:process";
|
|
3
|
+
import { PassThrough } from "node:stream";
|
|
4
|
+
import { runAsWorker } from "../synckit/index.js";
|
|
5
5
|
import {
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
} from
|
|
13
|
-
import { Readable } from
|
|
14
|
-
import { read } from
|
|
15
|
-
import { nextTick } from
|
|
6
|
+
clearOutgoingResponse,
|
|
7
|
+
createHttpRequest,
|
|
8
|
+
setOutgoingResponse,
|
|
9
|
+
startHttpServer,
|
|
10
|
+
stopHttpServer,
|
|
11
|
+
getHttpServerAddress,
|
|
12
|
+
} from "./worker-http.js";
|
|
13
|
+
import { Readable } from "node:stream";
|
|
14
|
+
import { read } from "node:fs";
|
|
15
|
+
import { nextTick } from "node:process";
|
|
16
16
|
import {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
} from
|
|
17
|
+
CALL_MASK,
|
|
18
|
+
CALL_TYPE_MASK,
|
|
19
|
+
CLOCKS_DURATION_SUBSCRIBE,
|
|
20
|
+
CLOCKS_INSTANT_SUBSCRIBE,
|
|
21
|
+
FILE,
|
|
22
|
+
FUTURE_DISPOSE,
|
|
23
|
+
FUTURE_SUBSCRIBE,
|
|
24
|
+
FUTURE_TAKE_VALUE,
|
|
25
|
+
HTTP,
|
|
26
|
+
HTTP_CREATE_REQUEST,
|
|
27
|
+
HTTP_OUTGOING_BODY_DISPOSE,
|
|
28
|
+
HTTP_OUTPUT_STREAM_FINISH,
|
|
29
|
+
HTTP_SERVER_CLEAR_OUTGOING_RESPONSE,
|
|
30
|
+
HTTP_SERVER_SET_OUTGOING_RESPONSE,
|
|
31
|
+
HTTP_SERVER_START,
|
|
32
|
+
HTTP_SERVER_STOP,
|
|
33
|
+
HTTP_SERVER_GET_ADDRESS,
|
|
34
|
+
INPUT_STREAM_BLOCKING_READ,
|
|
35
|
+
INPUT_STREAM_BLOCKING_SKIP,
|
|
36
|
+
INPUT_STREAM_CREATE,
|
|
37
|
+
INPUT_STREAM_DISPOSE,
|
|
38
|
+
INPUT_STREAM_READ,
|
|
39
|
+
INPUT_STREAM_SKIP,
|
|
40
|
+
INPUT_STREAM_SUBSCRIBE,
|
|
41
|
+
OUTPUT_STREAM_BLOCKING_FLUSH,
|
|
42
|
+
OUTPUT_STREAM_BLOCKING_SPLICE,
|
|
43
|
+
OUTPUT_STREAM_BLOCKING_WRITE_AND_FLUSH,
|
|
44
|
+
OUTPUT_STREAM_BLOCKING_WRITE_ZEROES_AND_FLUSH,
|
|
45
|
+
OUTPUT_STREAM_CHECK_WRITE,
|
|
46
|
+
OUTPUT_STREAM_CREATE,
|
|
47
|
+
OUTPUT_STREAM_DISPOSE,
|
|
48
|
+
OUTPUT_STREAM_FLUSH,
|
|
49
|
+
OUTPUT_STREAM_SPLICE,
|
|
50
|
+
OUTPUT_STREAM_SUBSCRIBE,
|
|
51
|
+
OUTPUT_STREAM_WRITE,
|
|
52
|
+
OUTPUT_STREAM_WRITE_ZEROES,
|
|
53
|
+
POLL_POLLABLE_BLOCK,
|
|
54
|
+
POLL_POLLABLE_DISPOSE,
|
|
55
|
+
POLL_POLLABLE_READY,
|
|
56
|
+
POLL_POLL_LIST,
|
|
57
|
+
SOCKET_RESOLVE_ADDRESS_CREATE_REQUEST,
|
|
58
|
+
SOCKET_RESOLVE_ADDRESS_SUBSCRIBE_REQUEST,
|
|
59
|
+
SOCKET_RESOLVE_ADDRESS_DISPOSE_REQUEST,
|
|
60
|
+
SOCKET_RESOLVE_ADDRESS_TAKE_REQUEST,
|
|
61
|
+
SOCKET_GET_DEFAULT_RECEIVE_BUFFER_SIZE,
|
|
62
|
+
SOCKET_GET_DEFAULT_SEND_BUFFER_SIZE,
|
|
63
|
+
SOCKET_TCP_ACCEPT,
|
|
64
|
+
SOCKET_TCP_BIND_FINISH,
|
|
65
|
+
SOCKET_TCP_BIND_START,
|
|
66
|
+
SOCKET_TCP_CONNECT_FINISH,
|
|
67
|
+
SOCKET_TCP_CONNECT_START,
|
|
68
|
+
SOCKET_TCP_CREATE_HANDLE,
|
|
69
|
+
SOCKET_TCP_DISPOSE,
|
|
70
|
+
SOCKET_TCP_GET_LOCAL_ADDRESS,
|
|
71
|
+
SOCKET_TCP_GET_REMOTE_ADDRESS,
|
|
72
|
+
SOCKET_TCP_IS_LISTENING,
|
|
73
|
+
SOCKET_TCP_LISTEN_FINISH,
|
|
74
|
+
SOCKET_TCP_LISTEN_START,
|
|
75
|
+
SOCKET_TCP_SET_KEEP_ALIVE,
|
|
76
|
+
SOCKET_TCP_SET_LISTEN_BACKLOG_SIZE,
|
|
77
|
+
SOCKET_TCP_SHUTDOWN,
|
|
78
|
+
SOCKET_TCP_SUBSCRIBE,
|
|
79
|
+
SOCKET_UDP_BIND_FINISH,
|
|
80
|
+
SOCKET_UDP_BIND_START,
|
|
81
|
+
SOCKET_UDP_CREATE_HANDLE,
|
|
82
|
+
SOCKET_UDP_DISPOSE,
|
|
83
|
+
SOCKET_UDP_GET_LOCAL_ADDRESS,
|
|
84
|
+
SOCKET_UDP_GET_RECEIVE_BUFFER_SIZE,
|
|
85
|
+
SOCKET_UDP_GET_REMOTE_ADDRESS,
|
|
86
|
+
SOCKET_UDP_GET_SEND_BUFFER_SIZE,
|
|
87
|
+
SOCKET_UDP_GET_UNICAST_HOP_LIMIT,
|
|
88
|
+
SOCKET_UDP_SET_RECEIVE_BUFFER_SIZE,
|
|
89
|
+
SOCKET_UDP_SET_SEND_BUFFER_SIZE,
|
|
90
|
+
SOCKET_UDP_SET_UNICAST_HOP_LIMIT,
|
|
91
|
+
SOCKET_UDP_STREAM,
|
|
92
|
+
SOCKET_UDP_SUBSCRIBE,
|
|
93
|
+
SOCKET_INCOMING_DATAGRAM_STREAM_RECEIVE,
|
|
94
|
+
SOCKET_OUTGOING_DATAGRAM_STREAM_CHECK_SEND,
|
|
95
|
+
SOCKET_OUTGOING_DATAGRAM_STREAM_SEND,
|
|
96
|
+
SOCKET_DATAGRAM_STREAM_SUBSCRIBE,
|
|
97
|
+
SOCKET_DATAGRAM_STREAM_DISPOSE,
|
|
98
|
+
STDERR,
|
|
99
|
+
STDIN,
|
|
100
|
+
STDOUT,
|
|
101
|
+
reverseMap,
|
|
102
|
+
} from "./calls.js";
|
|
103
103
|
import {
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
} from
|
|
104
|
+
SOCKET_STATE_BIND,
|
|
105
|
+
SOCKET_STATE_BOUND,
|
|
106
|
+
SOCKET_STATE_CONNECT,
|
|
107
|
+
SOCKET_STATE_CONNECTION,
|
|
108
|
+
SOCKET_STATE_LISTEN,
|
|
109
|
+
SOCKET_STATE_LISTENER,
|
|
110
|
+
socketResolveAddress,
|
|
111
|
+
getDefaultSendBufferSize,
|
|
112
|
+
getDefaultReceiveBufferSize,
|
|
113
|
+
} from "./worker-sockets.js";
|
|
114
114
|
import {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
} from
|
|
115
|
+
createTcpSocket,
|
|
116
|
+
socketTcpAccept,
|
|
117
|
+
socketTcpBindStart,
|
|
118
|
+
socketTcpConnectStart,
|
|
119
|
+
socketTcpDispose,
|
|
120
|
+
socketTcpFinish,
|
|
121
|
+
socketTcpGetLocalAddress,
|
|
122
|
+
socketTcpGetRemoteAddress,
|
|
123
|
+
socketTcpListenStart,
|
|
124
|
+
socketTcpSetKeepAlive,
|
|
125
|
+
socketTcpSetListenBacklogSize,
|
|
126
|
+
socketTcpShutdown,
|
|
127
|
+
tcpSockets,
|
|
128
|
+
} from "./worker-socket-tcp.js";
|
|
129
129
|
import {
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
} from
|
|
150
|
-
import process from
|
|
130
|
+
createUdpSocket,
|
|
131
|
+
datagramStreams,
|
|
132
|
+
socketDatagramStreamDispose,
|
|
133
|
+
socketIncomingDatagramStreamReceive,
|
|
134
|
+
socketOutgoingDatagramStreamCheckSend,
|
|
135
|
+
socketOutgoingDatagramStreamSend,
|
|
136
|
+
socketUdpBindFinish,
|
|
137
|
+
socketUdpBindStart,
|
|
138
|
+
socketUdpDispose,
|
|
139
|
+
socketUdpGetLocalAddress,
|
|
140
|
+
socketUdpGetReceiveBufferSize,
|
|
141
|
+
socketUdpGetRemoteAddress,
|
|
142
|
+
socketUdpGetSendBufferSize,
|
|
143
|
+
socketUdpGetUnicastHopLimit,
|
|
144
|
+
socketUdpSetReceiveBufferSize,
|
|
145
|
+
socketUdpSetSendBufferSize,
|
|
146
|
+
socketUdpSetUnicastHopLimit,
|
|
147
|
+
socketUdpStream,
|
|
148
|
+
udpSockets,
|
|
149
|
+
} from "./worker-socket-udp.js";
|
|
150
|
+
import process from "node:process";
|
|
151
151
|
|
|
152
152
|
export function log(msg) {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
153
|
+
if (debug) {
|
|
154
|
+
process._rawDebug(msg);
|
|
155
|
+
}
|
|
156
156
|
}
|
|
157
157
|
|
|
158
158
|
let pollCnt = 0,
|
|
159
|
-
|
|
160
|
-
|
|
159
|
+
streamCnt = 0,
|
|
160
|
+
futureCnt = 0;
|
|
161
161
|
|
|
162
162
|
/**
|
|
163
163
|
* @typedef {{
|
|
@@ -192,68 +192,68 @@ export const streams = new Map();
|
|
|
192
192
|
export const futures = new Map();
|
|
193
193
|
|
|
194
194
|
export function createReadableStreamPollState(nodeStream) {
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
195
|
+
const pollState = {
|
|
196
|
+
ready: true,
|
|
197
|
+
listener: null,
|
|
198
|
+
polls: [],
|
|
199
|
+
parentStream: nodeStream,
|
|
200
|
+
};
|
|
201
|
+
function pollDone() {
|
|
202
|
+
pollStateReady(pollState);
|
|
203
|
+
nodeStream.off("end", pollDone);
|
|
204
|
+
nodeStream.off("close", pollDone);
|
|
205
|
+
nodeStream.off("error", pollDone);
|
|
206
|
+
}
|
|
207
|
+
nodeStream.on("end", pollDone);
|
|
208
|
+
nodeStream.on("close", pollDone);
|
|
209
|
+
nodeStream.on("error", pollDone);
|
|
210
|
+
return pollState;
|
|
211
211
|
}
|
|
212
212
|
|
|
213
213
|
/**
|
|
214
214
|
* @param {NodeJS.ReadableStream | NodeJS.WritableStream} stream
|
|
215
215
|
*/
|
|
216
216
|
export function createReadableStream(
|
|
217
|
-
|
|
218
|
-
|
|
217
|
+
nodeStream,
|
|
218
|
+
pollState = createReadableStreamPollState(nodeStream),
|
|
219
219
|
) {
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
220
|
+
const stream = {
|
|
221
|
+
stream: nodeStream,
|
|
222
|
+
flushPromise: null,
|
|
223
|
+
pollState,
|
|
224
|
+
};
|
|
225
|
+
streams.set(++streamCnt, stream);
|
|
226
|
+
return streamCnt;
|
|
227
227
|
}
|
|
228
228
|
|
|
229
229
|
export function createWritableStream(nodeStream) {
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
230
|
+
const pollState = {
|
|
231
|
+
ready: true,
|
|
232
|
+
listener: null,
|
|
233
|
+
polls: [],
|
|
234
|
+
parentStream: null,
|
|
235
|
+
};
|
|
236
|
+
const stream = {
|
|
237
|
+
stream: nodeStream,
|
|
238
|
+
flushPromise: null,
|
|
239
|
+
pollState,
|
|
240
|
+
};
|
|
241
|
+
streams.set(++streamCnt, stream);
|
|
242
|
+
function pollReady() {
|
|
243
|
+
pollStateReady(pollState);
|
|
244
|
+
}
|
|
245
|
+
function pollDone() {
|
|
246
|
+
pollStateReady(pollState);
|
|
247
|
+
nodeStream.off("drain", pollReady);
|
|
248
|
+
nodeStream.off("finish", pollDone);
|
|
249
|
+
nodeStream.off("error", pollDone);
|
|
250
|
+
nodeStream.off("close", pollDone);
|
|
251
|
+
}
|
|
252
|
+
nodeStream.on("drain", pollReady);
|
|
253
|
+
nodeStream.on("finish", pollDone);
|
|
254
|
+
nodeStream.on("error", pollDone);
|
|
255
|
+
nodeStream.on("close", pollDone);
|
|
256
|
+
return streamCnt;
|
|
257
257
|
}
|
|
258
258
|
|
|
259
259
|
// Stdio
|
|
@@ -266,10 +266,10 @@ createWritableStream(stderr);
|
|
|
266
266
|
* @param {NodeJS.ReadableStream | NodeJS.WritableStream} stream
|
|
267
267
|
*/
|
|
268
268
|
function streamError(err) {
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
269
|
+
return {
|
|
270
|
+
tag: "last-operation-failed",
|
|
271
|
+
val: { code: err.code, message: err.message, stack: err.stack },
|
|
272
|
+
};
|
|
273
273
|
}
|
|
274
274
|
|
|
275
275
|
/**
|
|
@@ -277,21 +277,21 @@ function streamError(err) {
|
|
|
277
277
|
* @returns {{ stream: NodeJS.ReadableStream | NodeJS.WritableStream, polls: number[] }}
|
|
278
278
|
*/
|
|
279
279
|
export function getStreamOrThrow(streamId) {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
280
|
+
if (!streamId) {
|
|
281
|
+
throw new Error("wasi-io trap: no stream id provided");
|
|
282
|
+
}
|
|
283
|
+
const stream = streams.get(streamId);
|
|
284
|
+
// not in unfinished streams <=> closed
|
|
285
|
+
if (!stream) {
|
|
286
|
+
throw { tag: "closed" };
|
|
287
|
+
}
|
|
288
|
+
if (stream.stream.errored) {
|
|
289
|
+
throw streamError(stream.stream.errored);
|
|
290
|
+
}
|
|
291
|
+
if (stream.stream.closed) {
|
|
292
|
+
throw { tag: "closed" };
|
|
293
|
+
}
|
|
294
|
+
return stream;
|
|
295
295
|
}
|
|
296
296
|
|
|
297
297
|
/**
|
|
@@ -301,677 +301,631 @@ export function getStreamOrThrow(streamId) {
|
|
|
301
301
|
* @returns {Promise<any>}
|
|
302
302
|
*/
|
|
303
303
|
function handle(call, id, payload) {
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
304
|
+
if (uncaughtException) {
|
|
305
|
+
throw uncaughtException;
|
|
306
|
+
}
|
|
307
|
+
switch (call) {
|
|
308
308
|
// Http
|
|
309
309
|
case HTTP_CREATE_REQUEST: {
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
310
|
+
const {
|
|
311
|
+
method,
|
|
312
|
+
scheme,
|
|
313
|
+
authority,
|
|
314
|
+
pathWithQuery,
|
|
315
|
+
headers,
|
|
316
|
+
body,
|
|
317
|
+
connectTimeout,
|
|
318
|
+
betweenBytesTimeout,
|
|
319
|
+
firstByteTimeout,
|
|
320
|
+
} = payload;
|
|
321
|
+
return createFuture(
|
|
322
|
+
createHttpRequest(
|
|
323
|
+
method,
|
|
324
|
+
scheme,
|
|
325
|
+
authority,
|
|
326
|
+
pathWithQuery,
|
|
327
|
+
headers,
|
|
328
|
+
body,
|
|
329
|
+
connectTimeout,
|
|
330
|
+
betweenBytesTimeout,
|
|
331
|
+
firstByteTimeout,
|
|
332
|
+
),
|
|
333
|
+
);
|
|
334
334
|
}
|
|
335
335
|
case OUTPUT_STREAM_CREATE | HTTP: {
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
336
|
+
const stream = new PassThrough();
|
|
337
|
+
// content length is passed as payload
|
|
338
|
+
stream.contentLength = payload;
|
|
339
|
+
stream.bytesRemaining = payload;
|
|
340
|
+
return createWritableStream(stream);
|
|
341
341
|
}
|
|
342
342
|
case OUTPUT_STREAM_SUBSCRIBE | HTTP:
|
|
343
343
|
case OUTPUT_STREAM_FLUSH | HTTP:
|
|
344
344
|
case OUTPUT_STREAM_BLOCKING_WRITE_AND_FLUSH | HTTP: {
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
stream.bytesRemaining -= payload.byteLength;
|
|
349
|
-
if (stream.bytesRemaining < 0) {
|
|
350
|
-
throw {
|
|
351
|
-
tag: 'last-operation-failed',
|
|
352
|
-
val: {
|
|
353
|
-
tag: 'HTTP-request-body-size',
|
|
354
|
-
val: stream.contentLength - stream.bytesRemaining,
|
|
355
|
-
},
|
|
356
|
-
};
|
|
357
|
-
}
|
|
358
|
-
}
|
|
359
|
-
// otherwise fall through to generic implementation
|
|
360
|
-
return handle(call & ~HTTP, id, payload);
|
|
361
|
-
}
|
|
362
|
-
case OUTPUT_STREAM_WRITE | HTTP: {
|
|
363
|
-
const { stream } = getStreamOrThrow(id);
|
|
345
|
+
// http flush is a noop
|
|
346
|
+
const { stream } = getStreamOrThrow(id);
|
|
347
|
+
if (call === (OUTPUT_STREAM_BLOCKING_WRITE_AND_FLUSH | HTTP)) {
|
|
364
348
|
stream.bytesRemaining -= payload.byteLength;
|
|
365
349
|
if (stream.bytesRemaining < 0) {
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
350
|
+
throw {
|
|
351
|
+
tag: "last-operation-failed",
|
|
352
|
+
val: {
|
|
353
|
+
tag: "HTTP-request-body-size",
|
|
354
|
+
val: stream.contentLength - stream.bytesRemaining,
|
|
355
|
+
},
|
|
356
|
+
};
|
|
373
357
|
}
|
|
374
|
-
|
|
375
|
-
|
|
358
|
+
}
|
|
359
|
+
// otherwise fall through to generic implementation
|
|
360
|
+
return handle(call & ~HTTP, id, payload);
|
|
361
|
+
}
|
|
362
|
+
case OUTPUT_STREAM_WRITE | HTTP: {
|
|
363
|
+
const { stream } = getStreamOrThrow(id);
|
|
364
|
+
stream.bytesRemaining -= payload.byteLength;
|
|
365
|
+
if (stream.bytesRemaining < 0) {
|
|
366
|
+
throw {
|
|
367
|
+
tag: "last-operation-failed",
|
|
368
|
+
val: {
|
|
369
|
+
tag: "HTTP-request-body-size",
|
|
370
|
+
val: stream.contentLength - stream.bytesRemaining,
|
|
371
|
+
},
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
const output = handle(OUTPUT_STREAM_WRITE, id, payload);
|
|
375
|
+
return output;
|
|
376
376
|
}
|
|
377
377
|
case OUTPUT_STREAM_DISPOSE | HTTP:
|
|
378
|
-
|
|
379
|
-
'wasi-io trap: Output stream dispose not implemented as an IO-call for HTTP'
|
|
380
|
-
);
|
|
378
|
+
throw new Error("wasi-io trap: Output stream dispose not implemented as an IO-call for HTTP");
|
|
381
379
|
case HTTP_OUTPUT_STREAM_FINISH: {
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
}
|
|
389
|
-
if (e.tag === 'last-operation-failed') {
|
|
390
|
-
throw { tag: 'internal-error', val: e.val.message };
|
|
391
|
-
}
|
|
380
|
+
let stream;
|
|
381
|
+
try {
|
|
382
|
+
({ stream } = getStreamOrThrow(id));
|
|
383
|
+
} catch (e) {
|
|
384
|
+
if (e.tag === "closed") {
|
|
385
|
+
throw { tag: "internal-error", val: "stream closed" };
|
|
392
386
|
}
|
|
393
|
-
if (
|
|
394
|
-
|
|
395
|
-
tag: 'HTTP-request-body-size',
|
|
396
|
-
val: stream.contentLength - stream.bytesRemaining,
|
|
397
|
-
};
|
|
398
|
-
}
|
|
399
|
-
if (stream.bytesRemaining < 0) {
|
|
400
|
-
throw {
|
|
401
|
-
tag: 'HTTP-request-body-size',
|
|
402
|
-
val: stream.contentLength - stream.bytesRemaining,
|
|
403
|
-
};
|
|
387
|
+
if (e.tag === "last-operation-failed") {
|
|
388
|
+
throw { tag: "internal-error", val: e.val.message };
|
|
404
389
|
}
|
|
405
|
-
|
|
406
|
-
|
|
390
|
+
}
|
|
391
|
+
if (stream.bytesRemaining > 0) {
|
|
392
|
+
throw {
|
|
393
|
+
tag: "HTTP-request-body-size",
|
|
394
|
+
val: stream.contentLength - stream.bytesRemaining,
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
if (stream.bytesRemaining < 0) {
|
|
398
|
+
throw {
|
|
399
|
+
tag: "HTTP-request-body-size",
|
|
400
|
+
val: stream.contentLength - stream.bytesRemaining,
|
|
401
|
+
};
|
|
402
|
+
}
|
|
403
|
+
stream.end();
|
|
404
|
+
return;
|
|
407
405
|
}
|
|
408
406
|
case HTTP_OUTGOING_BODY_DISPOSE:
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
407
|
+
if (debug && !streams.has(id)) {
|
|
408
|
+
console.warn(`wasi-io: stream ${id} not found to dispose`);
|
|
409
|
+
}
|
|
410
|
+
streams.delete(id);
|
|
411
|
+
return;
|
|
414
412
|
case HTTP_SERVER_START:
|
|
415
|
-
|
|
413
|
+
return startHttpServer(id, payload);
|
|
416
414
|
case HTTP_SERVER_STOP:
|
|
417
|
-
|
|
415
|
+
return stopHttpServer(id);
|
|
418
416
|
case HTTP_SERVER_SET_OUTGOING_RESPONSE:
|
|
419
|
-
|
|
417
|
+
return setOutgoingResponse(id, payload);
|
|
420
418
|
case HTTP_SERVER_CLEAR_OUTGOING_RESPONSE:
|
|
421
|
-
|
|
419
|
+
return clearOutgoingResponse(id);
|
|
422
420
|
case HTTP_SERVER_GET_ADDRESS:
|
|
423
|
-
|
|
421
|
+
return getHttpServerAddress(id);
|
|
424
422
|
|
|
425
|
-
|
|
423
|
+
// Sockets name resolution
|
|
426
424
|
case SOCKET_RESOLVE_ADDRESS_CREATE_REQUEST:
|
|
427
|
-
|
|
425
|
+
return createFuture(socketResolveAddress(payload));
|
|
428
426
|
case SOCKET_RESOLVE_ADDRESS_SUBSCRIBE_REQUEST:
|
|
429
|
-
|
|
427
|
+
return createPoll(futures.get(id).pollState);
|
|
430
428
|
case SOCKET_RESOLVE_ADDRESS_DISPOSE_REQUEST:
|
|
431
|
-
|
|
429
|
+
return void futureDispose(id, true);
|
|
432
430
|
case SOCKET_RESOLVE_ADDRESS_TAKE_REQUEST: {
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
431
|
+
const val = futureTakeValue(id);
|
|
432
|
+
if (val === undefined) {
|
|
433
|
+
throw "would-block";
|
|
434
|
+
}
|
|
435
|
+
// double take avoidance is ensured
|
|
436
|
+
return val.val;
|
|
439
437
|
}
|
|
440
438
|
|
|
441
439
|
// Sockets TCP
|
|
442
440
|
case SOCKET_TCP_ACCEPT:
|
|
443
|
-
|
|
441
|
+
return socketTcpAccept(id);
|
|
444
442
|
case SOCKET_TCP_CREATE_HANDLE:
|
|
445
|
-
|
|
443
|
+
return createTcpSocket();
|
|
446
444
|
case SOCKET_TCP_BIND_START:
|
|
447
|
-
|
|
445
|
+
return socketTcpBindStart(id, payload.localAddress, payload.family);
|
|
448
446
|
case SOCKET_TCP_BIND_FINISH:
|
|
449
|
-
|
|
447
|
+
return socketTcpFinish(id, SOCKET_STATE_BIND, SOCKET_STATE_BOUND);
|
|
450
448
|
case SOCKET_TCP_CONNECT_START:
|
|
451
|
-
|
|
452
|
-
id,
|
|
453
|
-
payload.remoteAddress,
|
|
454
|
-
payload.family
|
|
455
|
-
);
|
|
449
|
+
return socketTcpConnectStart(id, payload.remoteAddress, payload.family);
|
|
456
450
|
case SOCKET_TCP_CONNECT_FINISH:
|
|
457
|
-
|
|
458
|
-
id,
|
|
459
|
-
SOCKET_STATE_CONNECT,
|
|
460
|
-
SOCKET_STATE_CONNECTION
|
|
461
|
-
);
|
|
451
|
+
return socketTcpFinish(id, SOCKET_STATE_CONNECT, SOCKET_STATE_CONNECTION);
|
|
462
452
|
case SOCKET_TCP_LISTEN_START:
|
|
463
|
-
|
|
453
|
+
return socketTcpListenStart(id);
|
|
464
454
|
case SOCKET_TCP_LISTEN_FINISH:
|
|
465
|
-
|
|
466
|
-
id,
|
|
467
|
-
SOCKET_STATE_LISTEN,
|
|
468
|
-
SOCKET_STATE_LISTENER
|
|
469
|
-
);
|
|
455
|
+
return socketTcpFinish(id, SOCKET_STATE_LISTEN, SOCKET_STATE_LISTENER);
|
|
470
456
|
case SOCKET_TCP_IS_LISTENING:
|
|
471
|
-
|
|
457
|
+
return tcpSockets.get(id).state === SOCKET_STATE_LISTENER;
|
|
472
458
|
case SOCKET_GET_DEFAULT_SEND_BUFFER_SIZE:
|
|
473
|
-
|
|
459
|
+
return getDefaultSendBufferSize(id);
|
|
474
460
|
case SOCKET_GET_DEFAULT_RECEIVE_BUFFER_SIZE:
|
|
475
|
-
|
|
461
|
+
return getDefaultReceiveBufferSize(id);
|
|
476
462
|
case SOCKET_TCP_SET_LISTEN_BACKLOG_SIZE:
|
|
477
|
-
|
|
463
|
+
return socketTcpSetListenBacklogSize(id);
|
|
478
464
|
case SOCKET_TCP_GET_LOCAL_ADDRESS:
|
|
479
|
-
|
|
465
|
+
return socketTcpGetLocalAddress(id);
|
|
480
466
|
case SOCKET_TCP_GET_REMOTE_ADDRESS:
|
|
481
|
-
|
|
467
|
+
return socketTcpGetRemoteAddress(id);
|
|
482
468
|
case SOCKET_TCP_SHUTDOWN:
|
|
483
|
-
|
|
469
|
+
return socketTcpShutdown(id, payload);
|
|
484
470
|
case SOCKET_TCP_SUBSCRIBE:
|
|
485
|
-
|
|
471
|
+
return createPoll(tcpSockets.get(id).pollState);
|
|
486
472
|
case SOCKET_TCP_SET_KEEP_ALIVE:
|
|
487
|
-
|
|
473
|
+
return socketTcpSetKeepAlive(id, payload);
|
|
488
474
|
case SOCKET_TCP_DISPOSE:
|
|
489
|
-
|
|
475
|
+
return socketTcpDispose(id);
|
|
490
476
|
|
|
491
|
-
|
|
477
|
+
// Sockets UDP
|
|
492
478
|
case SOCKET_UDP_CREATE_HANDLE:
|
|
493
|
-
|
|
479
|
+
return createUdpSocket(payload);
|
|
494
480
|
case SOCKET_UDP_BIND_START:
|
|
495
|
-
|
|
481
|
+
return socketUdpBindStart(id, payload.localAddress, payload.family);
|
|
496
482
|
case SOCKET_UDP_BIND_FINISH:
|
|
497
|
-
|
|
483
|
+
return socketUdpBindFinish(id);
|
|
498
484
|
case SOCKET_UDP_STREAM:
|
|
499
|
-
|
|
485
|
+
return socketUdpStream(id, payload);
|
|
500
486
|
case SOCKET_UDP_SUBSCRIBE:
|
|
501
|
-
|
|
487
|
+
return createPoll(udpSockets.get(id).pollState);
|
|
502
488
|
case SOCKET_UDP_GET_LOCAL_ADDRESS:
|
|
503
|
-
|
|
489
|
+
return socketUdpGetLocalAddress(id);
|
|
504
490
|
case SOCKET_UDP_GET_REMOTE_ADDRESS:
|
|
505
|
-
|
|
491
|
+
return socketUdpGetRemoteAddress(id);
|
|
506
492
|
case SOCKET_UDP_SET_RECEIVE_BUFFER_SIZE:
|
|
507
|
-
|
|
493
|
+
return socketUdpSetReceiveBufferSize(id, payload);
|
|
508
494
|
case SOCKET_UDP_SET_SEND_BUFFER_SIZE:
|
|
509
|
-
|
|
495
|
+
return socketUdpSetSendBufferSize(id, payload);
|
|
510
496
|
case SOCKET_UDP_SET_UNICAST_HOP_LIMIT:
|
|
511
|
-
|
|
497
|
+
return socketUdpSetUnicastHopLimit(id, payload);
|
|
512
498
|
case SOCKET_UDP_GET_RECEIVE_BUFFER_SIZE:
|
|
513
|
-
|
|
499
|
+
return socketUdpGetReceiveBufferSize(id);
|
|
514
500
|
case SOCKET_UDP_GET_SEND_BUFFER_SIZE:
|
|
515
|
-
|
|
501
|
+
return socketUdpGetSendBufferSize(id);
|
|
516
502
|
case SOCKET_UDP_GET_UNICAST_HOP_LIMIT:
|
|
517
|
-
|
|
503
|
+
return socketUdpGetUnicastHopLimit(id);
|
|
518
504
|
case SOCKET_UDP_DISPOSE:
|
|
519
|
-
|
|
505
|
+
return socketUdpDispose(id);
|
|
520
506
|
|
|
521
507
|
case SOCKET_INCOMING_DATAGRAM_STREAM_RECEIVE:
|
|
522
|
-
|
|
508
|
+
return socketIncomingDatagramStreamReceive(id, payload);
|
|
523
509
|
case SOCKET_OUTGOING_DATAGRAM_STREAM_CHECK_SEND:
|
|
524
|
-
|
|
510
|
+
return socketOutgoingDatagramStreamCheckSend(id);
|
|
525
511
|
case SOCKET_OUTGOING_DATAGRAM_STREAM_SEND:
|
|
526
|
-
|
|
512
|
+
return socketOutgoingDatagramStreamSend(id, payload);
|
|
527
513
|
case SOCKET_DATAGRAM_STREAM_SUBSCRIBE:
|
|
528
|
-
|
|
514
|
+
return createPoll(datagramStreams.get(id).pollState);
|
|
529
515
|
case SOCKET_DATAGRAM_STREAM_DISPOSE:
|
|
530
|
-
|
|
516
|
+
return socketDatagramStreamDispose(id);
|
|
531
517
|
|
|
532
|
-
|
|
518
|
+
// Stdio
|
|
533
519
|
case OUTPUT_STREAM_BLOCKING_FLUSH | STDOUT:
|
|
534
520
|
case OUTPUT_STREAM_BLOCKING_FLUSH | STDERR:
|
|
535
|
-
|
|
536
|
-
|
|
521
|
+
// no blocking flush for stdio in Node.js
|
|
522
|
+
return;
|
|
537
523
|
case OUTPUT_STREAM_DISPOSE | STDOUT:
|
|
538
524
|
case OUTPUT_STREAM_DISPOSE | STDERR:
|
|
539
|
-
|
|
525
|
+
return;
|
|
540
526
|
case INPUT_STREAM_CREATE | STDIN: {
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
);
|
|
527
|
+
return createReadableStream(
|
|
528
|
+
new Readable({
|
|
529
|
+
read(n) {
|
|
530
|
+
if (n <= 0) {
|
|
531
|
+
return void this.push(null);
|
|
532
|
+
}
|
|
533
|
+
let buf = Buffer.allocUnsafeSlow(n);
|
|
534
|
+
read(0, buf, 0, n, null, (err, bytesRead) => {
|
|
535
|
+
if (err) {
|
|
536
|
+
if (err.code === "EAGAIN") {
|
|
537
|
+
nextTick(() => void this._read(n));
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
this.destroy(err);
|
|
541
|
+
} else if (bytesRead > 0) {
|
|
542
|
+
if (bytesRead !== buf.length) {
|
|
543
|
+
const dst = Buffer.allocUnsafeSlow(bytesRead);
|
|
544
|
+
buf.copy(dst, 0, 0, bytesRead);
|
|
545
|
+
buf = dst;
|
|
546
|
+
}
|
|
547
|
+
this.push(buf);
|
|
548
|
+
} else {
|
|
549
|
+
this.push(null);
|
|
550
|
+
}
|
|
551
|
+
});
|
|
552
|
+
},
|
|
553
|
+
}),
|
|
554
|
+
);
|
|
570
555
|
}
|
|
571
556
|
|
|
572
557
|
// Clocks
|
|
573
558
|
case CLOCKS_DURATION_SUBSCRIBE:
|
|
574
|
-
|
|
575
|
-
|
|
559
|
+
payload = hrtime.bigint() + payload;
|
|
560
|
+
// fallthrough
|
|
576
561
|
case CLOCKS_INSTANT_SUBSCRIBE: {
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
562
|
+
const pollState = {
|
|
563
|
+
ready: false,
|
|
564
|
+
listener: null,
|
|
565
|
+
polls: [],
|
|
566
|
+
parentStream: null,
|
|
567
|
+
};
|
|
568
|
+
subscribeInstant(pollState, payload);
|
|
569
|
+
return createPoll(pollState);
|
|
585
570
|
}
|
|
586
571
|
|
|
587
572
|
// Filesystem
|
|
588
573
|
case INPUT_STREAM_CREATE | FILE: {
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
574
|
+
const { fd, offset } = payload;
|
|
575
|
+
const stream = createReadStream(null, {
|
|
576
|
+
fd,
|
|
577
|
+
autoClose: false,
|
|
578
|
+
highWaterMark: 64 * 1024,
|
|
579
|
+
start: Number(offset),
|
|
580
|
+
});
|
|
581
|
+
return createReadableStream(stream);
|
|
597
582
|
}
|
|
598
583
|
case OUTPUT_STREAM_CREATE | FILE: {
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
}
|
|
584
|
+
const { fd, offset } = payload;
|
|
585
|
+
const stream = createWriteStream(null, {
|
|
586
|
+
fd,
|
|
587
|
+
autoClose: false,
|
|
588
|
+
emitClose: false,
|
|
589
|
+
highWaterMark: 64 * 1024,
|
|
590
|
+
start: Number(offset),
|
|
591
|
+
});
|
|
592
|
+
return createWritableStream(stream);
|
|
609
593
|
}
|
|
594
|
+
}
|
|
610
595
|
|
|
611
|
-
|
|
612
|
-
|
|
596
|
+
// Generic call implementations (streams + polls)
|
|
597
|
+
switch (call & CALL_MASK) {
|
|
613
598
|
case INPUT_STREAM_READ: {
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
return new Uint8Array();
|
|
617
|
-
}
|
|
618
|
-
const res = stream.stream.read(
|
|
619
|
-
Math.min(stream.stream.readableLength, Number(payload))
|
|
620
|
-
);
|
|
621
|
-
if (res) {
|
|
622
|
-
return res;
|
|
623
|
-
}
|
|
624
|
-
if (stream.stream.readableEnded) {
|
|
625
|
-
throw { tag: 'closed' };
|
|
626
|
-
}
|
|
599
|
+
const stream = getStreamOrThrow(id);
|
|
600
|
+
if (!stream.pollState.ready) {
|
|
627
601
|
return new Uint8Array();
|
|
602
|
+
}
|
|
603
|
+
const res = stream.stream.read(Math.min(stream.stream.readableLength, Number(payload)));
|
|
604
|
+
if (res) {
|
|
605
|
+
return res;
|
|
606
|
+
}
|
|
607
|
+
if (stream.stream.readableEnded) {
|
|
608
|
+
throw { tag: "closed" };
|
|
609
|
+
}
|
|
610
|
+
return new Uint8Array();
|
|
628
611
|
}
|
|
629
612
|
case INPUT_STREAM_BLOCKING_READ: {
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
}
|
|
639
|
-
return new Promise(
|
|
640
|
-
(resolve) => void (pollState.listener = resolve)
|
|
641
|
-
).then(() =>
|
|
642
|
-
handle(INPUT_STREAM_READ | (call & CALL_TYPE_MASK), id, payload)
|
|
643
|
-
);
|
|
613
|
+
const { pollState } = streams.get(id);
|
|
614
|
+
pollStateCheck(pollState);
|
|
615
|
+
if (pollState.ready) {
|
|
616
|
+
return handle(INPUT_STREAM_READ | (call & CALL_TYPE_MASK), id, payload);
|
|
617
|
+
}
|
|
618
|
+
return new Promise((resolve) => void (pollState.listener = resolve)).then(() =>
|
|
619
|
+
handle(INPUT_STREAM_READ | (call & CALL_TYPE_MASK), id, payload),
|
|
620
|
+
);
|
|
644
621
|
}
|
|
645
622
|
case INPUT_STREAM_SKIP:
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
623
|
+
return handle(
|
|
624
|
+
INPUT_STREAM_READ | (call & CALL_TYPE_MASK),
|
|
625
|
+
id,
|
|
626
|
+
new Uint8Array(Number(payload)),
|
|
627
|
+
);
|
|
651
628
|
case INPUT_STREAM_BLOCKING_SKIP:
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
629
|
+
return handle(
|
|
630
|
+
INPUT_STREAM_BLOCKING_READ | (call & CALL_TYPE_MASK),
|
|
631
|
+
id,
|
|
632
|
+
new Uint8Array(Number(payload)),
|
|
633
|
+
);
|
|
657
634
|
case INPUT_STREAM_SUBSCRIBE:
|
|
658
|
-
|
|
635
|
+
return createPoll(streams.get(id).pollState);
|
|
659
636
|
case INPUT_STREAM_DISPOSE: {
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
637
|
+
const stream = streams.get(id);
|
|
638
|
+
verifyPollsDroppedForDrop(stream.pollState, "input stream");
|
|
639
|
+
streams.delete(id);
|
|
640
|
+
return;
|
|
664
641
|
}
|
|
665
642
|
case OUTPUT_STREAM_CHECK_WRITE: {
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
643
|
+
const { stream, pollState } = getStreamOrThrow(id);
|
|
644
|
+
const bytes = stream.writableHighWaterMark - stream.writableLength;
|
|
645
|
+
if (bytes === 0) {
|
|
646
|
+
pollState.ready = false;
|
|
647
|
+
}
|
|
648
|
+
return BigInt(bytes);
|
|
672
649
|
}
|
|
673
650
|
case OUTPUT_STREAM_WRITE: {
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
throw new Error(
|
|
680
|
-
'wasi-io trap: attempt to write too many bytes'
|
|
681
|
-
);
|
|
682
|
-
}
|
|
683
|
-
return void stream.write(payload);
|
|
651
|
+
const { stream } = getStreamOrThrow(id);
|
|
652
|
+
if (payload.byteLength > stream.writableHighWaterMark - stream.writableLength) {
|
|
653
|
+
throw new Error("wasi-io trap: attempt to write too many bytes");
|
|
654
|
+
}
|
|
655
|
+
return void stream.write(payload);
|
|
684
656
|
}
|
|
685
657
|
case OUTPUT_STREAM_BLOCKING_WRITE_AND_FLUSH: {
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
pollStateReady(stream.pollState);
|
|
718
|
-
resolve(BigInt(payload.byteLength));
|
|
719
|
-
} else {
|
|
720
|
-
stream.stream.write(payload, (err) => {
|
|
721
|
-
stream.flushPromise = null;
|
|
722
|
-
pollStateReady(stream.pollState);
|
|
723
|
-
if (err) {
|
|
724
|
-
return void reject(streamError(err));
|
|
725
|
-
}
|
|
726
|
-
resolve(BigInt(payload.byteLength));
|
|
727
|
-
});
|
|
658
|
+
const stream = getStreamOrThrow(id);
|
|
659
|
+
// if an existing flush, try again after that
|
|
660
|
+
if (stream.flushPromise) {
|
|
661
|
+
return stream.flushPromise.then(() => handle(call, id, payload));
|
|
662
|
+
}
|
|
663
|
+
if (payload.byteLength > stream.stream.writableHighWaterMark - stream.stream.writableLength) {
|
|
664
|
+
throw new Error("wasi-io trap: Cannot write more than permitted writable length");
|
|
665
|
+
}
|
|
666
|
+
stream.pollState.ready = false;
|
|
667
|
+
return (stream.flushPromise = new Promise((resolve, reject) => {
|
|
668
|
+
if (stream.stream === stdout || stream.stream === stderr) {
|
|
669
|
+
// Inside workers, NodeJS actually queues writes destined for
|
|
670
|
+
// stdout/stderr in a port that is only flushed on exit of the worker.
|
|
671
|
+
//
|
|
672
|
+
// In this case, we cannot attempt to wait for the promise.
|
|
673
|
+
//
|
|
674
|
+
// This code may have to be reworked for browsers.
|
|
675
|
+
//
|
|
676
|
+
// see: https://github.com/nodejs/node/blob/v22.12.0/lib/internal/worker/io.js#L288
|
|
677
|
+
// see: https://github.com/nodejs/node/blob/v22.12.0/lib/internal/worker.js#L303
|
|
678
|
+
// see: https://github.com/nodejs/node/blob/v22.12.0/typings/internalBinding/messaging.d.ts#L27
|
|
679
|
+
stream.stream.write(payload);
|
|
680
|
+
stream.flushPromise = null;
|
|
681
|
+
pollStateReady(stream.pollState);
|
|
682
|
+
resolve(BigInt(payload.byteLength));
|
|
683
|
+
} else {
|
|
684
|
+
stream.stream.write(payload, (err) => {
|
|
685
|
+
stream.flushPromise = null;
|
|
686
|
+
pollStateReady(stream.pollState);
|
|
687
|
+
if (err) {
|
|
688
|
+
return void reject(streamError(err));
|
|
728
689
|
}
|
|
729
|
-
|
|
690
|
+
resolve(BigInt(payload.byteLength));
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
}));
|
|
730
694
|
}
|
|
731
695
|
case OUTPUT_STREAM_FLUSH: {
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
}
|
|
761
|
-
resolve();
|
|
762
|
-
});
|
|
696
|
+
const stream = getStreamOrThrow(id);
|
|
697
|
+
if (stream.flushPromise) {
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
stream.pollState.ready = false;
|
|
701
|
+
stream.flushPromise = new Promise((resolve, reject) => {
|
|
702
|
+
if (stream.stream === stdout || stream.stream === stderr) {
|
|
703
|
+
// Inside workers, NodeJS actually queues writes destined for
|
|
704
|
+
// stdout/stderr in a port that is only flushed on exit of the worker.
|
|
705
|
+
//
|
|
706
|
+
// In this case, we cannot attempt to wait for the promise.
|
|
707
|
+
//
|
|
708
|
+
// This code may have to be reworked for browsers.
|
|
709
|
+
//
|
|
710
|
+
// see: https://github.com/nodejs/node/blob/v22.12.0/lib/internal/worker/io.js#L288
|
|
711
|
+
// see: https://github.com/nodejs/node/blob/v22.12.0/lib/internal/worker.js#L303
|
|
712
|
+
// see: https://github.com/nodejs/node/blob/v22.12.0/typings/internalBinding/messaging.d.ts#L27
|
|
713
|
+
stream.flushPromise = null;
|
|
714
|
+
pollStateReady(stream.pollState);
|
|
715
|
+
resolve();
|
|
716
|
+
} else {
|
|
717
|
+
// For all other writes, we can perform the actual write and expect the write to complete
|
|
718
|
+
// and trigger the relevant callback
|
|
719
|
+
stream.stream.write(new Uint8Array([]), (err) => {
|
|
720
|
+
stream.flushPromise = null;
|
|
721
|
+
pollStateReady(stream.pollState);
|
|
722
|
+
if (err) {
|
|
723
|
+
return void reject(streamError(err));
|
|
763
724
|
}
|
|
764
|
-
|
|
765
|
-
|
|
725
|
+
resolve();
|
|
726
|
+
});
|
|
727
|
+
}
|
|
728
|
+
});
|
|
729
|
+
return stream.flushPromise;
|
|
766
730
|
}
|
|
767
731
|
case OUTPUT_STREAM_BLOCKING_FLUSH: {
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
732
|
+
const stream = getStreamOrThrow(id);
|
|
733
|
+
if (stream.flushPromise) {
|
|
734
|
+
return stream.flushPromise;
|
|
735
|
+
}
|
|
736
|
+
return new Promise((resolve, reject) => {
|
|
737
|
+
if (stream.stream === stdout || stream.stream === stderr) {
|
|
738
|
+
// Inside workers, NodeJS actually queues writes destined for
|
|
739
|
+
// stdout/stderr in a port that is only flushed on exit of the worker.
|
|
740
|
+
//
|
|
741
|
+
// In this case, we cannot attempt to wait for the promise.
|
|
742
|
+
//
|
|
743
|
+
// This code may have to be reworked for browsers.
|
|
744
|
+
//
|
|
745
|
+
// see: https://github.com/nodejs/node/blob/v22.12.0/lib/internal/worker/io.js#L288
|
|
746
|
+
// see: https://github.com/nodejs/node/blob/v22.12.0/lib/internal/worker.js#L303
|
|
747
|
+
// see: https://github.com/nodejs/node/blob/v22.12.0/typings/internalBinding/messaging.d.ts#L27
|
|
748
|
+
resolve();
|
|
749
|
+
} else {
|
|
750
|
+
// For all other writes, we can perform the actual write and expect the write to complete
|
|
751
|
+
// and trigger the relevant callback
|
|
752
|
+
stream.stream.write(new Uint8Array([]), (err) =>
|
|
753
|
+
err ? reject(streamError(err)) : resolve(),
|
|
754
|
+
);
|
|
771
755
|
}
|
|
772
|
-
|
|
773
|
-
if (stream.stream === stdout || stream.stream === stderr) {
|
|
774
|
-
// Inside workers, NodeJS actually queues writes destined for
|
|
775
|
-
// stdout/stderr in a port that is only flushed on exit of the worker.
|
|
776
|
-
//
|
|
777
|
-
// In this case, we cannot attempt to wait for the promise.
|
|
778
|
-
//
|
|
779
|
-
// This code may have to be reworked for browsers.
|
|
780
|
-
//
|
|
781
|
-
// see: https://github.com/nodejs/node/blob/v22.12.0/lib/internal/worker/io.js#L288
|
|
782
|
-
// see: https://github.com/nodejs/node/blob/v22.12.0/lib/internal/worker.js#L303
|
|
783
|
-
// see: https://github.com/nodejs/node/blob/v22.12.0/typings/internalBinding/messaging.d.ts#L27
|
|
784
|
-
resolve();
|
|
785
|
-
} else {
|
|
786
|
-
// For all other writes, we can perform the actual write and expect the write to complete
|
|
787
|
-
// and trigger the relevant callback
|
|
788
|
-
stream.stream.write(new Uint8Array([]), (err) =>
|
|
789
|
-
err ? reject(streamError(err)) : resolve()
|
|
790
|
-
);
|
|
791
|
-
}
|
|
792
|
-
});
|
|
756
|
+
});
|
|
793
757
|
}
|
|
794
758
|
case OUTPUT_STREAM_WRITE_ZEROES:
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
759
|
+
return handle(
|
|
760
|
+
OUTPUT_STREAM_WRITE | (call & CALL_TYPE_MASK),
|
|
761
|
+
id,
|
|
762
|
+
new Uint8Array(Number(payload)),
|
|
763
|
+
);
|
|
800
764
|
case OUTPUT_STREAM_BLOCKING_WRITE_ZEROES_AND_FLUSH:
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
);
|
|
765
|
+
return handle(
|
|
766
|
+
OUTPUT_STREAM_BLOCKING_WRITE_AND_FLUSH | (call & CALL_TYPE_MASK),
|
|
767
|
+
id,
|
|
768
|
+
new Uint8Array(Number(payload)),
|
|
769
|
+
);
|
|
807
770
|
case OUTPUT_STREAM_SPLICE: {
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
return payload.len - BigInt(bytesRemaining);
|
|
771
|
+
const outputStream = getStreamOrThrow(id);
|
|
772
|
+
const inputStream = getStreamOrThrow(payload.src);
|
|
773
|
+
let bytesRemaining = Number(payload.len);
|
|
774
|
+
let chunk;
|
|
775
|
+
while (
|
|
776
|
+
bytesRemaining > 0 &&
|
|
777
|
+
(chunk = inputStream.stream.read(
|
|
778
|
+
Math.min(
|
|
779
|
+
outputStream.writableHighWaterMark - outputStream.writableLength,
|
|
780
|
+
bytesRemaining,
|
|
781
|
+
),
|
|
782
|
+
))
|
|
783
|
+
) {
|
|
784
|
+
bytesRemaining -= chunk.byteLength;
|
|
785
|
+
outputStream.stream.write(chunk);
|
|
786
|
+
}
|
|
787
|
+
if (inputStream.stream.errored) {
|
|
788
|
+
throw streamError(inputStream.stream.errored);
|
|
789
|
+
}
|
|
790
|
+
if (outputStream.stream.errored) {
|
|
791
|
+
throw streamError(outputStream.stream.errored);
|
|
792
|
+
}
|
|
793
|
+
return payload.len - BigInt(bytesRemaining);
|
|
832
794
|
}
|
|
833
795
|
case OUTPUT_STREAM_SUBSCRIBE:
|
|
834
|
-
|
|
796
|
+
return createPoll(streams.get(id).pollState);
|
|
835
797
|
case OUTPUT_STREAM_BLOCKING_SPLICE: {
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
throw streamError(err);
|
|
851
|
-
}
|
|
852
|
-
);
|
|
853
|
-
}
|
|
854
|
-
const inputStream = getStreamOrThrow(payload.src);
|
|
855
|
-
if (!inputStream.stream.readable) {
|
|
856
|
-
promise = promise.then(() =>
|
|
857
|
-
new Promise((_resolve, _reject) => {
|
|
858
|
-
inputStream.stream
|
|
859
|
-
.once('readable', (resolve = _resolve))
|
|
860
|
-
.once('error', (reject = _reject));
|
|
861
|
-
}).then(
|
|
862
|
-
() => {
|
|
863
|
-
inputStream.stream.off('error', reject);
|
|
864
|
-
},
|
|
865
|
-
(err) => {
|
|
866
|
-
inputStream.stream.off('readable', resolve);
|
|
867
|
-
throw streamError(err);
|
|
868
|
-
}
|
|
869
|
-
)
|
|
870
|
-
);
|
|
871
|
-
}
|
|
872
|
-
return promise.then(() =>
|
|
873
|
-
handle(OUTPUT_STREAM_SPLICE, id, payload)
|
|
798
|
+
const outputStream = getStreamOrThrow(id);
|
|
799
|
+
let promise = Promise.resolve();
|
|
800
|
+
let resolve, reject;
|
|
801
|
+
if (outputStream.stream.writableNeedDrain) {
|
|
802
|
+
promise = new Promise((_resolve, _reject) => {
|
|
803
|
+
outputStream.stream.once("drain", (resolve = _resolve)).once("error", (reject = _reject));
|
|
804
|
+
}).then(
|
|
805
|
+
() => {
|
|
806
|
+
outputStream.stream.off("error", reject);
|
|
807
|
+
},
|
|
808
|
+
(err) => {
|
|
809
|
+
outputStream.stream.off("drain", resolve);
|
|
810
|
+
throw streamError(err);
|
|
811
|
+
},
|
|
874
812
|
);
|
|
813
|
+
}
|
|
814
|
+
const inputStream = getStreamOrThrow(payload.src);
|
|
815
|
+
if (!inputStream.stream.readable) {
|
|
816
|
+
promise = promise.then(() =>
|
|
817
|
+
new Promise((_resolve, _reject) => {
|
|
818
|
+
inputStream.stream
|
|
819
|
+
.once("readable", (resolve = _resolve))
|
|
820
|
+
.once("error", (reject = _reject));
|
|
821
|
+
}).then(
|
|
822
|
+
() => {
|
|
823
|
+
inputStream.stream.off("error", reject);
|
|
824
|
+
},
|
|
825
|
+
(err) => {
|
|
826
|
+
inputStream.stream.off("readable", resolve);
|
|
827
|
+
throw streamError(err);
|
|
828
|
+
},
|
|
829
|
+
),
|
|
830
|
+
);
|
|
831
|
+
}
|
|
832
|
+
return promise.then(() => handle(OUTPUT_STREAM_SPLICE, id, payload));
|
|
875
833
|
}
|
|
876
834
|
case OUTPUT_STREAM_DISPOSE: {
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
835
|
+
const stream = streams.get(id);
|
|
836
|
+
verifyPollsDroppedForDrop(stream.pollState, "output stream");
|
|
837
|
+
stream.stream.end();
|
|
838
|
+
streams.delete(id);
|
|
839
|
+
return;
|
|
882
840
|
}
|
|
883
841
|
|
|
884
842
|
case POLL_POLLABLE_READY:
|
|
885
|
-
|
|
843
|
+
return polls.get(id).ready;
|
|
886
844
|
case POLL_POLLABLE_BLOCK:
|
|
887
|
-
|
|
888
|
-
|
|
845
|
+
payload = [id];
|
|
846
|
+
// [intentional case fall-through]
|
|
889
847
|
case POLL_POLL_LIST: {
|
|
890
|
-
|
|
891
|
-
|
|
848
|
+
if (payload.length === 0) {
|
|
849
|
+
throw new Error("wasi-io trap: attempt to poll on empty list");
|
|
850
|
+
}
|
|
851
|
+
const doneList = [];
|
|
852
|
+
const pollList = payload.map((pollId) => polls.get(pollId));
|
|
853
|
+
for (const [idx, pollState] of pollList.entries()) {
|
|
854
|
+
pollStateCheck(pollState);
|
|
855
|
+
if (pollState.ready) {
|
|
856
|
+
doneList.push(idx);
|
|
892
857
|
}
|
|
893
|
-
|
|
894
|
-
|
|
858
|
+
}
|
|
859
|
+
if (doneList.length > 0) {
|
|
860
|
+
return new Uint32Array(doneList);
|
|
861
|
+
}
|
|
862
|
+
let readyPromiseResolve;
|
|
863
|
+
const readyPromise = new Promise((resolve) => void (readyPromiseResolve = resolve));
|
|
864
|
+
for (const poll of pollList) {
|
|
865
|
+
poll.listener = readyPromiseResolve;
|
|
866
|
+
}
|
|
867
|
+
return readyPromise.then(() => {
|
|
895
868
|
for (const [idx, pollState] of pollList.entries()) {
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
869
|
+
pollState.listener = null;
|
|
870
|
+
if (pollState.ready) {
|
|
871
|
+
doneList.push(idx);
|
|
872
|
+
}
|
|
900
873
|
}
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
}
|
|
904
|
-
let readyPromiseResolve;
|
|
905
|
-
const readyPromise = new Promise(
|
|
906
|
-
(resolve) => void (readyPromiseResolve = resolve)
|
|
907
|
-
);
|
|
908
|
-
for (const poll of pollList) {
|
|
909
|
-
poll.listener = readyPromiseResolve;
|
|
910
|
-
}
|
|
911
|
-
return readyPromise.then(() => {
|
|
912
|
-
for (const [idx, pollState] of pollList.entries()) {
|
|
913
|
-
pollState.listener = null;
|
|
914
|
-
if (pollState.ready) {
|
|
915
|
-
doneList.push(idx);
|
|
916
|
-
}
|
|
917
|
-
}
|
|
918
|
-
return new Uint32Array(doneList);
|
|
919
|
-
});
|
|
874
|
+
return new Uint32Array(doneList);
|
|
875
|
+
});
|
|
920
876
|
}
|
|
921
877
|
case POLL_POLLABLE_DISPOSE:
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
}
|
|
927
|
-
return;
|
|
878
|
+
if (!polls.delete(id)) {
|
|
879
|
+
throw new Error(`wasi-io trap: Disposed a poll ${id} that does not exist`);
|
|
880
|
+
}
|
|
881
|
+
return;
|
|
928
882
|
|
|
929
883
|
case FUTURE_TAKE_VALUE:
|
|
930
|
-
|
|
884
|
+
return futureTakeValue(id);
|
|
931
885
|
|
|
932
886
|
case FUTURE_SUBSCRIBE: {
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
887
|
+
const { pollState } = futures.get(id);
|
|
888
|
+
const pollId = ++pollCnt;
|
|
889
|
+
polls.set(pollId, pollState);
|
|
890
|
+
return pollId;
|
|
937
891
|
}
|
|
938
892
|
case FUTURE_DISPOSE:
|
|
939
|
-
|
|
893
|
+
return void futureDispose(id, true);
|
|
940
894
|
default:
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
895
|
+
throw new Error(
|
|
896
|
+
`wasi-io trap: Unknown call ${call} (${reverseMap[call]}) with type ${
|
|
897
|
+
reverseMap[call & CALL_TYPE_MASK]
|
|
898
|
+
}`,
|
|
899
|
+
);
|
|
900
|
+
}
|
|
947
901
|
}
|
|
948
902
|
|
|
949
903
|
/**
|
|
950
904
|
* @param {PollState} pollState
|
|
951
905
|
*/
|
|
952
906
|
function createPoll(pollState) {
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
907
|
+
const pollId = ++pollCnt;
|
|
908
|
+
pollState.polls.push(pollId);
|
|
909
|
+
polls.set(pollId, pollState);
|
|
910
|
+
return pollId;
|
|
957
911
|
}
|
|
958
912
|
|
|
959
913
|
function subscribeInstant(pollState, instant) {
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
}
|
|
968
|
-
pollStateReady(pollState);
|
|
969
|
-
}
|
|
970
|
-
if (duration < 10e6) {
|
|
971
|
-
setImmediate(cb);
|
|
972
|
-
} else {
|
|
973
|
-
setTimeout(cb, Number(duration) / 1e6);
|
|
914
|
+
const duration = instant - hrtime.bigint();
|
|
915
|
+
if (duration <= 0) {
|
|
916
|
+
return pollStateReady(pollState);
|
|
917
|
+
}
|
|
918
|
+
function cb() {
|
|
919
|
+
if (hrtime.bigint() < instant) {
|
|
920
|
+
return subscribeInstant(pollState, instant);
|
|
974
921
|
}
|
|
922
|
+
pollStateReady(pollState);
|
|
923
|
+
}
|
|
924
|
+
if (duration < 10e6) {
|
|
925
|
+
setImmediate(cb);
|
|
926
|
+
} else {
|
|
927
|
+
setTimeout(cb, Number(duration) / 1e6);
|
|
928
|
+
}
|
|
975
929
|
}
|
|
976
930
|
|
|
977
931
|
/**
|
|
@@ -979,14 +933,14 @@ function subscribeInstant(pollState, instant) {
|
|
|
979
933
|
* @param {string} polledResourceDebugName
|
|
980
934
|
*/
|
|
981
935
|
export function verifyPollsDroppedForDrop(pollState, polledResourceDebugName) {
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
}
|
|
936
|
+
for (const pollId of pollState.polls) {
|
|
937
|
+
const poll = polls.get(pollId);
|
|
938
|
+
if (poll) {
|
|
939
|
+
throw new Error(
|
|
940
|
+
`wasi-io trap: Cannot drop ${polledResourceDebugName} as it has a child poll resource which has not yet been dropped`,
|
|
941
|
+
);
|
|
989
942
|
}
|
|
943
|
+
}
|
|
990
944
|
}
|
|
991
945
|
|
|
992
946
|
/**
|
|
@@ -994,41 +948,39 @@ export function verifyPollsDroppedForDrop(pollState, polledResourceDebugName) {
|
|
|
994
948
|
* @param {bool} finished
|
|
995
949
|
*/
|
|
996
950
|
export function pollStateReady(pollState) {
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
pollState.
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
pollState.listener = null;
|
|
1006
|
-
}
|
|
951
|
+
if (pollState.ready && pollState.listener) {
|
|
952
|
+
uncaughtException = new Error("wasi-io trap: poll already ready with listener attached");
|
|
953
|
+
}
|
|
954
|
+
pollState.ready = true;
|
|
955
|
+
if (pollState.listener) {
|
|
956
|
+
pollState.listener();
|
|
957
|
+
pollState.listener = null;
|
|
958
|
+
}
|
|
1007
959
|
}
|
|
1008
960
|
|
|
1009
961
|
/**
|
|
1010
962
|
* @param {PollState} pollState
|
|
1011
963
|
*/
|
|
1012
964
|
function pollStateCheck(pollState) {
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
}
|
|
965
|
+
if (pollState.ready && pollState.parentStream) {
|
|
966
|
+
// stream ONLY applies to readable streams here
|
|
967
|
+
const stream = pollState.parentStream;
|
|
968
|
+
const res = stream.read(0);
|
|
969
|
+
if (res !== null) {
|
|
970
|
+
throw new Error("wasi-io trap: got data for a null read");
|
|
971
|
+
}
|
|
972
|
+
if (
|
|
973
|
+
pollState.ready &&
|
|
974
|
+
stream.readableLength === 0 &&
|
|
975
|
+
!stream.readableEnded &&
|
|
976
|
+
!stream.errored
|
|
977
|
+
) {
|
|
978
|
+
pollState.ready = false;
|
|
979
|
+
stream.once("readable", () => {
|
|
980
|
+
pollStateReady(pollState);
|
|
981
|
+
});
|
|
1031
982
|
}
|
|
983
|
+
}
|
|
1032
984
|
}
|
|
1033
985
|
|
|
1034
986
|
/**
|
|
@@ -1038,31 +990,31 @@ function pollStateCheck(pollState) {
|
|
|
1038
990
|
* @returns {number}
|
|
1039
991
|
*/
|
|
1040
992
|
export function createFuture(promise, pollState) {
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
993
|
+
const futureId = ++futureCnt;
|
|
994
|
+
if (pollState) {
|
|
995
|
+
pollState.ready = false;
|
|
996
|
+
} else {
|
|
997
|
+
pollState = {
|
|
998
|
+
ready: false,
|
|
999
|
+
listener: null,
|
|
1000
|
+
polls: [],
|
|
1001
|
+
parent: null,
|
|
1002
|
+
};
|
|
1003
|
+
}
|
|
1004
|
+
const future = { tag: "ok", val: null };
|
|
1005
|
+
futures.set(futureId, { future, pollState });
|
|
1006
|
+
promise.then(
|
|
1007
|
+
(value) => {
|
|
1008
|
+
pollStateReady(pollState);
|
|
1009
|
+
future.val = value;
|
|
1010
|
+
},
|
|
1011
|
+
(value) => {
|
|
1012
|
+
pollStateReady(pollState);
|
|
1013
|
+
future.tag = "err";
|
|
1014
|
+
future.val = value;
|
|
1015
|
+
},
|
|
1016
|
+
);
|
|
1017
|
+
return futureId;
|
|
1066
1018
|
}
|
|
1067
1019
|
|
|
1068
1020
|
/**
|
|
@@ -1071,29 +1023,29 @@ export function createFuture(promise, pollState) {
|
|
|
1071
1023
|
* @throws {undefined}
|
|
1072
1024
|
*/
|
|
1073
1025
|
export function futureTakeValue(id) {
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1026
|
+
const future = futures.get(id);
|
|
1027
|
+
// Not ready = return undefined
|
|
1028
|
+
if (!future.pollState.ready) {
|
|
1029
|
+
return undefined;
|
|
1030
|
+
}
|
|
1031
|
+
// Ready but already taken = return { tag: 'err', val: undefined }
|
|
1032
|
+
if (!future.future) {
|
|
1033
|
+
return { tag: "err", val: undefined };
|
|
1034
|
+
}
|
|
1035
|
+
const out = { tag: "ok", val: future.future };
|
|
1036
|
+
future.future = null;
|
|
1037
|
+
return out;
|
|
1086
1038
|
}
|
|
1087
1039
|
|
|
1088
1040
|
export function futureDispose(id, ownsState) {
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1092
|
-
|
|
1093
|
-
|
|
1041
|
+
const { pollState } = futures.get(id);
|
|
1042
|
+
if (ownsState) {
|
|
1043
|
+
verifyPollsDroppedForDrop(pollState, "future");
|
|
1044
|
+
}
|
|
1045
|
+
return void futures.delete(id);
|
|
1094
1046
|
}
|
|
1095
1047
|
|
|
1096
1048
|
let uncaughtException;
|
|
1097
|
-
process.on(
|
|
1049
|
+
process.on("uncaughtException", (err) => (uncaughtException = err));
|
|
1098
1050
|
|
|
1099
1051
|
const debug = runAsWorker(handle);
|