Skip to content

Commit 557b0bb

Browse files
committed
Start on WASM integration and immediately find we have no good way to load it
1 parent 2e00347 commit 557b0bb

File tree

4 files changed

+91
-1
lines changed

4 files changed

+91
-1
lines changed

src/APIInterface.mjs

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ export class APIInterface {
1212

1313
// Returns files used to determine what options are available in the track picker.
1414
// Returns object with keys: files, bedFiles.
15+
// files holds an array of objects like { name: string; type: filetype;}, where filetype is a file type like "graph".
16+
// bedFiles just holds an array of strings.
1517
// cancelSignal is an AbortSignal that can be used to cancel the request.
1618
async getFilenames(cancelSignal) {
1719
throw new Error("getFilenames function not implemented");

src/GBZBaseAPI.mjs

+52-1
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,32 @@
11
import { APIInterface } from "./APIInterface.mjs";
22

3+
// TODO: The Webpack way to get the WASM would be something like:
4+
//import QueryWasm from "gbz-base/target/wasm32-wasi/release/query.wasm";
5+
// if the export mapping is broken, or
6+
//import QueryWasm from "gbz-base/query.wasm";
7+
// if it is working. In Jest, not only is the export mapping not working, but
8+
// also it can't get us a fetch-able string from the import like Webpack does.
9+
// So we will need some fancy Jest config to mock the WASM file into a js
10+
// module that does *something*, and also to mock fetch() into something that
11+
// can fetch it. Or else we need to hide that all behind something that can
12+
// fetch the WASM on either Webpack or Jest with its own strategies/by being
13+
// swapped out.
14+
315
/**
416
* API implementation that uses tools compiled to WebAssembly, client-side.
517
*/
618
export class GBZBaseAPI extends APIInterface {
719
constructor() {
820
super();
21+
22+
// We can take user uploads, in which case we need to hold on to them somewhere.
23+
// This holds all the file objects.
24+
this.files = [];
25+
26+
// We need to index all their names by type.
27+
this.filesByType = {};
28+
29+
// We need to set up our WASM
930
}
1031

1132
async getChunkedData(viewTarget, cancelSignal) {
@@ -18,16 +39,46 @@ export class GBZBaseAPI extends APIInterface {
1839
}
1940

2041
async getFilenames(cancelSignal) {
21-
return {
42+
// Set up an empty response.
43+
let response = {
2244
files: [],
2345
bedFiles: []
2446
};
47+
48+
for (let type of this.filesByType) {
49+
if (type == "bed") {
50+
// Just send all these files in bedFiles.
51+
response.bedFiles = this.filesByType[type];
52+
} else {
53+
for (let fileName of this.filesByType[type]) {
54+
// We sens a name/type record for each non-BED file
55+
response.files.push({name: fileName, type: type});
56+
}
57+
}
58+
}
59+
60+
return response;
2561
}
2662

2763
subscribeToFilenameChanges(handler, cancelSignal) {
2864
return {};
2965
}
3066

67+
async putFile(fileType, file, cancelSignal) {
68+
// We track files just by array index.
69+
let fileName = this.files.length.toString();
70+
// Just hang on to the File object.
71+
this.files.push(file);
72+
73+
if (this.filesByType[fileType] === undefined) {
74+
this.filesByType[fileType] = [];
75+
}
76+
// Index the name we produced by type.
77+
this.filesByType[fileType].push(fileName);
78+
79+
return fileName;
80+
}
81+
3182
async getBedRegions(bedFile, cancelSignal) {
3283
return {
3384
bedRegions: []

src/GBZBaseAPI.test.js

+33
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { GBZBaseAPI } from './GBZBaseAPI.mjs';
2+
3+
import fs from "fs-extra";
4+
5+
it("can be constructed", () => {
6+
let api = new GBZBaseAPI();
7+
});
8+
9+
it("can have a file uploaded", async () => {
10+
let api = new GBZBaseAPI();
11+
12+
// We need to make sure we make a jsdom File (which is a jsdom Blob), and not
13+
// a Node Blob, for our test file. Otherwise it doesn't work with jsdom's
14+
// upload machinery.
15+
// See for example <https://github.com/vitest-dev/vitest/issues/2078> for
16+
// background on the many flavors of Blob.
17+
const fileData = await fs.readFileSync("exampleData/cactus.vg");
18+
// Since a Node Buffer is an ArrayBuffer, we can use it to make a jsdom File.
19+
// We need to put the data block in an enclosing array, or else the block
20+
// will be iterated and each byte will be stringified and *those* bytes will
21+
// be uploaded.
22+
const file = new window.File([fileData], "cactus.vg", {
23+
type: "application/octet-stream",
24+
});
25+
26+
// Set up for canceling the upload
27+
let controller = new AbortController();
28+
29+
let uploadName = await api.putFile("graph", file, controller.signal);
30+
31+
expect(uploadName).toBeTruthy();
32+
33+
});

src/components/HeaderForm.js

+4
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,10 @@ class HeaderForm extends Component {
654654

655655
try {
656656
let fileName = await this.api.putFile(fileType, file, this.cancelSignal);
657+
if (fileType == "graph") {
658+
// Refresh the graphs right away
659+
this.getMountedFilenames();
660+
}
657661
this.setUploadInProgress(false);
658662
return fileName;
659663
} catch (e) {

0 commit comments

Comments
 (0)