Skip to content

Commit

Permalink
Send stdout/stderr from WasmRunner to dev server without decoding as …
Browse files Browse the repository at this point in the history
…UTF-8 (#471)

* Enable WasmRunner to handle stdout as raw binary

* catch other errors

* move devDeps

* use browser exception handling

* comment out
  • Loading branch information
omochi committed May 24, 2024
1 parent 59730f9 commit 3cb3877
Show file tree
Hide file tree
Showing 13 changed files with 224 additions and 69 deletions.
8 changes: 4 additions & 4 deletions Sources/CartonKit/Server/StaticArchive.swift

Large diffs are not rendered by default.

7 changes: 7 additions & 0 deletions Tests/Fixtures/SandboxApp/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.DS_Store
/.build
/Packages
xcuserdata/
DerivedData/
.swiftpm
.netrc
28 changes: 28 additions & 0 deletions Tests/Fixtures/SandboxApp/Package.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// swift-tools-version: 5.9

import PackageDescription

let package = Package(
name: "DevServerTestApp",
products: [
.executable(name: "app", targets: ["app"])
],
dependencies: [
.package(path: "../../.."),
.package(url: "https://github.com/swiftwasm/JavaScriptKit", from: "0.19.2")
],
targets: [
.executableTarget(
name: "app",
dependencies: [
.product(name: "JavaScriptKit", package: "JavaScriptKit")
],
resources: [
.copy("style.css")
]
),
.testTarget(
name: "SimpleTests"
)
]
)
4 changes: 4 additions & 0 deletions Tests/Fixtures/SandboxApp/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
This application serves as a working environment for experimenting with the behavior of "carton".
Since it is not used by automated tests, it can be easily modified.
If you want to include the behavior created here in automated tests,
please separate the target application for testing.
33 changes: 33 additions & 0 deletions Tests/Fixtures/SandboxApp/Sources/app/main.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#if os(WASI)
import WASILibc
typealias FILEPointer = OpaquePointer
#else
import Darwin
typealias FILEPointer = UnsafeMutablePointer<FILE>
#endif

import JavaScriptKit

func fputs(_ string: String, file: FILEPointer) {
_ = string.withCString { (cstr) in
fputs(cstr, file)
}
}

fputs("hello stdout\n", file: stdout)
fputs("hello stderr\n", file: stderr)

//fatalError("hello fatalError")

let document = JSObject.global.document

let button = document.createElement("button")
_ = button.appendChild(
document.createTextNode("click to crash")
)

_ = button.addEventListener("click", JSClosure { (e) in
fatalError("crash")
})

_ = document.body.appendChild(button)
4 changes: 4 additions & 0 deletions Tests/Fixtures/SandboxApp/Sources/app/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
* {
margin: 0;
padding: 0;
}
7 changes: 7 additions & 0 deletions Tests/Fixtures/SandboxApp/Tests/SimpleTests/BasicTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import XCTest

final class BasicTests: XCTestCase {
func testAdd() {
XCTAssertEqual(1 + 1, 2)
}
}
22 changes: 11 additions & 11 deletions entrypoint/bundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,22 +31,22 @@ const startWasiTask = async () => {
// JavaScriptKit module not available, running without JavaScriptKit runtime.
}

const wasmRunner = WasmRunner(false, runtimeConstructor);
const wasmRunner = WasmRunner({
onStdoutLine(line) {
console.log(line);
},
onStderrLine(line) {
console.error(line);
}
}, runtimeConstructor);

// Instantiate the WebAssembly file
const wasmBytes = new Uint8Array(responseArrayBuffer).buffer;
await wasmRunner.run(wasmBytes);
};

