Skip to content
Snippets Groups Projects
Commit 4ea15010 authored by Cheng Shao's avatar Cheng Shao :beach:
Browse files

wasm: support wasi console redirect for the ghci browser mode

This commit adds optional support for redirecting wasi console
stdout/stderr back to the host when running wasm ghci browser mode. By
default, the wasi console outputs are only available under F12
devtools console, but in case of testing against a mobile browser, the
devtools console may not be readily available, and it would be more
convenient to at least get wasi console output on the host side.

The redirection logic is simple, just adding another two WebSockets
connections that pump the line-buffered textual messages back to
host.

(cherry picked from commit ad7e271d)
parent d8cddd75
No related branches found
No related tags found
No related merge requests found
......@@ -370,8 +370,11 @@ export class DyLDRPC {
#origin;
#wsPipe;
#wsSig;
#redirectWasiConsole;
#wsStdout;
#wsStderr;
constructor({ origin }) {
constructor({ origin, redirectWasiConsole }) {
this.#origin = origin;
const ws_url = this.#origin.replace("http://", "ws://");
......@@ -399,8 +402,17 @@ export class DyLDRPC {
this.#wsSig = new WebSocket(ws_url, "sig");
this.#wsSig.binaryType = "arraybuffer";
this.#redirectWasiConsole = redirectWasiConsole;
if (redirectWasiConsole) {
this.#wsStdout = new WebSocket(ws_url, "stdout");
this.#wsStderr = new WebSocket(ws_url, "stderr");
}
this.opened = Promise.all(
[this.#wsPipe, this.#wsSig].map(
(redirectWasiConsole
? [this.#wsPipe, this.#wsSig, this.#wsStdout, this.#wsStderr]
: [this.#wsPipe, this.#wsSig]
).map(
(ws) =>
new Promise((res, rej) => {
ws.addEventListener("open", res);
......@@ -413,6 +425,10 @@ export class DyLDRPC {
close() {
this.#wsPipe.close();
this.#wsSig.close();
if (this.#redirectWasiConsole) {
this.#wsStdout.close();
this.#wsStderr.close();
}
}
async #rpc(endpoint, ...args) {
......@@ -444,6 +460,22 @@ export class DyLDRPC {
async fetchWasm(p) {
return fetch(`${this.#origin}/fs${p}`);
}
stdout(msg) {
if (this.#redirectWasiConsole) {
this.#wsStdout.send(msg);
} else {
console.info(msg);
}
}
stderr(msg) {
if (this.#redirectWasiConsole) {
this.#wsStderr.send(msg);
} else {
console.warn(msg);
}
}
}
// Actual implementation of endpoints used by DyLDRPC
......@@ -452,7 +484,15 @@ class DyLDRPCServer {
#server;
#wss;
constructor({ host, port, dyldPath, libdir, ghciSoPath, args }) {
constructor({
host,
port,
dyldPath,
libdir,
ghciSoPath,
args,
redirectWasiConsole,
}) {
this.#server = http.createServer(async (req, res) => {
const origin = originFromServerAddress(await this.listening);
......@@ -487,7 +527,7 @@ class DyLDRPCServer {
`
import { DyLDRPC, main } from "./fs${dyldPath}";
const args = ${JSON.stringify({ libdir, ghciSoPath, args })};
args.rpc = new DyLDRPC({origin: "${origin}"});
args.rpc = new DyLDRPC({origin: "${origin}", redirectWasiConsole: ${redirectWasiConsole}});
args.rpc.opened.then(() => main(args));
`
);
......@@ -578,6 +618,16 @@ args.rpc.opened.then(() => main(args));
return;
}
if (ws.protocol === "stdout") {
ws.addEventListener("message", (ev) => console.info(ev.data));
return;
}
if (ws.protocol === "stderr") {
ws.addEventListener("message", (ev) => console.warn(ev.data));
return;
}
throw new Error(`unknown protocol ${ws.protocol}`);
});
......@@ -682,12 +732,8 @@ class DyLD {
new wasi.OpenFile(
new wasi.File(new Uint8Array(), { readonly: true })
),
wasi.ConsoleStdout.lineBuffered((msg) =>
console.log(`[WASI stdout] ${msg}`)
),
wasi.ConsoleStdout.lineBuffered((msg) =>
console.warn(`[WASI stderr] ${msg}`)
),
wasi.ConsoleStdout.lineBuffered((msg) => this.#rpc.stdout(msg)),
wasi.ConsoleStdout.lineBuffered((msg) => this.#rpc.stderr(msg)),
],
{ debug: false }
);
......@@ -1126,6 +1172,11 @@ export async function main({ rpc, libdir, ghciSoPath, args }) {
libdir,
ghciSoPath,
args,
redirectWasiConsole:
process.env.GHCI_BROWSER_PUPPETEER_LAUNCH_OPTS ||
process.env.GHCI_BROWSER_PLAYWRIGHT_BROWSER_TYPE
? false
: Boolean(process.env.GHCI_BROWSER_REDIRECT_WASI_CONSOLE),
});
const origin = originFromServerAddress(await server.listening);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment