Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add local backend mode #403

Merged
merged 24 commits into from
Mar 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
76161bc
Make sure we can see the files we uploaded
adamnovak Feb 7, 2024
e19db44
Get it to actually read the database
adamnovak Feb 7, 2024
af60d03
Send out standard output as text
adamnovak Feb 7, 2024
7645c93
Convert JSON to vg format
adamnovak Feb 7, 2024
21bfb52
Manage to render from a local WASM run
adamnovak Feb 7, 2024
a1f23dc
Make the local mode checkbox sort of work and document why it isn't b…
adamnovak Feb 7, 2024
360337e
Try to set up a real worker and a fake polyfill for Jest, but Jest wo…
adamnovak Feb 8, 2024
a086c56
Get the mock worker to actually load under Jest
adamnovak Feb 8, 2024
60167f4
Reorganize API code to contain the proliferating worker glue files
adamnovak Feb 8, 2024
676d5cc
Fix import in server API and fix tests
adamnovak Feb 8, 2024
d26a2c8
Get build to pass by un-defaulting exports and adding extension
adamnovak Feb 8, 2024
2896dfe
Get API working over RPC to/from the fake Jest worker
adamnovak Feb 8, 2024
139f042
Get local API implementation working inside the worker
adamnovak Feb 8, 2024
e31ad31
Merge branch 'lancet-demo' into HEAD
adamnovak Feb 14, 2024
0918b63
Merge branch 'lancet-demo' into wasm-worker
adamnovak Feb 14, 2024
c608583
Merge remote-tracking branch 'origin/master' into wasm-worker
adamnovak Mar 11, 2024
b563e94
Implement sync file read with read-into-memory fallback
adamnovak Mar 11, 2024
9a7d5ff
Fix typo and convince the linter to let us use the cool worker stuff
adamnovak Mar 11, 2024
41d97d9
Turn off file upload limit for local backend
adamnovak Mar 11, 2024
f11a0c9
Upgrade gbz-base
adamnovak Mar 12, 2024
0500fe1
Formalize system of using 'none' in bedFile to fix left and right but…
adamnovak Mar 13, 2024
7f7fec3
Put API mode switch in a defensible place on the page
adamnovak Mar 13, 2024
eda237d
Upgrade comparison operators
adamnovak Mar 13, 2024
f796739
Fix negation to re-enable local limit for server API uploads
adamnovak Mar 13, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added exampleData/x.gbz.db
Binary file not shown.
44 changes: 36 additions & 8 deletions package-lock.json

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

