@bytecodealliance/preview3-shim 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -60,7 +60,7 @@ declare class Descriptor {
|
|
|
60
60
|
* @returns {Promise<void>}
|
|
61
61
|
* @throws {FSError} `payload.tag` contains mapped WASI error code.
|
|
62
62
|
*/
|
|
63
|
-
advise(
|
|
63
|
+
advise(offset: any, length: any, advice: any): Promise<void>;
|
|
64
64
|
/**
|
|
65
65
|
* Synchronize file data to disk.
|
|
66
66
|
* WIT:
|
|
@@ -158,11 +158,14 @@ class Descriptor {
|
|
|
158
158
|
* @returns {Promise<void>}
|
|
159
159
|
* @throws {FSError} `payload.tag` contains mapped WASI error code.
|
|
160
160
|
*/
|
|
161
|
-
async advise(
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
161
|
+
async advise(offset, length, advice) {
|
|
162
|
+
this.#ensureHandle();
|
|
163
|
+
try {
|
|
164
|
+
const { fadvise } = await import("@bytecodealliance/jco-node-fs");
|
|
165
|
+
fadvise(this.#handle.fd, offset, length, advice);
|
|
166
|
+
}
|
|
167
|
+
catch (error) {
|
|
168
|
+
throw FSError.from(error);
|
|
166
169
|
}
|
|
167
170
|
}
|
|
168
171
|
/**
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { Server, Socket } from "node:net";
|
|
2
|
-
import { Readable } from "stream";
|
|
3
|
-
import { pipeline } from "stream/promises";
|
|
4
2
|
import { once } from "node:events";
|
|
5
3
|
import { isMainThread, parentPort } from "worker_threads";
|
|
6
4
|
//#region dist/nodejs/workers/resource-worker.js
|
|
@@ -382,10 +380,29 @@ async function handleTcpSend({ socketId, stream }) {
|
|
|
382
380
|
const socket = sockets.get(socketId);
|
|
383
381
|
socket.activeStreams++;
|
|
384
382
|
const { tcp } = socket;
|
|
385
|
-
const
|
|
383
|
+
const reader = stream.getReader();
|
|
384
|
+
let rejectOnSocketError;
|
|
385
|
+
const socketError = new Promise((_resolve, reject) => {
|
|
386
|
+
rejectOnSocketError = reject;
|
|
387
|
+
});
|
|
388
|
+
tcp.once("error", rejectOnSocketError);
|
|
386
389
|
try {
|
|
387
|
-
|
|
390
|
+
while (true) {
|
|
391
|
+
const { done, value } = await Promise.race([reader.read(), socketError]);
|
|
392
|
+
if (done) break;
|
|
393
|
+
await Promise.race([new Promise((resolve, reject) => {
|
|
394
|
+
tcp.write(value, (err) => err ? reject(err) : resolve());
|
|
395
|
+
}), socketError]);
|
|
396
|
+
}
|
|
397
|
+
await new Promise((resolve, reject) => {
|
|
398
|
+
tcp.end((err) => err ? reject(err) : resolve());
|
|
399
|
+
});
|
|
400
|
+
} catch (err) {
|
|
401
|
+
reader.cancel(err).catch(() => {});
|
|
402
|
+
throw err;
|
|
388
403
|
} finally {
|
|
404
|
+
tcp.off("error", rejectOnSocketError);
|
|
405
|
+
reader.releaseLock();
|
|
389
406
|
socket.activeStreams--;
|
|
390
407
|
cleanupDisposedSocket(socketId, socket);
|
|
391
408
|
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import { Socket, Server } from "node:net";
|
|
2
|
-
import { Readable } from "stream";
|
|
3
|
-
import { pipeline } from "stream/promises";
|
|
4
2
|
import { once } from "node:events";
|
|
5
3
|
import { Router } from "../workers/resource-worker.js";
|
|
6
4
|
import { serializeIpAddress, makeIpAddress, ipAddressConflict } from "../sockets/address.js";
|
|
@@ -170,11 +168,44 @@ async function handleTcpSend({ socketId, stream }) {
|
|
|
170
168
|
const socket = sockets.get(socketId);
|
|
171
169
|
socket.activeStreams++;
|
|
172
170
|
const { tcp } = socket;
|
|
173
|
-
const
|
|
171
|
+
const reader = stream.getReader();
|
|
172
|
+
let rejectOnSocketError;
|
|
173
|
+
const socketError = new Promise((_resolve, reject) => {
|
|
174
|
+
rejectOnSocketError = reject;
|
|
175
|
+
});
|
|
176
|
+
tcp.once("error", rejectOnSocketError);
|
|
174
177
|
try {
|
|
175
|
-
|
|
178
|
+
// Do not replace this pump with stream.pipeline(). Node 26 changed async
|
|
179
|
+
// iteration to preserve allowHalfOpen duplex streams. For WASI TCP send,
|
|
180
|
+
// however, a write failure must promptly cancel the transferred input
|
|
181
|
+
// stream so the guest's stream writer is dropped. Explicitly awaiting each
|
|
182
|
+
// write keeps socket backpressure and cancellation coupled across workers.
|
|
183
|
+
while (true) {
|
|
184
|
+
const { done, value } = await Promise.race([reader.read(), socketError]);
|
|
185
|
+
if (done) {
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
188
|
+
await Promise.race([
|
|
189
|
+
new Promise((resolve, reject) => {
|
|
190
|
+
tcp.write(value, (err) => (err ? reject(err) : resolve()));
|
|
191
|
+
}),
|
|
192
|
+
socketError,
|
|
193
|
+
]);
|
|
194
|
+
}
|
|
195
|
+
await new Promise((resolve, reject) => {
|
|
196
|
+
tcp.end((err) => (err ? reject(err) : resolve()));
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
catch (err) {
|
|
200
|
+
// Cancellation crosses the worker boundary. Do not wait for its completion:
|
|
201
|
+
// the producer can itself be waiting for this operation's result, which
|
|
202
|
+
// would turn error propagation into a cycle.
|
|
203
|
+
void reader.cancel(err).catch(() => { });
|
|
204
|
+
throw err;
|
|
176
205
|
}
|
|
177
206
|
finally {
|
|
207
|
+
tcp.off("error", rejectOnSocketError);
|
|
208
|
+
reader.releaseLock();
|
|
178
209
|
socket.activeStreams--;
|
|
179
210
|
cleanupDisposedSocket(socketId, socket);
|
|
180
211
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bytecodealliance/preview3-shim",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "WASI Preview3 shim for JS environments",
|
|
5
5
|
"homepage": "https://github.com/bytecodealliance/jco/blob/main/packages/preview3-shim/#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -48,7 +48,8 @@
|
|
|
48
48
|
}
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@bytecodealliance/
|
|
51
|
+
"@bytecodealliance/jco-node-fs": "0.2.0",
|
|
52
|
+
"@bytecodealliance/preview2-shim": "^0.22.0"
|
|
52
53
|
},
|
|
53
54
|
"devDependencies": {
|
|
54
55
|
"@types/node": "^24.12.4",
|