Backend Modules
The WebPlatform backend is a Node.js/TypeScript application built on uWebSockets.js. This page describes each module's responsibilities and public interface.
For the WebSocket protocol these modules expose, see the WebSocket API Reference.
Module overview
Controller
File: src/api/core/Controller.ts
The central coordinator. Holds references to all other modules and provides a unified API that MonitorServer calls in response to frontend commands.
Responsibilities:
- Initializes and manages the lifecycle of all other modules.
- Coordinates cross-module workflows (e.g., on experiment launch: waits for GAMA confirmation, then adds all waiting players).
- Arms a 3-hour session timer; initiates clean shutdown if UPS is on battery when it fires.
Public methods:
| Method | Description |
|---|---|
restart() | Closes and recreates PlayerManager, GamaConnector, MonitorServer, ModelManager. |
getSimulationInformations() | Returns the nested catalog JSON from ModelManager. |
notifyMonitor() | Broadcasts current GAMA + player state to all monitor clients. |
broadcastSimulationOutput(json) | Forwards GAMA simulation output to the targeted player headsets. |
addInGamePlayer(id) | Asks GamaConnector to add a player to the running simulation. |
purgePlayer(id) | Removes a player from GAMA, PlayerManager, and notifies the monitor. |
launchExperiment() | Sends load command to GAMA; polls until running; adds all waiting players. |
stopExperiment() | Stops the GAMA experiment and removes all players. |
pauseExperiment(callback?) | Pauses the GAMA experiment. |
resumeExperiment() | Resumes a paused GAMA experiment. |
sendExpression(id, expr) | Sends a GAML expression to GAMA on behalf of a player. |
sendAsk(json) | Sends a GAML ask statement to GAMA. |
MonitorServer
File: src/api/monitoring/MonitorServer.ts
WebSocket server (uWebSockets.js) on MONITOR_WS_PORT (default 8001). The admin UI connects here.
Responsibilities:
- Broadcasts
json_stateto all connected clients on any state change. - Parses incoming commands and delegates to Controller.
- Sends targeted responses (catalog list, simulation settings) to the requesting client only.
Handled incoming message types: launch_experiment, stop_experiment, pause_experiment, resume_experiment, add_player_headset, remove_player_headset, get_simulation_informations, get_simulation_by_index, send_simulation, screen_control, try_connection.
Idle timeout: 30 seconds (uWS default).
PlayerManager
File: src/api/multiplayer/PlayerManager.ts
WebSocket server (uWebSockets.js) on HEADSET_WS_PORT (default 8080). VR headsets (Unity apps) connect here.
Data structure:
playerList: Map<string, Player>
// key = headset IP address (string)
interface Player {
id: string; // player name (from "connection" message)
ws: uWS.WebSocket<unknown>; // live WebSocket handle
ping_interval: number; // heartbeat interval in ms
is_alive: boolean; // cleared on ping, set on pong
timeout?: NodeJS.Timeout; // heartbeat timer handle
connected: boolean;
in_game: boolean;
date_connection: string; // "HH:MM" format
}
Responsibilities:
- Accepts and tracks headset WebSocket connections keyed by IP address.
- Routes
expressionandaskmessages to GamaConnector. - Sends heartbeat pings; terminates dead sockets.
- Routes targeted simulation output (
json_output) to individual headsets. - Automatically adds a connecting headset to the GAMA simulation if one is running.
Reconnection: If a headset with a known IP reconnects (e.g. after a brief WiFi drop), the existing player entry is updated in-place without re-registering with GAMA.
Aggressive disconnect: When AGGRESSIVE_DISCONNECT=true, the player entry is deleted from playerList on disconnect instead of being kept with connected: false.
GamaConnector
File: src/api/simulation/GamaConnector.ts
WebSocket client that connects to the GAMA server at ws://<GAMA_IP_ADDRESS>:<GAMA_WS_PORT>.
State tracked:
interface GamaState {
connected: boolean;
experiment_state: string; // NONE | NOTREADY | RUNNING | PAUSED
loading: boolean;
content_error: string;
experiment_id: string;
experiment_name: string;
}
Responsibilities:
- Formats and sends GAMA protocol messages (
load,play,pause,stop,expression). - Parses incoming messages (
SimulationStatus,SimulationOutput,CommandExecutedSuccessfully, error types). - On
SimulationOutput: parsesmessage.contentand callscontroller.broadcastSimulationOutput(). - On error types (see
GAMA_ERROR_MESSAGESconstant): logs error and setscontent_errorin state. - Reconnects automatically 5 seconds after any abnormal closure or connection error.
Message queue: Messages are queued in listMessages[] and flushed on the next sendMessages() call. A callback may be passed to run after all messages are sent.
ModelManager
File: src/api/simulation/ModelManager.ts
Scans learning package directories and builds the catalog of available Virtual Universes.
Responsibilities:
- Scans
LEARNING_PACKAGE_PATHandEXTRA_LEARNING_PACKAGE_PATHfor directories containingsettings.json. - Parses each
settings.jsonas eitherjson_settings(a single model) orcatalog(a nested folder of models). - Resolves relative
model_file_pathvalues to absolute paths. - Maintains a flat
models: Model[]list (indexed bymodel_index) and a nestedmonitorNestedModelsstructure for the frontend.
Settings format: see Virtual Universe settings reference.
Error handling in packaged mode: If no learning packages are found, the process exits with code 1.
Model
File: src/api/simulation/Model.ts
Immutable representation of one Virtual Universe.
| Getter | Returns |
|---|---|
getModelFilePath() | Absolute path to the .gaml file |
getExperimentName() | GAMA experiment name to launch |
getJsonSettings() | The full VU_MODEL_SETTING_JSON object |
AdbManager
File: src/api/android/adb/AdbManager.ts
Manages ADB connections to Meta Quest headsets.
Prerequisites: adb must be installed and in PATH; adb devices must succeed.
Responsibilities:
- Connects to the local ADB server at
127.0.0.1:5037via@yume-chan/adb. - Discovers headsets via
DeviceFinder(explicit IPs fromHEADSETS_IPor network scan viaevilscan). - Sets device-level ADB settings (WiFi watchdog, sleep timeouts, OTA disable) via
HeadsetSetup. - Launches screen mirroring (
ScrcpyServer) per device. - Shuts down all headsets during the session timer cleanup sequence.
UpsManager
File: src/api/infra/ups/UpsManager.ts
Monitors an APC UPS via USB HID (node-hid).
Responsibilities:
- Connects to the first recognized APC UPS device.
- Tracks battery/AC status.
isOnAC(): returnstrueif running on mains power.armShutdown(seconds): schedules UPS output cut after the given delay (used in the session timer shutdown sequence).
StaticServer
File: src/api/infra/StaticServer.ts
Express HTTP server that serves the compiled React frontend from dist/. Only started when NODE_ENV=production or when running as a packaged executable.
Constants
File: src/api/core/Constants.ts
GAMA_ERROR_MESSAGES
const GAMA_ERROR_MESSAGES = [
"SimulationStatusError",
"SimulationErrorDialog",
"SimulationError",
"RuntimeError",
"GamaServerError",
"MalformedRequest",
"UnableToExecuteRequest"
];
GamaConnector treats any incoming message whose type matches an entry in this array as an error.
HEADSET_COLOR
Maps the last octet(s) of a headset's IP address to a CSS color name. Used to assign a colored border to the headset's screen mirror in the admin UI, and to select the matching headset_<color>.png icon. The 101 → blue, 102 → green, etc. mapping is used by M2L2 deployments with fixed IP assignments.