5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"es-dirname": "^0.1.0",
"express": "^4.18.2",
"fs-extra": "^10.1.0",
"gbz-base": "^0.1.0-alpha.0",
"gbz-base": "^0.1.0-alpha.1",
"gh-pages": "^4.0.0",
"markdown-to-jsx": "^7.2.0",
"multer": "^1.4.5-lts.1",
Expand All @@ -56,7 +56,8 @@
"uuid": "^9.0.0",
"webpack": "^5.82.0",
"webpack-dev-server": "4.11.1",
"websocket": "^1.0.34"
"websocket": "^1.0.34",
"worker-rpc": "^0.2.0"
},
"scripts": {
"start": "concurrently -n frontend,backend -c red,green 'HOST=${HOST:=127.0.0.1} PORT=${PORT:=3001} react-scripts start' 'npm:serve'",
Expand Down
83 changes: 66 additions & 17 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import Footer from "./components/Footer";
import { dataOriginTypes } from "./enums";
import "./config-client.js";
import { config } from "./config-global.mjs";
import ServerAPI from "./ServerAPI.mjs";
import { GBZBaseAPI } from "./GBZBaseAPI.mjs";
import ServerAPI from "./api/ServerAPI.mjs";
import { LocalAPI } from "./api/LocalAPI.mjs";

const EXAMPLE_TRACKS = [
// Fake tracks for the generated examples.
Expand Down Expand Up @@ -47,19 +47,6 @@ class App extends Component {
constructor(props) {
super(props);

// See if the WASM API is available.
// Right now this just tests and logs, but eventually we will be able to use it.
let gbzApi = new GBZBaseAPI();
gbzApi.available().then((working) => {
if (working) {
console.log("WASM API implementation available!");
} else {
console.error("WASM API implementation not available!");
}
});

this.APIInterface = new ServerAPI(props.apiUrl);

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

// Set defaultViewTarget to either URL params (if present) or the first example
Expand All @@ -83,8 +70,68 @@ class App extends Component {
colorSchemes: getColorSchemesFromTracks(this.defaultViewTarget.tracks),
mappingQualityCutoff: 0,
},
APIInterface: new ServerAPI(props.apiUrl)
};
}

/**
* Set which API implementation to query for graph data.
*
* Mode can be "local" or "server".
*/
setAPIMode(mode) {
this.setState((state) => {
if (mode !== this.getAPIMode(state)) {
if (mode === "local") {
// Make a local API
return {
APIInterface: new LocalAPI(),
// Set up an empty view target that can't really render.
// TODO: Let us control HeaderForm's dataType state so we can pop it right over to custom, or feed it a different defaultViewTarget
dataOrigin: dataOriginTypes.API,
viewTarget: {
tracks: []
},
visOptions: {
...state.visOptions,
colorSchemes: [],
},
};
} else if (mode === "server") {
// Make a server API
return {
APIInterface: new ServerAPI(this.props.apiUrl),
// Also reset to a current view target this can show
dataOrigin: dataOriginTypes.API,
viewTarget: this.defaultViewTarget,
visOptions: {
...state.visOptions,
colorSchemes: getColorSchemesFromTracks(this.defaultViewTarget.tracks),
},
};
} else {
throw new Error("Unimplemented API mode: " + mode)
}
}
});
}

/**
* Get the string describing the current API mode ("local" or "server"),
* given the state (by default the current state).
*/
getAPIMode(state) {
if (state === undefined) {
state = this.state;
}
if (state.APIInterface instanceof LocalAPI) {
return "local";
} else if (state.APIInterface instanceof ServerAPI) {
return "server";
} else {
throw new Error("Unnamed API implementation: " + state.APIInterface);
}
}

/*
* Drop undefined values
Expand Down Expand Up @@ -197,13 +244,13 @@ class App extends Component {
dataOrigin={this.state.dataOrigin}
defaultViewTarget={this.defaultViewTarget}
getCurrentViewTarget={this.getCurrentViewTarget}
APIInterface={this.APIInterface}
APIInterface={this.state.APIInterface}
/>
<TubeMapContainer
viewTarget={this.state.viewTarget}
dataOrigin={this.state.dataOrigin}
visOptions={this.state.visOptions}
APIInterface={this.APIInterface}
APIInterface={this.state.APIInterface}
/>
<CustomizationAccordion
visOptions={this.state.visOptions}
Expand All @@ -217,6 +264,8 @@ class App extends Component {
this.handleMappingQualityCutoffChange
}
setColorSetting={this.setColorSetting}
currentAPIMode={this.getAPIMode()}
setAPIMode={this.setAPIMode.bind(this)}
/>
<Footer />
</div>
Expand Down
4 changes: 2 additions & 2 deletions src/App.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { fetchAndParse } from "./fetchAndParse";
// We want to be able to replace the `fetchAndParse` that *other* files see,
// and we want to use *different* implementations for different tests in this
// file. We can mock it with Jest, but Jest will move this call before the
// imports when runnin the tests, so we can't access any file-level variables
// imports when running the tests, so we can't access any file-level variables
// in it. So we need to do some sneaky global trickery.

// Register the given replacement function to be called instead of fetchAndParse.
Expand All @@ -25,7 +25,7 @@ function clearFetchAndParseMock() {
}

jest.mock("./fetchAndParse", () => {
// This dispatcher will replace fetchAndParse when we or anyone eles imports it.
// This dispatcher will replace fetchAndParse when we or anyone else imports it.
function fetchAndParseDispatcher() {
// Ge tthe real fetchAndParse
const { fetchAndParse } = jest.requireActual("./fetchAndParse");
Expand Down
Loading
Loading