Sim-Link
Sim-Link is a web application designed to take the results of Gazebo simulations, save them, rank the best-performing simulations, and display the detailed results in a clean, easy-to-understand format.
Tech Stack
- Frontend: SvelteKit (built into a completely Static Single Page Application using Bun).
- Backend: Golang.
- Database: SQLite3.
- Containerization: Docker & Docker Compose.
Running with Docker (Recommended)
The easiest way to run Sim-Link is by using the provided docker-compose environment. This encapsulates the build steps for both the SvelteKit frontend and the Go backend.
# Build and start the container in the background
docker compose up -d --build
Note: The results/ folder and server/ folder are native volume mounts in Docker Compose. This ensures your simulation logs update live, and the sim-link.db SQLite file persists on your host machine.
You can then access the interface at: http://localhost:8080
Running Locally Manually
If you prefer to run the system directly on your OS without Docker, you will need Bun and Go (with CGO enabled) installed.
1. Build the Frontend
Navigate to the root directory and use npm to install dependencies and build the static HTML/JS payload.
npm install
npm run build
(This produces a build/ directory that the Go backend expects).
2. Run the Backend Server
Because the backend uses go-sqlite3, it requires CGO to compile. Navigate completely into the server directory so the relative paths for serving the ../build and ../results folders remain accurate.
cd server
go run .
The server will automatically scan the ../results folder on startup, index the simulations into the SQLite database, and host the web interface at http://localhost:8080.
API Endpoints
The Go backend provides a simple REST API to interact with the simulations:
GET /api/simulations
Returns a JSON array of all indexed simulations, including their ID, name, created date, and configuration string.
POST /api/simulations/create
Creates a new simulation entry.
- Request Body: JSON object containing the combined configurations (e.g.,
search,uav,ugv). The configuration must contain at least one search pattern definition (eitherspiral,lawnmower,levy, orsar) inside the JSON. - Behavior: Checks if an identical config exists. If so, it returns the existing simulation ID/Name for overwriting. If not, it allocates a new
simulation_Xincrementally, inserts it into the database, builds the file directory in../results, and returns the new ID/Name. Returns400 Bad Requestif payload is not valid JSON or lacks a known search pattern. - Response: JSON object
{"id": <int>, "name": <string>}
GET /api/simulations/:id
Provides detailed JSON metadata for a specific simulation ID, including its name, JSON config string, creation timestamp, and a dynamically fetched array of all the internal resources (images, logs, videos) located within its folder.
PUT /api/simulations/:id/time
Updates the numeric benchmarking metrics (search_time and total_time) for a specific simulation run.
- Request Body: JSON object containing floats:
{"search_time": 25.4, "total_time": 105.8} - Response: JSON object
{"status": "success"}
PUT /api/simulations/:id/hardware
Updates the physical hardware strings tied directly to a specific simulation run to properly map system configurations to benchmark outcomes.
- Request Body: JSON object containing string fields (nullable):
{"cpu_info": "Intel i9", "gpu_info": "RTX 4090", "ram_info": "64GB DDR5"} - Response: JSON object
{"status": "success"}
PUT /api/simulations/:id/rename
Renames a specific simulation. Automatically updates the database and physically renames the matching directory path on the system filesystem to mirror structural links.
- Request Body: JSON object containing the new underlying name:
{"name": "new_simulation_name"} - Response: JSON object
{"status": "success", "new_name": "new_simulation_name"}
POST /api/simulations/:id/upload
Uploads a new media or data resource file directly into a completed simulation run. Supports both images (e.g., PNGs) and heavy video files (e.g., AVIs) out of the box with an initial multi-part memory bounds mapping of 32 MB (spilling to disk for larger files).
- Request Data:
multipart/form-datapacket using thefilekeyword carrying the binary data blocks. - Behavior: The Go service validates the simulation ID exists, dynamically builds the memory pool, opens a stream writer caching the binary blob into the
../results/simulation_X/filename.extdirectory path, and records the resource in the primary SQLite instance. - Response: JSON object
{"status": "success", "filename": "example.png"}
DELETE /api/simulations/:id
Permanently deletes a complete simulation from the platform.
- Behavior: Deletes the record from the SQLite database along with any bound resource hooks. It subsequently initiates a full removal of the linked
../results/:namedirectory natively off the OS to completely recover physical disk space. - Response: JSON object
{"status": "success"}
DELETE /api/simulations/:id/resources/:filename
Deletes a specific user-uploaded media asset or log file dynamically out of a simulation without dropping the core simulation entity itself.
- Behavior: Detaches the file association string from SQLite and forces an OS-level file drop directly onto the specific asset file stored within the simulation's results directory.
- Response: JSON object
{"status": "success"}
DELETE /api/simulations/clear-fails
Purges all failed tracking simulations globally from the database and physically drops their filesystem result nodes off the host system. A simulation is identified natively as "failed" when its total_time tracking variable maps to a 0.0 or numeric null value during extraction.
- Response: JSON object
{"status": "success", "cleared": <int>}
GET /api/stats
Retrieves globally aggregated system statistics across the entire database resolving UI constraints.
- Response: JSON object
{"total_simulations": <int>, "fastest_sim_id": <int>, "total_storage_bytes": <int>}