Skip to content

Commit 4a64c49

Browse files
committed
Make WASM setup test itself and log when the app is loaded
1 parent 08c8e77 commit 4a64c49

File tree

3 files changed

+55
-15
lines changed

3 files changed

+55
-15
lines changed

src/App.js

+12
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { dataOriginTypes } from "./enums";
1515
import "./config-client.js";
1616
import { config } from "./config-global.mjs";
1717
import ServerAPI from "./ServerAPI.mjs";
18+
import { GBZBaseAPI } from "./GBZBaseAPI.mjs";
1819

1920
const EXAMPLE_TRACKS = [
2021
// Fake tracks for the generated examples.
@@ -46,6 +47,17 @@ class App extends Component {
4647
constructor(props) {
4748
super(props);
4849

50+
// See if the WASM API is available.
51+
// Right now this just tests and logs, but eventually we will be able to use it.
52+
let gbzApi = new GBZBaseAPI();
53+
gbzApi.available().then((working) => {
54+
if (working) {
55+
console.log("WASM API implementation available!");
56+
} else {
57+
console.error("WASM API implementation not available!");
58+
}
59+
});
60+
4961
this.APIInterface = new ServerAPI(props.apiUrl);
5062

5163
console.log("App component starting up with API URL: " + props.apiUrl);

src/GBZBaseAPI.mjs

+40-13
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { APIInterface } from "./APIInterface.mjs";
2-
import { readFile } from "fs-extra";
3-
import { WASI, File, OpenFile, PreopenDirectory } from "@bjorn3/browser_wasi_shim";
2+
import { WASI, File, OpenFile } from "@bjorn3/browser_wasi_shim";
43

54
// TODO: The Webpack way to get the WASM would be something like:
65
//import QueryWasm from "gbz-base/target/wasm32-wasi/release/query.wasm";
@@ -14,24 +13,32 @@ import { WASI, File, OpenFile, PreopenDirectory } from "@bjorn3/browser_wasi_shi
1413
// fetch the WASM on either Webpack or Jest with its own strategies/by being
1514
// swapped out.
1615

17-
// Resolve with the bytes of the WASM query blob, on Jest or Webpack.
16+
// Resolve with the bytes or Response of the WASM query blob, on Jest or Webpack.
1817
async function getWasmBytes() {
1918
let blobBytes = null;
2019

21-
if (!jest) {
22-
// Not running on Jest, we should be able to dynamic import a binary asset and get the bytes, and Webpack will handle it.
20+
if (!window["jest"]) {
21+
// Not running on Jest, we should be able to dynamic import a binary asset
22+
// by export name and get the bytes, and Webpack will handle it.
2323
try {
24-
blobBytes = await import("gbz-base/target/wasm32-wasi/release/query.wasm");
24+
let blobImport = await import("gbz-base/query.wasm");
25+
return fetch(blobImport.default);
2526
} catch (e) {
2627
console.error("Could not dynamically import WASM blob.", e);
2728
// Leave blobBytes unset to try a fallback method.
2829
}
2930
}
3031

3132
if (!blobBytes) {
32-
// Either we're on Jest, or the dynamic import didn't work (maybe we're on plain Node?).
33+
// Either we're on Jest, or the dynamic import didn't work (maybe we're on
34+
// plain Node?).
35+
//
3336
// Try to open the file from the filesystem.
34-
blobBytes = await readFile("node_modules/gbz-base/target/wasm32-wasi/release/query.wasm");
37+
//
38+
// Don't actually try and ship the filesystem module in the browser though:
39+
// see <https://webpack.js.org/api/module-methods/#webpackignore>
40+
let fs = await import(/* webpackIgnore: true */ "fs-extra");
41+
blobBytes = await fs.readFile("node_modules/gbz-base/target/wasm32-wasi/release/query.wasm");
3542
}
3643

3744
console.log("Got blob bytes: ", blobBytes);
@@ -60,7 +67,16 @@ export class GBZBaseAPI extends APIInterface {
6067
async setUp() {
6168
if (this.compiledWasm === undefined) {
6269
// Kick off and save exactly one request to get and load the WASM bytes.
63-
this.compiledWasm = WebAssembly.compile(await getWasmBytes());
70+
this.compiledWasm = getWasmBytes().then((result) => {
71+
if (result instanceof Response) {
72+
// If a fetch request was made, compile as it streams in
73+
return WebAssembly.compileStreaming(result);
74+
} else {
75+
// We have all the bytes, so compile right away.
76+
// TODO: Put this logic in the function?
77+
return WebAssembly.compile(result);
78+
}
79+
});
6480
}
6581

6682
// Wait for the bytes to be available.
@@ -73,10 +89,11 @@ export class GBZBaseAPI extends APIInterface {
7389
// We need at least one command line argument to be the program name.
7490
throw new Error("Not safe to invoke main() without program name");
7591
}
76-
92+
93+
// Make sure this.compiledWasm is set.
94+
// TODO: Change to an accessor method?
7795
await this.setUp();
78-
let wasm = this.compiledWasm;
79-
96+
8097
// Define the places to store program input and output
8198
let stdin = new File([]);
8299
let stdout = new File([]);
@@ -106,6 +123,16 @@ export class GBZBaseAPI extends APIInterface {
106123
console.log("Standard Error:", new TextDecoder().decode(stderr.data));
107124
}
108125
}
126+
127+
// Return true if the WASM setup is working, and false otherwise.
128+
async available() {
129+
try {
130+
await this.callWasm(["query", "--help"]);
131+
return true;
132+
} catch {
133+
return false;
134+
}
135+
}
109136

110137
/////////
111138
// Tube Map API implementation
@@ -128,7 +155,7 @@ export class GBZBaseAPI extends APIInterface {
128155
};
129156

130157
for (let type of this.filesByType) {
131-
if (type == "bed") {
158+
if (type === "bed") {
132159
// Just send all these files in bedFiles.
133160
response.bedFiles = this.filesByType[type];
134161
} else {

src/GBZBaseAPI.test.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ it("can be constructed", () => {
66
let api = new GBZBaseAPI();
77
});
88

9-
it("can run the WASM blob", async () => {
9+
it("can self-test its WASM setup", async () => {
1010
let api = new GBZBaseAPI();
11-
await api.callWasm(["query", "--help"]);
11+
let working = await api.available();
12+
expect(working).toBeTruthy();
1213
});
1314

1415
it("can have a file uploaded", async () => {

0 commit comments

Comments
 (0)