From 43693ccccbc8923249dd842dcbb503d29a4ee91a Mon Sep 17 00:00:00 2001 From: Joe Heffernan Date: Mon, 17 Mar 2025 15:58:06 -0700 Subject: [PATCH 01/29] remove loadInitialData/postConnect flow and controller params --- README.md | 26 +++++----- examples/src/Viewer.tsx | 3 +- src/controller/index.ts | 75 ++------------------------- src/test/AgentSimController.test.ts | 28 ---------- src/test/SimulariumController.test.ts | 24 ++------- src/viewport/index.tsx | 9 ---- 6 files changed, 20 insertions(+), 145 deletions(-) delete mode 100644 src/test/AgentSimController.test.ts diff --git a/README.md b/README.md index 201a7462..a490a03c 100644 --- a/README.md +++ b/README.md @@ -45,10 +45,9 @@ const netConnectionSettings = { serverPort: 9002, }; -const simulariumController = new SimulariumController({ - trajectoryPlaybackFile: "ATPsynthase_9.h5", - netConnectionSettings: netConnectionSettings, -}); +const simulariumController = new SimulariumController(); +// todo show correct call of changeFile to load trajectory + class Viewer extends React.Component { public constructor(props) { @@ -89,7 +88,6 @@ class Viewer extends React.Component { onJsonDataArrived={this.handleJsonMeshData} onTrajectoryFileInfoChanged={this.handleTrajectoryInfo} highlightedParticleType={this.state.highlightId} - loadInitialData={true} hideAllAgents={this.state.hideAllAgents} showPaths={this.state.showPaths} />) @@ -108,15 +106,15 @@ This will run the example in `/examples/src/`, demonstrating the viewer's functi ## Quick Start -| script | comments | -| ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| build | create ES module build | -| clean | remove generated artifacts | -| generateTypes | generate type declarations | -| lint | run eslint on `src` directory | -| transpileES | run babel on `src` directory; _do not_ transpile `import/export` statements for an ES module compatible build (used by bundlers for tree-shaking) | -| test | run `vitest`; searches for any files matching the pattern "src/\*_/_.test.js" | -| typeCheck | run `tsc` in type-check only mode | +| script | comments | +| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| build | create ES module build | +| clean | remove generated artifacts | +| generateTypes | generate type declarations | +| lint | run eslint on `src` directory | +| transpileES | run babel on `src` directory; _do not_ transpile `import/export` statements for an ES module compatible build (used by bundlers for tree-shaking) | +| test | run `vitest`; searches for any files matching the pattern "src/\*_/_.test.js" | +| typeCheck | run `tsc` in type-check only mode | | start | runs an example app from `examples` for testing. Runs at `localhost:8080`. Use `--localserver` to run backend locally. With no flags, this script will default to using the staging octopus server as backend | --- diff --git a/examples/src/Viewer.tsx b/examples/src/Viewer.tsx index a734c5fd..8595c5f7 100644 --- a/examples/src/Viewer.tsx +++ b/examples/src/Viewer.tsx @@ -91,7 +91,7 @@ interface ViewerState { conversionFileName: string; } -const simulariumController = new SimulariumController({}); +const simulariumController = new SimulariumController(); let currentFrame = 0; let currentTime = 0; @@ -1100,7 +1100,6 @@ class Viewer extends React.Component { onFollowObjectChanged={this.handleFollowObjectData.bind( this )} - loadInitialData={true} agentColors={this.state.agentColors} showPaths={this.state.showPaths} onError={this.onError} diff --git a/src/controller/index.ts b/src/controller/index.ts index b6ebd3f7..ed8ffd19 100644 --- a/src/controller/index.ts +++ b/src/controller/index.ts @@ -27,14 +27,6 @@ import { OctopusServicesClient } from "../simularium/OctopusClient.js"; jsLogger.setHandler(jsLogger.createDefaultHandler()); -// TODO: refine this as part of the public API for initializing the -// controller (also see SimulatorConnectionParams below) -interface SimulariumControllerParams { - remoteSimulator?: RemoteSimulator; - netConnectionSettings?: NetConnectionParams; - trajectoryPlaybackFile?: string; -} - // TODO: refine this as part of the public API for initializing the // controller with a simulator connection interface SimulatorConnectionParams { @@ -54,7 +46,6 @@ export default class SimulariumController { public visGeometry: VisGeometry | undefined; public tickIntervalLength: number; public handleTrajectoryInfo: (TrajectoryFileInfo) => void; - public postConnect: () => void; public startRecording: () => void; public stopRecording: () => void; public onError?: (error: FrontEndError) => void; @@ -63,53 +54,19 @@ export default class SimulariumController { private isFileChanging: boolean; private playBackFile: string; - public constructor(params: SimulariumControllerParams) { + public constructor() { this.visData = new VisData(); this.tickIntervalLength = 0; // Will be overwritten when a trajectory is loaded - this.postConnect = () => noop; this.startRecording = () => noop; this.stopRecording = () => noop; this.handleTrajectoryInfo = (/*msg: TrajectoryFileInfo*/) => noop; this.onError = (/*errorMessage*/) => noop; - // might only be used in unit testing - // TODO: change test so controller isn't initialized with a remoteSimulator - if (params.remoteSimulator) { - this.simulator = params.remoteSimulator; - this.simulator.setTrajectoryFileInfoHandler( - (trajFileInfo: TrajectoryFileInfo) => { - this.handleTrajectoryInfo(trajFileInfo); - } - ); - this.simulator.setTrajectoryDataHandler( - this.visData.parseAgentsFromNetData.bind(this.visData) - ); - // TODO: probably remove this? We're never initalizing the controller - // with any settings on the website. - } else if (params.netConnectionSettings) { - this.createSimulatorConnection( - params.netConnectionSettings, - undefined, - undefined - ); - } else { - // No network information was passed in - // the viewer will be initialized blank - - this.simulator = undefined; - - // @TODO: Pass this warning upwards (to installing app) - if (params.trajectoryPlaybackFile) { - console.warn( - "trajectoryPlaybackFile param ignored, no network config provided" - ); - } - } - this.isPaused = false; this.isFileChanging = false; - this.playBackFile = params.trajectoryPlaybackFile || ""; + this.playBackFile = ""; + this.simulator = undefined; this.zoomIn = this.zoomIn.bind(this); this.zoomOut = this.zoomOut.bind(this); this.resetCamera = this.resetCamera.bind(this); @@ -196,26 +153,6 @@ export default class SimulariumController { return this.isFileChanging; } - // Not called by viewer, but could be called by - // parent app - // todo candidate for removal? not called in website - public connect(): Promise { - if (!this.remoteWebsocketClient) { - return Promise.reject( - new Error( - "No network connection established in simularium controller." - ) - ); - } - - return this.remoteWebsocketClient - .connectToRemoteServer() - .then((msg: string) => { - this.postConnect(); - return msg; - }); - } - public start(): Promise { if (!this.simulator) { return Promise.reject(); @@ -282,12 +219,6 @@ export default class SimulariumController { return this.isPaused; } - public initializeTrajectoryFile(): void { - if (this.simulator) { - this.simulator.initialize(this.playBackFile); - } - } - public startSmoldynSim( netConnectionConfig: NetConnectionParams, fileName: string, diff --git a/src/test/AgentSimController.test.ts b/src/test/AgentSimController.test.ts deleted file mode 100644 index 15086563..00000000 --- a/src/test/AgentSimController.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { SimulariumController } from "../controller/index.js"; -import { DummyRemoteSimulator } from "./DummyRemoteSimulator.js"; - -describe("SimulariumController module", () => { - describe("SimulariumController Time", () => { - test("Go to time in cache", () => - new Promise((done) => { - const netConn = new DummyRemoteSimulator({}); - netConn.timeStep = 1; - netConn.totalDuration = 100; - netConn.commandLatencyMS = 0; - netConn.connectLatencyMS = 0; - - const controller = new SimulariumController({ - remoteSimulator: netConn, - }); - - controller.start(); - controller.gotoTime(2); - - // allow time for data streaming to occur - setTimeout(() => { - expect(controller.time()).toEqual(2); - done(); - }, 500); - })); - }); -}); diff --git a/src/test/SimulariumController.test.ts b/src/test/SimulariumController.test.ts index 38038074..4e10f131 100644 --- a/src/test/SimulariumController.test.ts +++ b/src/test/SimulariumController.test.ts @@ -1,26 +1,10 @@ -import { SimulariumController } from "../controller/index.js"; -import { DummyRemoteSimulator } from "./DummyRemoteSimulator.js"; - describe("SimulariumController module", () => { describe("SimulariumController Time", () => { test("Go to time in cache", () => - new Promise((done) => { - const netConn = new DummyRemoteSimulator({}); - netConn.timeStep = 1; - netConn.totalDuration = 100; - netConn.commandLatencyMS = 0; - netConn.connectLatencyMS = 0; - - const controller = new SimulariumController({ - remoteSimulator: netConn, - }); - - controller.start(); - controller.gotoTime(2); - setTimeout(() => { - expect(controller.time()).toEqual(2); - done(); - }, 500); + new Promise(() => { + // todo new approach to testing dummy simulator comming in + // changes to simulator params + return Promise.resolve(); })); }); }); diff --git a/src/viewport/index.tsx b/src/viewport/index.tsx index a3725352..a2ae05cd 100644 --- a/src/viewport/index.tsx +++ b/src/viewport/index.tsx @@ -36,7 +36,6 @@ type ViewportProps = { cachedData: TrajectoryFileInfo ) => void | undefined; onUIDisplayDataChanged: (data: UIDisplayData) => void | undefined; - loadInitialData: boolean; hideAllAgents: boolean; showPaths: boolean; showBounds: boolean; @@ -55,7 +54,6 @@ const defaultProps = { backgroundColor: [0, 0, 0], height: 800, width: 800, - loadInitialData: true, hideAllAgents: false, showPaths: true, showBounds: true, @@ -243,7 +241,6 @@ class Viewport extends React.Component< const { backgroundColor, simulariumController, - loadInitialData, onError, lockedCamera, } = this.props; @@ -268,12 +265,6 @@ class Viewport extends React.Component< ) => { this.onTrajectoryFileInfo(msg); }; - - simulariumController.postConnect = () => { - if (loadInitialData) { - simulariumController.initializeTrajectoryFile(); - } - }; simulariumController.startRecording = this.startRecording.bind(this); simulariumController.stopRecording = this.stopRecording.bind(this); From 19fc1b7a485d2202f565dfc3cf8c80e09573f058 Mon Sep 17 00:00:00 2001 From: Joe Heffernan Date: Mon, 17 Mar 2025 16:15:15 -0700 Subject: [PATCH 02/29] fix placeholder test --- src/test/SimulariumController.test.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/test/SimulariumController.test.ts b/src/test/SimulariumController.test.ts index 4e10f131..626c228e 100644 --- a/src/test/SimulariumController.test.ts +++ b/src/test/SimulariumController.test.ts @@ -1,10 +1,12 @@ +import SimulariumController from "../controller"; + describe("SimulariumController module", () => { describe("SimulariumController Time", () => { - test("Go to time in cache", () => - new Promise(() => { - // todo new approach to testing dummy simulator comming in - // changes to simulator params - return Promise.resolve(); - })); + test("Go to time in cache", () => { + // todo new approach to testing dummy simulator comming in + // changes to simulator params + const controller = new SimulariumController(); + expect(controller).toBeDefined(); + }); }); }); From aa0dceeaca44fbf53968fbb55045b2b0010f7da8 Mon Sep 17 00:00:00 2001 From: Joe Heffernan Date: Fri, 21 Mar 2025 11:26:45 -0700 Subject: [PATCH 03/29] move plots and metrics API into ISimulator --- src/controller/index.ts | 51 ++++++++-------------------- src/simularium/ClientSimulator.ts | 14 +++++++- src/simularium/ISimulator.ts | 19 ++++++++++- src/simularium/LocalFileSimulator.ts | 50 ++++++++++++++++++++++++++- src/simularium/RemoteSimulator.ts | 44 +++++++++++++++++++++++- 5 files changed, 138 insertions(+), 40 deletions(-) diff --git a/src/controller/index.ts b/src/controller/index.ts index ed8ffd19..af3bed95 100644 --- a/src/controller/index.ts +++ b/src/controller/index.ts @@ -41,7 +41,6 @@ export default class SimulariumController { public simulator?: ISimulator; public remoteWebsocketClient?: WebsocketClient; public octopusClient?: OctopusServicesClient; - public metricsCalculator?: RemoteMetricsCalculator; public visData: VisData; public visGeometry: VisGeometry | undefined; public tickIntervalLength: number; @@ -392,59 +391,39 @@ export default class SimulariumController { } } - private setupMetricsCalculator( + private async setupMetricsCalculator( config: NetConnectionParams - ): RemoteMetricsCalculator { + ): Promise { const webSocketClient = this.remoteWebsocketClient && this.remoteWebsocketClient.socketIsValid() ? this.remoteWebsocketClient : new WebsocketClient(config, this.onError); - return new RemoteMetricsCalculator(webSocketClient, this.onError); + const metricsCalculator = new RemoteMetricsCalculator( + webSocketClient, + this.onError + ); + await metricsCalculator.connectToRemoteServer(); + return metricsCalculator; } public async getMetrics(config: NetConnectionParams): Promise { - if ( - !this.metricsCalculator || - !this.metricsCalculator.socketIsValid() - ) { - this.metricsCalculator = this.setupMetricsCalculator(config); - await this.metricsCalculator.connectToRemoteServer(); + if (this.simulator instanceof LocalFileSimulator) { + const calculator = await this.setupMetricsCalculator(config); + await this.simulator.setupMetricsCalculator(calculator); } - this.metricsCalculator.getAvailableMetrics(); + + this.simulator?.requestAvailableMetrics(); } public async getPlotData( config: NetConnectionParams, requestedPlots: PlotConfig[] ): Promise { - if (!this.simulator) { - return; - } - - if ( - !this.metricsCalculator || - !this.metricsCalculator.socketIsValid() - ) { - this.metricsCalculator = this.setupMetricsCalculator(config); - await this.metricsCalculator.connectToRemoteServer(); - } - if (this.simulator instanceof LocalFileSimulator) { - const simulariumFile: ISimulariumFile = - this.simulator.getSimulariumFile(); - this.metricsCalculator.getPlotData( - simulariumFile["simulariumFile"], - requestedPlots - ); - } else if (this.simulator instanceof RemoteSimulator) { - // we don't have the simularium file, so we'll just send an empty data object - this.metricsCalculator.getPlotData( - {}, - requestedPlots, - this.simulator.getLastRequestedFile() - ); + await this.setupMetricsCalculator(config); } + this.simulator?.requestPlotData({}, requestedPlots); } public clearLocalCache(): void { diff --git a/src/simularium/ClientSimulator.ts b/src/simularium/ClientSimulator.ts index b2a14810..75fd23c1 100644 --- a/src/simularium/ClientSimulator.ts +++ b/src/simularium/ClientSimulator.ts @@ -1,7 +1,7 @@ import jsLogger from "js-logger"; import { ILogger } from "js-logger"; -import { VisDataMessage, TrajectoryFileInfo } from "./types.js"; +import { VisDataMessage, TrajectoryFileInfo, PlotConfig } from "./types.js"; import { ClientMessageEnum, ClientPlayBackType, @@ -211,4 +211,16 @@ export class ClientSimulator implements ISimulator { "Initialize trajectory file info" ); } + + public requestAvailableMetrics(): void { + /*not implemented*/ + // todo add plot or metric msg type to client message enum? + } + + public requestPlotData( + _data: Record, + _plots: Array + ): void { + /*not implemented*/ + } } diff --git a/src/simularium/ISimulator.ts b/src/simularium/ISimulator.ts index b6c2e179..e5d8a17f 100644 --- a/src/simularium/ISimulator.ts +++ b/src/simularium/ISimulator.ts @@ -1,4 +1,4 @@ -import { VisDataMessage, TrajectoryFileInfo } from "./types.js"; +import { VisDataMessage, TrajectoryFileInfo, PlotConfig } from "./types.js"; /** From the caller's perspective, this interface is a contract for a @@ -22,6 +22,16 @@ export interface ISimulator { handler: (msg: VisDataMessage | ArrayBuffer) => void ): void; + /** todo implement callback pattern for plots and metrics */ + /** a callback to receive available metrics */ + // setAvailableMetricsHandler( + // handler: (msg: NetMessage) => void + // ): void; + // /** a callback to receive plot data */ + // setPlotDataHandler( + // handler: (msg: NetMessage) => void + // ): void; + /** a callback to propagate errors from a simulator to it's implementing context */ setErrorHandler(handler: (msg: Error) => void): void; @@ -46,4 +56,11 @@ export interface ISimulator { requestFrameByTime(time: number): void; /** request trajectory metadata */ requestTrajectoryFileInfo(fileName: string): void; + /** request available metrics */ + requestAvailableMetrics(): void; + // /** request available plots */ + requestPlotData( + data: Record, + plots: Array + ): void; } diff --git a/src/simularium/LocalFileSimulator.ts b/src/simularium/LocalFileSimulator.ts index e10ecf11..81610298 100644 --- a/src/simularium/LocalFileSimulator.ts +++ b/src/simularium/LocalFileSimulator.ts @@ -1,15 +1,22 @@ import jsLogger from "js-logger"; import { ILogger } from "js-logger"; -import { VisDataFrame, VisDataMessage, TrajectoryFileInfoV2 } from "./types.js"; +import { + VisDataFrame, + VisDataMessage, + TrajectoryFileInfoV2, + PlotConfig, +} from "./types.js"; import { ISimulator } from "./ISimulator.js"; import type { ISimulariumFile } from "./ISimulariumFile.js"; +import { RemoteMetricsCalculator } from "./RemoteMetricsCalculator.js"; // a LocalFileSimulator is a ISimulator that plays back the contents of // a drag-n-drop trajectory file (a ISimulariumFile object) export class LocalFileSimulator implements ISimulator { protected fileName: string; protected simulariumFile: ISimulariumFile; + protected remoteMetricsCalculator?: RemoteMetricsCalculator; protected logger: ILogger; public onTrajectoryFileInfoArrive: (msg: TrajectoryFileInfoV2) => void; public onTrajectoryDataArrive: (msg: VisDataMessage | ArrayBuffer) => void; @@ -133,4 +140,45 @@ export class LocalFileSimulator implements ISimulator { public getSimulariumFile(): ISimulariumFile { return this.simulariumFile; } + + public async setupMetricsCalculator( + metricsCalculator: RemoteMetricsCalculator + ): Promise { + this.remoteMetricsCalculator = metricsCalculator; + } + + public requestAvailableMetrics(): void { + if ( + !this.remoteMetricsCalculator || + !this.remoteMetricsCalculator.socketIsValid() + ) { + this.handleError( + new Error("Metrics calculator is not configured.") + ); + return; + } + + this.remoteMetricsCalculator.getAvailableMetrics(); + } + + public requestPlotData( + _data: Record, + plots: Array + ): void { + if ( + !this.remoteMetricsCalculator || + !this.remoteMetricsCalculator.socketIsValid() + ) { + this.handleError( + new Error("Metrics calculator is not configured.") + ); + return; + } + + this.remoteMetricsCalculator.getPlotData( + this.simulariumFile["simulariumFile"], + plots, + this.fileName + ); + } } diff --git a/src/simularium/RemoteSimulator.ts b/src/simularium/RemoteSimulator.ts index 21d8c641..b548a750 100644 --- a/src/simularium/RemoteSimulator.ts +++ b/src/simularium/RemoteSimulator.ts @@ -8,7 +8,7 @@ import { } from "./WebsocketClient.js"; import type { NetMessage, ErrorMessage } from "./WebsocketClient.js"; import { ISimulator } from "./ISimulator.js"; -import { TrajectoryFileInfoV2, VisDataMessage } from "./types.js"; +import { PlotConfig, TrajectoryFileInfoV2, VisDataMessage } from "./types.js"; // a RemoteSimulator is a ISimulator that connects to the Octopus backend server // and plays back a trajectory specified in the NetConnectionParams @@ -182,6 +182,14 @@ export class RemoteSimulator implements ISimulator { NetMessageEnum.ID_ERROR_MSG, (msg) => this.onErrorMsg(msg as ErrorMessage) ); + this.webSocketClient.addJsonMessageHandler( + NetMessageEnum.ID_AVAILABLE_METRICS_RESPONSE, + (msg) => this.onAvailableMetricsArrive(msg) + ); + this.webSocketClient.addJsonMessageHandler( + NetMessageEnum.ID_PLOT_DATA_RESPONSE, + (msg) => this.onPlotDataArrive(msg) + ); } /** @@ -334,4 +342,38 @@ export class RemoteSimulator implements ISimulator { ); return Promise.resolve(); } + + public requestAvailableMetrics(): void { + this.webSocketClient.sendWebSocketRequest( + { + msgType: NetMessageEnum.ID_AVAILABLE_METRICS_REQUEST, + }, + "Request available metrics from the metrics service" + ); + } + + public requestPlotData( + data: Record, + plots: Array + ): void { + this.webSocketClient.sendWebSocketRequest( + { + msgType: NetMessageEnum.ID_PLOT_DATA_REQUEST, + fileName: this.lastRequestedFile, + data: data, + plots: plots, + }, + "Request plot data for a given trajectory and plot types" + ); + } + + public onAvailableMetricsArrive(msg: NetMessage): void { + // TODO: implement callback + console.log("Available metrics: ", msg["metrics"]); + } + + public onPlotDataArrive(msg: NetMessage): void { + // TODO: implement callback + console.log("Plot data: ", msg["plotData"]); + } } From 58c93244b1b2f7b7c4a63f7a76a6e8c679f210cd Mon Sep 17 00:00:00 2001 From: Joe Heffernan Date: Fri, 21 Mar 2025 11:46:35 -0700 Subject: [PATCH 04/29] remove server health checks --- .../src/Components/ConversionForm/index.tsx | 4 +--- examples/src/Viewer.tsx | 19 +--------------- src/controller/index.ts | 13 ----------- src/simularium/OctopusClient.ts | 22 ------------------- 4 files changed, 2 insertions(+), 56 deletions(-) diff --git a/examples/src/Components/ConversionForm/index.tsx b/examples/src/Components/ConversionForm/index.tsx index 6ca8f764..e500466f 100644 --- a/examples/src/Components/ConversionForm/index.tsx +++ b/examples/src/Components/ConversionForm/index.tsx @@ -6,7 +6,6 @@ interface InputFormProps { template: { [key: string]: any }; templateData: { [key: string]: any }; type: string; - submitDisabled: boolean; submitFile: (data) => void; onReturned: () => void; } @@ -58,7 +57,7 @@ class InputForm extends React.Component { } render() { - const { template, templateData, type, submitDisabled } = this.props; + const { template, templateData, type } = this.props; return (

