@bytecodealliance/preview3-shim 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/nodejs/cli.js +2 -1
- package/dist/nodejs/filesystem/descriptor.js +2 -1
- package/dist/nodejs/http/client.js +2 -1
- package/dist/nodejs/http/fields.js +7 -2
- package/dist/nodejs/http/server.js +2 -1
- package/dist/nodejs/sockets/tcp.js +2 -1
- package/dist/nodejs/sockets/udp.js +2 -1
- package/dist/nodejs/workers/cli-worker.bundle.js +88 -0
- package/dist/nodejs/workers/filesystem-worker.bundle.js +236 -0
- package/dist/nodejs/workers/filesystem-worker.js +8 -1
- package/dist/nodejs/workers/http-worker.bundle.js +403 -0
- package/dist/nodejs/workers/resource-worker.d.ts +1 -1
- package/dist/nodejs/workers/resource-worker.js +5 -5
- package/dist/nodejs/workers/tcp-worker.bundle.js +496 -0
- package/dist/nodejs/workers/udp-worker.bundle.js +270 -0
- package/package.json +3 -2
package/dist/nodejs/cli.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import process from "node:process";
|
|
2
2
|
import { Readable } from "node:stream";
|
|
3
|
+
import { Worker } from "node:worker_threads";
|
|
3
4
|
import { ResourceWorker } from "./workers/resource-worker.js";
|
|
4
5
|
import { StreamReader, readableByteStreamFromReader } from "./stream.js";
|
|
5
6
|
import { future } from "./future.js";
|
|
@@ -16,7 +17,7 @@ export const environment = {
|
|
|
16
17
|
};
|
|
17
18
|
let WORKER = null;
|
|
18
19
|
function worker() {
|
|
19
|
-
return (WORKER ??= new ResourceWorker(new URL("./workers/cli-worker.js", import.meta.url)));
|
|
20
|
+
return (WORKER ??= new ResourceWorker(() => new Worker(new URL("./workers/cli-worker.bundle.js", import.meta.url))));
|
|
20
21
|
}
|
|
21
22
|
/**
|
|
22
23
|
* Map a Node.js error to a WIT error-code enum value.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
2
|
import nodePath from "node:path";
|
|
3
3
|
import process from "node:process";
|
|
4
|
+
import { Worker } from "node:worker_threads";
|
|
4
5
|
import { StreamReader, readableByteStreamFromReader } from "../stream.js";
|
|
5
6
|
import { FutureReader } from "../future.js";
|
|
6
7
|
import { ResourceWorker } from "../workers/resource-worker.js";
|
|
@@ -10,7 +11,7 @@ import { wasiTypeFromDirent } from "./utils.js";
|
|
|
10
11
|
const symbolDispose = Symbol.dispose || Symbol.for("dispose");
|
|
11
12
|
let WORKER = null;
|
|
12
13
|
function worker() {
|
|
13
|
-
return (WORKER ??= new ResourceWorker(new URL("../workers/filesystem-worker.js", import.meta.url)));
|
|
14
|
+
return (WORKER ??= new ResourceWorker(() => new Worker(new URL("../workers/filesystem-worker.bundle.js", import.meta.url))));
|
|
14
15
|
}
|
|
15
16
|
class Descriptor {
|
|
16
17
|
/** Node.js file handle for file operations (FileHandle from fs.promises.open) */
|
|
@@ -8,7 +8,7 @@ import { Response } from "./response.js";
|
|
|
8
8
|
import { _fieldsFromEntriesChecked, _readTrailersForTransport, _trailerResultFromEntries, } from "./fields.js";
|
|
9
9
|
let WORKER = null;
|
|
10
10
|
function worker() {
|
|
11
|
-
return (WORKER ??= new ResourceWorker(new URL("../workers/http-worker.js", import.meta.url)));
|
|
11
|
+
return (WORKER ??= new ResourceWorker(() => new Worker(new URL("../workers/http-worker.bundle.js", import.meta.url))));
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
14
14
|
* HTTP client interface.
|
|
@@ -136,3 +136,4 @@ class TrailerFutureReader extends FutureReader {
|
|
|
136
136
|
super.close();
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
|
+
import { Worker } from "node:worker_threads";
|
|
@@ -6,9 +6,14 @@ export const _forbiddenHeaders = {
|
|
|
6
6
|
get value() {
|
|
7
7
|
return (FORBIDDEN_HEADERS ??= new Set([
|
|
8
8
|
"connection",
|
|
9
|
-
"
|
|
9
|
+
"http2-settings",
|
|
10
10
|
"host",
|
|
11
|
-
"
|
|
11
|
+
"keep-alive",
|
|
12
|
+
"proxy-authenticate",
|
|
13
|
+
"proxy-authorization",
|
|
14
|
+
"proxy-connection",
|
|
15
|
+
"transfer-encoding",
|
|
16
|
+
"upgrade",
|
|
12
17
|
]));
|
|
13
18
|
},
|
|
14
19
|
};
|
|
@@ -9,7 +9,7 @@ import { HttpError } from "./error.js";
|
|
|
9
9
|
import { _fieldsFromEntriesChecked, _readTrailersForTransport, _trailerResultFromEntries, } from "./fields.js";
|
|
10
10
|
let WORKER = null;
|
|
11
11
|
function worker() {
|
|
12
|
-
return (WORKER ??= new ResourceWorker(new URL("../workers/http-worker.js", import.meta.url)));
|
|
12
|
+
return (WORKER ??= new ResourceWorker(() => new Worker(new URL("../workers/http-worker.bundle.js", import.meta.url))));
|
|
13
13
|
}
|
|
14
14
|
/**
|
|
15
15
|
* HttpServer uses a background worker thread to handle raw HTTP connections,
|
|
@@ -125,3 +125,4 @@ const requestFromParts = (parts) => {
|
|
|
125
125
|
req.setPathWithQuery(url);
|
|
126
126
|
return req;
|
|
127
127
|
};
|
|
128
|
+
import { Worker } from "node:worker_threads";
|
|
@@ -6,7 +6,7 @@ import { isWildcardIpAddress, isUnicastIpAddress, isMulticastIpAddress, isIpv4Ma
|
|
|
6
6
|
let WORKER = null;
|
|
7
7
|
const symbolDispose = Symbol.dispose || Symbol.for("dispose");
|
|
8
8
|
function worker() {
|
|
9
|
-
return (WORKER ??= new ResourceWorker(new URL("../workers/tcp-worker.js", import.meta.url)));
|
|
9
|
+
return (WORKER ??= new ResourceWorker(() => new Worker(new URL("../workers/tcp-worker.bundle.js", import.meta.url))));
|
|
10
10
|
}
|
|
11
11
|
let TCP_CREATE_TOKEN = null;
|
|
12
12
|
function token() {
|
|
@@ -721,3 +721,4 @@ export class TcpSocket {
|
|
|
721
721
|
!isIpv4MappedAddress(remoteAddress));
|
|
722
722
|
}
|
|
723
723
|
}
|
|
724
|
+
import { Worker } from "node:worker_threads";
|
|
@@ -3,7 +3,7 @@ import { SocketError } from "./error.js";
|
|
|
3
3
|
import { isWildcardIpAddress, isUnicastIpAddress, isIpv4MappedAddress, isBindableIpAddress, IP_ADDRESS_FAMILY, } from "./address.js";
|
|
4
4
|
let WORKER = null;
|
|
5
5
|
function worker() {
|
|
6
|
-
return (WORKER ??= new ResourceWorker(new URL("../workers/udp-worker.js", import.meta.url)));
|
|
6
|
+
return (WORKER ??= new ResourceWorker(() => new Worker(new URL("../workers/udp-worker.bundle.js", import.meta.url))));
|
|
7
7
|
}
|
|
8
8
|
let UDP_CREATE_TOKEN = null;
|
|
9
9
|
function token() {
|
|
@@ -473,3 +473,4 @@ export class UdpSocket {
|
|
|
473
473
|
}
|
|
474
474
|
}
|
|
475
475
|
export const udpCreateSocket = {};
|
|
476
|
+
import { Worker } from "node:worker_threads";
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import process from "node:process";
|
|
2
|
+
import { Readable } from "node:stream";
|
|
3
|
+
import { pipeline } from "stream/promises";
|
|
4
|
+
import { isMainThread, parentPort } from "worker_threads";
|
|
5
|
+
//#region dist/nodejs/workers/resource-worker.js
|
|
6
|
+
function Router() {
|
|
7
|
+
const _hooks = {
|
|
8
|
+
beforeAll: null,
|
|
9
|
+
ops: /* @__PURE__ */ new Map()
|
|
10
|
+
};
|
|
11
|
+
if (isMainThread || !parentPort) throw new Error("Router can only be used in worker threads");
|
|
12
|
+
parentPort.on("message", async (msg) => {
|
|
13
|
+
const { _reply, _condvar, ...rest } = msg;
|
|
14
|
+
let result, error, transfer = [];
|
|
15
|
+
try {
|
|
16
|
+
if (_hooks.beforeAll) _hooks.beforeAll(rest);
|
|
17
|
+
const handler = _hooks.ops.get(rest.op);
|
|
18
|
+
if (!handler) throw new Error(`Unknown op ${rest.op}`);
|
|
19
|
+
const outcome = await handler(rest);
|
|
20
|
+
if (outcome && Array.isArray(outcome.transferable)) {
|
|
21
|
+
result = outcome.result;
|
|
22
|
+
transfer = outcome.transferable;
|
|
23
|
+
} else result = outcome;
|
|
24
|
+
} catch (err) {
|
|
25
|
+
error = serializeError(err);
|
|
26
|
+
}
|
|
27
|
+
_reply.postMessage({
|
|
28
|
+
result,
|
|
29
|
+
error
|
|
30
|
+
}, transfer);
|
|
31
|
+
_reply.close();
|
|
32
|
+
if (_condvar) notify(_condvar);
|
|
33
|
+
});
|
|
34
|
+
return {
|
|
35
|
+
beforeAll(fn) {
|
|
36
|
+
_hooks.beforeAll = fn;
|
|
37
|
+
return this;
|
|
38
|
+
},
|
|
39
|
+
op(name, fn) {
|
|
40
|
+
_hooks.ops.set(name, fn);
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function serializeError(err) {
|
|
46
|
+
if (!(err instanceof Error)) return err;
|
|
47
|
+
const serialized = {
|
|
48
|
+
__resourceWorkerError: true,
|
|
49
|
+
name: err.name,
|
|
50
|
+
message: err.message,
|
|
51
|
+
stack: err.stack
|
|
52
|
+
};
|
|
53
|
+
for (const key of Reflect.ownKeys(err)) serialized[key] = err[key];
|
|
54
|
+
if (err.cause !== void 0) serialized.cause = serializeError(err.cause);
|
|
55
|
+
return serialized;
|
|
56
|
+
}
|
|
57
|
+
function notify(condvar) {
|
|
58
|
+
const lock = new Int32Array(condvar);
|
|
59
|
+
Atomics.store(lock, 0, 1);
|
|
60
|
+
Atomics.notify(lock, 0, 1);
|
|
61
|
+
}
|
|
62
|
+
//#endregion
|
|
63
|
+
//#region dist/nodejs/workers/cli-worker.js
|
|
64
|
+
Router().op("stdout", handleOp).op("stderr", handleOp);
|
|
65
|
+
async function handleOp(msg) {
|
|
66
|
+
const { op, stream } = msg;
|
|
67
|
+
await pipeline(Readable.from(byteChunks(stream), { objectMode: false }), op === "stdout" ? process.stdout : process.stderr, { end: false });
|
|
68
|
+
return { ok: true };
|
|
69
|
+
}
|
|
70
|
+
async function* byteChunks(stream) {
|
|
71
|
+
for await (const value of stream) yield nodeByteChunk(value);
|
|
72
|
+
}
|
|
73
|
+
function assertByte(value) {
|
|
74
|
+
if (!Number.isInteger(value) || value < 0 || value > 255) throw new RangeError(`Invalid byte stream value: ${value}`);
|
|
75
|
+
return value;
|
|
76
|
+
}
|
|
77
|
+
function nodeByteChunk(value) {
|
|
78
|
+
if (value instanceof Uint8Array) return value;
|
|
79
|
+
if (value instanceof ArrayBuffer) return new Uint8Array(value);
|
|
80
|
+
if (Array.isArray(value)) {
|
|
81
|
+
for (const byte of value) assertByte(byte);
|
|
82
|
+
return Uint8Array.from(value);
|
|
83
|
+
}
|
|
84
|
+
if (typeof value === "number") return Uint8Array.of(assertByte(value));
|
|
85
|
+
return value;
|
|
86
|
+
}
|
|
87
|
+
//#endregion
|
|
88
|
+
export {};
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { promisify } from "util";
|
|
2
|
+
import { isMainThread, parentPort } from "worker_threads";
|
|
3
|
+
import fs from "fs";
|
|
4
|
+
//#region dist/nodejs/workers/resource-worker.js
|
|
5
|
+
function Router() {
|
|
6
|
+
const _hooks = {
|
|
7
|
+
beforeAll: null,
|
|
8
|
+
ops: /* @__PURE__ */ new Map()
|
|
9
|
+
};
|
|
10
|
+
if (isMainThread || !parentPort) throw new Error("Router can only be used in worker threads");
|
|
11
|
+
parentPort.on("message", async (msg) => {
|
|
12
|
+
const { _reply, _condvar, ...rest } = msg;
|
|
13
|
+
let result, error, transfer = [];
|
|
14
|
+
try {
|
|
15
|
+
if (_hooks.beforeAll) _hooks.beforeAll(rest);
|
|
16
|
+
const handler = _hooks.ops.get(rest.op);
|
|
17
|
+
if (!handler) throw new Error(`Unknown op ${rest.op}`);
|
|
18
|
+
const outcome = await handler(rest);
|
|
19
|
+
if (outcome && Array.isArray(outcome.transferable)) {
|
|
20
|
+
result = outcome.result;
|
|
21
|
+
transfer = outcome.transferable;
|
|
22
|
+
} else result = outcome;
|
|
23
|
+
} catch (err) {
|
|
24
|
+
error = serializeError(err);
|
|
25
|
+
}
|
|
26
|
+
_reply.postMessage({
|
|
27
|
+
result,
|
|
28
|
+
error
|
|
29
|
+
}, transfer);
|
|
30
|
+
_reply.close();
|
|
31
|
+
if (_condvar) notify(_condvar);
|
|
32
|
+
});
|
|
33
|
+
return {
|
|
34
|
+
beforeAll(fn) {
|
|
35
|
+
_hooks.beforeAll = fn;
|
|
36
|
+
return this;
|
|
37
|
+
},
|
|
38
|
+
op(name, fn) {
|
|
39
|
+
_hooks.ops.set(name, fn);
|
|
40
|
+
return this;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function serializeError(err) {
|
|
45
|
+
if (!(err instanceof Error)) return err;
|
|
46
|
+
const serialized = {
|
|
47
|
+
__resourceWorkerError: true,
|
|
48
|
+
name: err.name,
|
|
49
|
+
message: err.message,
|
|
50
|
+
stack: err.stack
|
|
51
|
+
};
|
|
52
|
+
for (const key of Reflect.ownKeys(err)) serialized[key] = err[key];
|
|
53
|
+
if (err.cause !== void 0) serialized.cause = serializeError(err.cause);
|
|
54
|
+
return serialized;
|
|
55
|
+
}
|
|
56
|
+
function notify(condvar) {
|
|
57
|
+
const lock = new Int32Array(condvar);
|
|
58
|
+
Atomics.store(lock, 0, 1);
|
|
59
|
+
Atomics.notify(lock, 0, 1);
|
|
60
|
+
}
|
|
61
|
+
//#endregion
|
|
62
|
+
//#region dist/nodejs/filesystem/error.js
|
|
63
|
+
const ERROR_MAP = {
|
|
64
|
+
EACCES: "access",
|
|
65
|
+
EALREADY: "already",
|
|
66
|
+
EBADF: "bad-descriptor",
|
|
67
|
+
EBUSY: "busy",
|
|
68
|
+
EDEADLK: "deadlock",
|
|
69
|
+
EDQUOT: "quota",
|
|
70
|
+
EEXIST: "exist",
|
|
71
|
+
EFBIG: "file-too-large",
|
|
72
|
+
EILSEQ: "illegal-byte-sequence",
|
|
73
|
+
EINPROGRESS: "in-progress",
|
|
74
|
+
EINTR: "interrupted",
|
|
75
|
+
EINVAL: "invalid",
|
|
76
|
+
EIO: "io",
|
|
77
|
+
EISDIR: "is-directory",
|
|
78
|
+
ELOOP: "loop",
|
|
79
|
+
EMLINK: "too-many-links",
|
|
80
|
+
EMSGSIZE: "message-size",
|
|
81
|
+
ENAMETOOLONG: "name-too-long",
|
|
82
|
+
ENODEV: "no-device",
|
|
83
|
+
ENOENT: "no-entry",
|
|
84
|
+
ENOLCK: "no-lock",
|
|
85
|
+
ENOMEM: "insufficient-memory",
|
|
86
|
+
ENOSPC: "insufficient-space",
|
|
87
|
+
ENOTDIR: "not-directory",
|
|
88
|
+
ERR_FS_EISDIR: "not-directory",
|
|
89
|
+
ENOTEMPTY: "not-empty",
|
|
90
|
+
ENOTRECOVERABLE: "not-recoverable",
|
|
91
|
+
ENOTSUP: "unsupported",
|
|
92
|
+
ENOTTY: "no-tty",
|
|
93
|
+
ENXIO: "no-such-device",
|
|
94
|
+
EOVERFLOW: "overflow",
|
|
95
|
+
EPERM: "not-permitted",
|
|
96
|
+
EPIPE: "pipe",
|
|
97
|
+
EROFS: "read-only",
|
|
98
|
+
ESPIPE: "invalid-seek",
|
|
99
|
+
ETXTBSY: "text-file-busy",
|
|
100
|
+
EXDEV: "cross-device"
|
|
101
|
+
};
|
|
102
|
+
function getErrorTag(e) {
|
|
103
|
+
if (e.code in ERROR_MAP) return ERROR_MAP[e.code];
|
|
104
|
+
if (e.code === -4094 || e.code === "UNKNOWN" && e.errno === -4094) return "no-such-device";
|
|
105
|
+
throw e;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Custom error for File operations with JCO compatible payload.
|
|
109
|
+
*/
|
|
110
|
+
var FSError = class FSError extends Error {
|
|
111
|
+
payload;
|
|
112
|
+
/**
|
|
113
|
+
* @param {string} tag – machine‐readable error tag
|
|
114
|
+
* @param {string} [message] – human‐readable message
|
|
115
|
+
* @param {any} [val] – optional extra data
|
|
116
|
+
* @param {object} [opts]
|
|
117
|
+
* @param {Error} [opts.cause]
|
|
118
|
+
*/
|
|
119
|
+
constructor(tag, message = void 0, val = void 0, opts = {}) {
|
|
120
|
+
super(message ?? `Error: ${tag}`, { cause: opts.cause });
|
|
121
|
+
this.name = "FSError";
|
|
122
|
+
this.payload = val !== void 0 ? {
|
|
123
|
+
tag,
|
|
124
|
+
val
|
|
125
|
+
} : { tag };
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Create or rewrap an error into FSError
|
|
129
|
+
* @param {any} err – number, string, Error, or FSError
|
|
130
|
+
*/
|
|
131
|
+
static from(err) {
|
|
132
|
+
if (err instanceof FSError) return err;
|
|
133
|
+
const tag = getErrorTag(err);
|
|
134
|
+
const message = err?.message;
|
|
135
|
+
return new FSError(tag, message, void 0, { cause: err });
|
|
136
|
+
}
|
|
137
|
+
};
|
|
138
|
+
//#endregion
|
|
139
|
+
//#region dist/nodejs/filesystem/utils.js
|
|
140
|
+
/** Map fs.Dirent -> WASI type */
|
|
141
|
+
function wasiTypeFromDirent(obj) {
|
|
142
|
+
if (obj.isFile()) return { tag: "regular-file" };
|
|
143
|
+
else if (obj.isSocket()) return { tag: "socket" };
|
|
144
|
+
else if (obj.isSymbolicLink()) return { tag: "symbolic-link" };
|
|
145
|
+
else if (obj.isFIFO()) return { tag: "fifo" };
|
|
146
|
+
else if (obj.isDirectory()) return { tag: "directory" };
|
|
147
|
+
else if (obj.isCharacterDevice()) return { tag: "character-device" };
|
|
148
|
+
else if (obj.isBlockDevice()) return { tag: "block-device" };
|
|
149
|
+
return {
|
|
150
|
+
tag: "other",
|
|
151
|
+
val: void 0
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
//#endregion
|
|
155
|
+
//#region dist/nodejs/workers/filesystem-worker.js
|
|
156
|
+
const readAsync = promisify(fs.read);
|
|
157
|
+
const writeAsync = promisify(fs.write);
|
|
158
|
+
const { opendir } = fs.promises;
|
|
159
|
+
const CHUNK_BYTES = 64 * 1024;
|
|
160
|
+
const BUFFER = Buffer.alloc(CHUNK_BYTES);
|
|
161
|
+
const MAX_SAFE_FILE_POSITION = BigInt(Number.MAX_SAFE_INTEGER);
|
|
162
|
+
/** Auto‐dispatch all ops */
|
|
163
|
+
Router().op("read", handleRead).op("write", handleWrite).op("readDir", handleReadDir);
|
|
164
|
+
async function handleRead({ fd, offset, stream }) {
|
|
165
|
+
if (typeof fd !== "number" || fd < 0) throw new TypeError(`Invalid file descriptor: ${fd}`);
|
|
166
|
+
if (!stream || typeof stream.getWriter !== "function") throw new TypeError("stream must have a getWriter() method");
|
|
167
|
+
const writer = stream.getWriter();
|
|
168
|
+
let pos = BigInt(offset);
|
|
169
|
+
try {
|
|
170
|
+
filePosition(pos);
|
|
171
|
+
} catch (err) {
|
|
172
|
+
await writer.close();
|
|
173
|
+
throw err;
|
|
174
|
+
}
|
|
175
|
+
try {
|
|
176
|
+
const start = pos;
|
|
177
|
+
while (true) {
|
|
178
|
+
const { bytesRead } = await readAsync(fd, BUFFER, 0, CHUNK_BYTES, filePosition(pos));
|
|
179
|
+
if (bytesRead === 0) break;
|
|
180
|
+
await writer.write(BUFFER.subarray(0, bytesRead));
|
|
181
|
+
pos += BigInt(bytesRead);
|
|
182
|
+
}
|
|
183
|
+
await writer.close();
|
|
184
|
+
return { bytesRead: pos - start };
|
|
185
|
+
} catch (err) {
|
|
186
|
+
await writer.abort(err);
|
|
187
|
+
throw err;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
async function handleWrite({ fd, offset, stream }) {
|
|
191
|
+
if (typeof fd !== "number" || fd < 0) throw new TypeError(`Invalid file descriptor: ${fd}`);
|
|
192
|
+
if (!stream || typeof stream.getReader !== "function") throw new TypeError("stream must have a getReader() method");
|
|
193
|
+
const reader = stream.getReader();
|
|
194
|
+
try {
|
|
195
|
+
let pos = BigInt(offset);
|
|
196
|
+
const start = pos;
|
|
197
|
+
while (true) {
|
|
198
|
+
const { done, value } = await reader.read();
|
|
199
|
+
if (done) break;
|
|
200
|
+
const buf = Buffer.from(value);
|
|
201
|
+
const { bytesWritten } = await writeAsync(fd, buf, 0, buf.length, filePosition(pos));
|
|
202
|
+
pos += BigInt(bytesWritten);
|
|
203
|
+
}
|
|
204
|
+
return { bytesWritten: pos - start };
|
|
205
|
+
} catch (err) {
|
|
206
|
+
await reader.cancel(err);
|
|
207
|
+
throw err;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
function filePosition(position) {
|
|
211
|
+
if (position < 0n || position > MAX_SAFE_FILE_POSITION) throw new FSError("invalid");
|
|
212
|
+
return Number(position);
|
|
213
|
+
}
|
|
214
|
+
async function handleReadDir({ fullPath, stream, preopens }) {
|
|
215
|
+
if (!stream || typeof stream.getWriter !== "function") throw new TypeError("stream must have a getWriter() method");
|
|
216
|
+
const writer = stream.getWriter();
|
|
217
|
+
if (!preopens.some((p) => fullPath === p || fullPath.startsWith(p + "/"))) {
|
|
218
|
+
const err = new FSError("not-permitted");
|
|
219
|
+
await writer.abort(err);
|
|
220
|
+
throw err;
|
|
221
|
+
}
|
|
222
|
+
try {
|
|
223
|
+
const walker = await opendir(fullPath);
|
|
224
|
+
for await (const dirent of walker) await writer.write({
|
|
225
|
+
name: dirent.name,
|
|
226
|
+
type: wasiTypeFromDirent(dirent)
|
|
227
|
+
});
|
|
228
|
+
await writer.close();
|
|
229
|
+
return { ok: true };
|
|
230
|
+
} catch (err) {
|
|
231
|
+
await writer.abort(err);
|
|
232
|
+
throw err;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
//#endregion
|
|
236
|
+
export {};
|
|
@@ -21,8 +21,15 @@ async function handleRead({ fd, offset, stream }) {
|
|
|
21
21
|
throw new TypeError("stream must have a getWriter() method");
|
|
22
22
|
}
|
|
23
23
|
const writer = stream.getWriter();
|
|
24
|
+
let pos = BigInt(offset);
|
|
25
|
+
try {
|
|
26
|
+
filePosition(pos);
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
await writer.close();
|
|
30
|
+
throw err;
|
|
31
|
+
}
|
|
24
32
|
try {
|
|
25
|
-
let pos = BigInt(offset);
|
|
26
33
|
const start = pos;
|
|
27
34
|
while (true) {
|
|
28
35
|
const { bytesRead } = await readAsync(fd, BUFFER, 0, CHUNK_BYTES, filePosition(pos));
|