mirror of
https://github.com/zebrajr/node.git
synced 2026-01-15 12:15:26 +00:00
wasi: allow WASI stdio to be configured
This commit adds stdin, stderr, and stdout options to WASI, which allow the stdio streams to be configured. PR-URL: https://github.com/nodejs/node/pull/33544 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: David Carlier <devnexen@gmail.com> Reviewed-By: Juan José Arboleda <soyjuanarbol@gmail.com> Reviewed-By: Zeyu Yang <himself65@outlook.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
committed by
Ruben Bridgewater
parent
e2d3230565
commit
e3b54b4d1c
@@ -66,6 +66,12 @@ added:
|
||||
process via the `__wasi_proc_exit()` function. Setting this option to `true`
|
||||
causes `wasi.start()` to return the exit code rather than terminate the
|
||||
process. **Default:** `false`.
|
||||
* `stdin` {integer} The file descriptor used as standard input in the
|
||||
WebAssembly application. **Default:** `0`.
|
||||
* `stdout` {integer} The file descriptor used as standard output in the
|
||||
WebAssembly application. **Default:** `1`.
|
||||
* `stderr` {integer} The file descriptor used as standard error in the
|
||||
WebAssembly application. **Default:** `2`.
|
||||
|
||||
### `wasi.start(instance)`
|
||||
<!-- YAML
|
||||
|
||||
@@ -16,6 +16,7 @@ const { isArrayBuffer } = require('internal/util/types');
|
||||
const {
|
||||
validateArray,
|
||||
validateBoolean,
|
||||
validateInt32,
|
||||
validateObject,
|
||||
} = require('internal/validators');
|
||||
const { WASI: _WASI } = internalBinding('wasi');
|
||||
@@ -51,7 +52,13 @@ class WASI {
|
||||
}
|
||||
}
|
||||
|
||||
const wrap = new _WASI(args, env, preopens);
|
||||
const { stdin = 0, stdout = 1, stderr = 2 } = options;
|
||||
validateInt32(stdin, 'options.stdin', 0);
|
||||
validateInt32(stdout, 'options.stdout', 0);
|
||||
validateInt32(stderr, 'options.stderr', 0);
|
||||
const stdio = [stdin, stdout, stderr];
|
||||
|
||||
const wrap = new _WASI(args, env, preopens, stdio);
|
||||
|
||||
for (const prop in wrap) {
|
||||
wrap[prop] = FunctionPrototypeBind(wrap[prop], wrap);
|
||||
|
||||
@@ -163,10 +163,11 @@ void WASI::DecreaseAllocatedSize(size_t size) {
|
||||
|
||||
void WASI::New(const FunctionCallbackInfo<Value>& args) {
|
||||
CHECK(args.IsConstructCall());
|
||||
CHECK_EQ(args.Length(), 3);
|
||||
CHECK_EQ(args.Length(), 4);
|
||||
CHECK(args[0]->IsArray());
|
||||
CHECK(args[1]->IsArray());
|
||||
CHECK(args[2]->IsArray());
|
||||
CHECK(args[3]->IsArray());
|
||||
|
||||
Environment* env = Environment::GetCurrent(args);
|
||||
Local<Context> context = env->context();
|
||||
@@ -174,9 +175,15 @@ void WASI::New(const FunctionCallbackInfo<Value>& args) {
|
||||
const uint32_t argc = argv->Length();
|
||||
uvwasi_options_t options;
|
||||
|
||||
options.in = 0;
|
||||
options.out = 1;
|
||||
options.err = 2;
|
||||
Local<Array> stdio = args[3].As<Array>();
|
||||
CHECK_EQ(stdio->Length(), 3);
|
||||
options.in = stdio->Get(context, 0).ToLocalChecked()->
|
||||
Int32Value(context).FromJust();
|
||||
options.out = stdio->Get(context, 1).ToLocalChecked()->
|
||||
Int32Value(context).FromJust();
|
||||
options.err = stdio->Get(context, 2).ToLocalChecked()->
|
||||
Int32Value(context).FromJust();
|
||||
|
||||
options.fd_table_size = 3;
|
||||
options.argc = argc;
|
||||
options.argv =
|
||||
|
||||
@@ -25,6 +25,18 @@ assert.throws(() => { new WASI({ preopens: 'fhqwhgads' }); },
|
||||
assert.throws(() => { new WASI({ returnOnExit: 'fhqwhgads' }); },
|
||||
{ code: 'ERR_INVALID_ARG_TYPE', message: /\breturnOnExit\b/ });
|
||||
|
||||
// If stdin is not an int32 and not undefined, it should throw.
|
||||
assert.throws(() => { new WASI({ stdin: 'fhqwhgads' }); },
|
||||
{ code: 'ERR_INVALID_ARG_TYPE', message: /\bstdin\b/ });
|
||||
|
||||
// If stdout is not an int32 and not undefined, it should throw.
|
||||
assert.throws(() => { new WASI({ stdout: 'fhqwhgads' }); },
|
||||
{ code: 'ERR_INVALID_ARG_TYPE', message: /\bstdout\b/ });
|
||||
|
||||
// If stderr is not an int32 and not undefined, it should throw.
|
||||
assert.throws(() => { new WASI({ stderr: 'fhqwhgads' }); },
|
||||
{ code: 'ERR_INVALID_ARG_TYPE', message: /\bstderr\b/ });
|
||||
|
||||
// If options is provided, but not an object, the constructor should throw.
|
||||
[null, 'foo', '', 0, NaN, Symbol(), true, false, () => {}].forEach((value) => {
|
||||
assert.throws(() => { new WASI(value); },
|
||||
|
||||
34
test/wasi/test-wasi-stdio.js
Normal file
34
test/wasi/test-wasi-stdio.js
Normal file
@@ -0,0 +1,34 @@
|
||||
// Flags: --experimental-wasi-unstable-preview1 --experimental-wasm-bigint
|
||||
'use strict';
|
||||
require('../common');
|
||||
const tmpdir = require('../common/tmpdir');
|
||||
const { strictEqual } = require('assert');
|
||||
const { closeSync, openSync, readFileSync, writeFileSync } = require('fs');
|
||||
const { join } = require('path');
|
||||
const { WASI } = require('wasi');
|
||||
const modulePath = join(__dirname, 'wasm', 'stdin.wasm');
|
||||
const buffer = readFileSync(modulePath);
|
||||
const stdinFile = join(tmpdir.path, 'stdin.txt');
|
||||
const stdoutFile = join(tmpdir.path, 'stdout.txt');
|
||||
const stderrFile = join(tmpdir.path, 'stderr.txt');
|
||||
|
||||
tmpdir.refresh();
|
||||
// Write 33 x's. The test's buffer only holds 31 x's + a terminator.
|
||||
writeFileSync(stdinFile, 'x'.repeat(33));
|
||||
|
||||
const stdin = openSync(stdinFile, 'r');
|
||||
const stdout = openSync(stdoutFile, 'a');
|
||||
const stderr = openSync(stderrFile, 'a');
|
||||
const wasi = new WASI({ stdin, stdout, stderr, returnOnExit: true });
|
||||
const importObject = { wasi_snapshot_preview1: wasi.wasiImport };
|
||||
|
||||
(async () => {
|
||||
const { instance } = await WebAssembly.instantiate(buffer, importObject);
|
||||
|
||||
strictEqual(wasi.start(instance), 0);
|
||||
closeSync(stdin);
|
||||
closeSync(stdout);
|
||||
closeSync(stderr);
|
||||
strictEqual(readFileSync(stdoutFile, 'utf8').trim(), 'x'.repeat(31));
|
||||
strictEqual(readFileSync(stderrFile, 'utf8').trim(), '');
|
||||
})();
|
||||
Reference in New Issue
Block a user