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