Enter display data for your {type} trajectory

@@ -81,7 +80,6 @@ class InputForm extends React.Component { diff --git a/examples/src/Viewer.tsx b/examples/src/Viewer.tsx index 8595c5f7..81206f08 100644 --- a/examples/src/Viewer.tsx +++ b/examples/src/Viewer.tsx @@ -82,7 +82,6 @@ interface ViewerState { data: ISimulariumFile | null; } | null; clientSimulator: boolean; - serverHealthy: boolean; isRecordingEnabled: boolean; trajectoryTitle: string; initialPlay: boolean; @@ -118,7 +117,6 @@ const initialState: ViewerState = { selectedFile: "TEST_LIVEMODE_API", simulariumFile: null, clientSimulator: false, - serverHealthy: false, isRecordingEnabled: true, trajectoryTitle: "", initialPlay: true, @@ -143,7 +141,6 @@ class Viewer extends React.Component { this.loadFile = this.loadFile.bind(this); this.clearPendingFile = this.clearPendingFile.bind(this); this.convertFile = this.convertFile.bind(this); - this.onHealthCheckResponse = this.onHealthCheckResponse.bind(this); this.handleResize = this.handleResize.bind(this); this.state = initialState; @@ -317,10 +314,6 @@ class Viewer extends React.Component { return typeMap; } - public onHealthCheckResponse() { - this.setState({ serverHealthy: true }); - } - public async loadSmoldynFile() { const smoldynTemplate = await fetch( `${UI_TEMPLATE_DOWNLOAD_URL_ROOT}/${SMOLDYN_TEMPLATE}` @@ -332,13 +325,8 @@ class Viewer extends React.Component { type: TrajectoryType.SMOLDYN, template: smoldynTemplate.smoldyn_data, templateData: templateMap, - }, - serverHealthy: false, + } }); - simulariumController.checkServerHealth( - this.onHealthCheckResponse, - this.netConnectionSettings - ); } public convertFile(obj: Record, fileType: TrajectoryType) { @@ -369,10 +357,6 @@ class Viewer extends React.Component { conversionFileName: AWAITING_SMOLDYN_SIM_RUN, selectedFile: "", }); - simulariumController.checkServerHealth( - this.onHealthCheckResponse, - this.netConnectionSettings - ); const fileName = "smoldyn_sim" + uuidv4() + ".simularium"; simulariumController .startSmoldynSim( @@ -799,7 +783,6 @@ class Viewer extends React.Component { {...this.state.filePending} submitFile={(obj) => this.convertFile(obj, fileType)} onReturned={this.clearPendingFile} - submitDisabled={!this.state.serverHealthy} /> ); } diff --git a/src/controller/index.ts b/src/controller/index.ts index af3bed95..ffdbc174 100644 --- a/src/controller/index.ts +++ b/src/controller/index.ts @@ -372,19 +372,6 @@ export default class SimulariumController { return this.playBackFile; } - public checkServerHealth( - handler: () => void, - netConnectionConfig: NetConnectionParams - ): void { - if (!this.isRemoteOctopusClientConfigured()) { - this.configureNetwork(netConnectionConfig); - } - if (this.octopusClient) { - this.octopusClient.setHealthCheckHandler(handler); - this.octopusClient.checkServerHealth(); - } - } - public cancelConversion(): void { if (this.octopusClient) { this.octopusClient.cancelConversion(); diff --git a/src/simularium/OctopusClient.ts b/src/simularium/OctopusClient.ts index eece0003..fe2ae3ce 100644 --- a/src/simularium/OctopusClient.ts +++ b/src/simularium/OctopusClient.ts @@ -4,21 +4,9 @@ import { WebsocketClient, NetMessageEnum } from "./WebsocketClient.js"; export class OctopusServicesClient { private webSocketClient: WebsocketClient; private lastRequestedFile = ""; - private healthCheckHandler: () => void; constructor(webSocketClient: WebsocketClient) { this.webSocketClient = webSocketClient; - this.healthCheckHandler = () => { - /* do nothing */ - }; - } - - public setHealthCheckHandler(handler: () => void): void { - this.healthCheckHandler = handler; - this.webSocketClient.addJsonMessageHandler( - NetMessageEnum.ID_SERVER_HEALTHY_RESPONSE, - () => this.healthCheckHandler() - ); } public async connectToRemoteServer(): Promise { @@ -53,16 +41,6 @@ export class OctopusServicesClient { this.lastRequestedFile = ""; } - public async checkServerHealth(): Promise { - await this.webSocketClient.connectToRemoteServer(); - this.webSocketClient.sendWebSocketRequest( - { - msgType: NetMessageEnum.ID_CHECK_HEALTH_REQUEST, - }, - "Request server health check" - ); - } - public async sendSmoldynData( outFileName: string, smoldynInput: string From 5e409f42ef420d35a79e3622fc7b466e4a736dff Mon Sep 17 00:00:00 2001 From: Joe Heffernan Date: Fri, 21 Mar 2025 13:21:31 -0700 Subject: [PATCH 05/29] extend BaseRemoteClient for classes that need websockets and handle on conversion complete for the front end --- examples/src/Components/FileSelect.tsx | 20 +- examples/src/Viewer.tsx | 65 ++----- examples/src/constants.ts | 2 - src/controller/index.ts | 220 ++++++++++------------ src/simularium/LocalFileSimulator.ts | 14 +- src/simularium/OctopusClient.ts | 42 ++++- src/simularium/RemoteClient.ts | 98 ++++++++++ src/simularium/RemoteMetricsCalculator.ts | 18 +- src/simularium/RemoteSimulator.ts | 93 +++------ 9 files changed, 292 insertions(+), 280 deletions(-) create mode 100644 src/simularium/RemoteClient.ts diff --git a/examples/src/Components/FileSelect.tsx b/examples/src/Components/FileSelect.tsx index 0191e1bc..18333c6d 100644 --- a/examples/src/Components/FileSelect.tsx +++ b/examples/src/Components/FileSelect.tsx @@ -3,7 +3,7 @@ import { TRAJECTORY_OPTIONS } from "../constants"; interface FileSelectionProps { selectedFile: string; - conversionFileName: string; + awaitingConversion: boolean; onFileSelect: (file: string) => void; loadSmoldynFile: () => void; clearFile: () => void; @@ -13,7 +13,7 @@ interface FileSelectionProps { const FileSelection = ({ selectedFile, - conversionFileName, + awaitingConversion, onFileSelect, loadSmoldynFile, clearFile, @@ -28,19 +28,11 @@ const FileSelection = ({ } }, []); - const isAwaitingFileConversion = conversionFileName !== ""; - const selectValue = isAwaitingFileConversion - ? "Awaiting file conversion..." - : selectedFile; - const handleFileSelect = useCallback( (file: string) => { - if (conversionFileName !== "") { - return; - } onFileSelect(file); }, - [selectedFile, onFileSelect, conversionFileName] + [selectedFile, onFileSelect] ); const notInList = @@ -49,15 +41,14 @@ const FileSelection = ({ return (


+ {awaitingConversion &&
Awaiting file conversion...
}