function handleError(e: any) {
console.error(e);
if (e instanceof WebAssembly.RuntimeError) {
console.log(e.stack);
}
async function main(): Promise<void> {
await startWasiTask();
}

try {
startWasiTask().catch(handleError);
} catch (e) {
handleError(e);
}
main();
70 changes: 50 additions & 20 deletions entrypoint/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,35 +15,72 @@
import { WASI, File, OpenFile, ConsoleStdout, PreopenDirectory } from "@bjorn3/browser_wasi_shim";
import type { SwiftRuntime, SwiftRuntimeConstructor } from "./JavaScriptKit_JavaScriptKit.resources/Runtime";

export class LineDecoder {
constructor(onLine: (line: string) => void) {
this.decoder = new TextDecoder("utf-8", { fatal: false });
this.buffer = "";
this.onLine = onLine;
}

private decoder: TextDecoder;
private buffer: string;
private onLine: (line: string) => void;

send(chunk: Uint8Array) {
this.buffer += this.decoder.decode(chunk, { stream: true });

const lines = this.buffer.split("\n");
for (let i = 0; i < lines.length - 1; i++) {
this.onLine(lines[i]);
}

this.buffer = lines[lines.length - 1];
}
}

export type Options = {
args?: string[];
onStdout?: (text: string) => void;
onStderr?: (text: string) => void;
onStdout?: (chunk: Uint8Array) => void;
onStdoutLine?: (line: string) => void;
onStderr?: (chunk: Uint8Array) => void;
onStderrLine?: (line: string) => void;
};

export type WasmRunner = {
run(wasmBytes: ArrayBufferLike, extraWasmImports?: WebAssembly.Imports): Promise<void>
};

export const WasmRunner = (rawOptions: Options | false, SwiftRuntime: SwiftRuntimeConstructor | undefined): WasmRunner => {
export const WasmRunner = (rawOptions: Options, SwiftRuntime: SwiftRuntimeConstructor | undefined): WasmRunner => {
const options: Options = defaultRunnerOptions(rawOptions);

let swift: SwiftRuntime;
if (SwiftRuntime) {
swift = new SwiftRuntime();
}

let stdoutLine: LineDecoder | undefined = undefined;
if (options.onStdoutLine != null) {
stdoutLine = new LineDecoder(options.onStdoutLine);
}
const stdout = new ConsoleStdout((chunk) => {
options.onStdout?.call(undefined, chunk);
stdoutLine?.send(chunk);
});

let stderrLine: LineDecoder | undefined = undefined;
if (options.onStderrLine != null) {
stderrLine = new LineDecoder(options.onStderrLine);
}
const stderr = new ConsoleStdout((chunk) => {
options.onStderr?.call(undefined, chunk);
stderrLine?.send(chunk);
});

const args = options.args || [];
const fds = [
new OpenFile(new File([])), // stdin
ConsoleStdout.lineBuffered((stdout) => {
console.log(stdout);
options.onStdout?.call(undefined, stdout);
}),
ConsoleStdout.lineBuffered((stderr) => {
console.error(stderr);
options.onStderr?.call(undefined, stderr);
}),
stdout,
stderr,
new PreopenDirectory("/", new Map()),
];

Expand Down Expand Up @@ -129,15 +166,8 @@ export const WasmRunner = (rawOptions: Options | false, SwiftRuntime: SwiftRunti
};
};

const defaultRunnerOptions = (options: Options | false): Options => {
if (!options) return defaultRunnerOptions({});
if (!options.onStdout) {
options.onStdout = () => { };
}
if (!options.onStderr) {
options.onStderr = () => { };
}
if (!options.args) {
const defaultRunnerOptions = (options: Options): Options => {
if (options.args != null) {
options.args = ["main.wasm"];
}
return options;
Expand Down
47 changes: 30 additions & 17 deletions entrypoint/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,17 +44,12 @@ const startWasiTask = async () => {

const wasmRunner = WasmRunner(
{
onStderr() {
const prevLimit = Error.stackTraceLimit;
Error.stackTraceLimit = 1000;
socket.send(
JSON.stringify({
kind: "stackTrace",
stackTrace: new Error().stack,
})
);
Error.stackTraceLimit = prevLimit;
onStdoutLine(line) {
console.log(line);
},
onStderrLine(line) {
console.error(line);
}
},
runtimeConstructor
);
Expand All @@ -65,14 +60,32 @@ const startWasiTask = async () => {
};

function handleError(e: any) {
console.error(e);
if (e instanceof WebAssembly.RuntimeError) {
console.log(e.stack);
if (e instanceof Error) {
const stack = e.stack;
if (stack != null) {
socket.send(
JSON.stringify({
kind: "stackTrace",
stackTrace: stack,
})
);
}
}
}

try {
startWasiTask().catch(handleError);
} catch (e) {
handleError(e);
async function main(): Promise<void> {
try {
window.addEventListener("error", (event) => {
handleError(event.error);
});
window.addEventListener("unhandledrejection", (event) => {
handleError(event.reason);
});
await startWasiTask();
} catch (e) {
handleError(e);
throw e;
}
}

main();
47 changes: 31 additions & 16 deletions entrypoint/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,16 +45,12 @@ const startWasiTask = async () => {
let testRunOutput = "";
const wasmRunner = WasmRunner(
{
onStdout: (text) => {
testRunOutput += text + "\n";
onStdoutLine: (line) => {
console.log(line);
testRunOutput += line + "\n";
},
onStderr: () => {
socket.send(
JSON.stringify({
kind: "stackTrace",
stackTrace: new Error().stack,
})
);
onStderrLine: (line) => {
console.error(line);
},
},
runtimeConstructor
Expand Down Expand Up @@ -109,14 +105,33 @@ const startWasiTask = async () => {

function handleError(e: any) {
console.error(e);
if (e instanceof WebAssembly.RuntimeError) {
console.log(e.stack);

if (e instanceof Error) {
const stack = e.stack;
if (stack != null) {
socket.send(
JSON.stringify({
kind: "stackTrace",
stackTrace: stack,
})
);
}
}
socket.send(JSON.stringify({ kind: "errorReport", errorReport: e.toString() }));

socket.send(
JSON.stringify({
kind: "errorReport",
errorReport: e.toString()
})
);
}

try {
startWasiTask().catch(handleError);
} catch (e) {
handleError(e);
async function main(): Promise<void> {
try {
await startWasiTask();
} catch (e) {
handleError(e);
}
}

main();
13 changes: 13 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 3cb3877

Please sign in to comment.