-
Notifications
You must be signed in to change notification settings - Fork 8
Description
Also coming from a previous PR that was about refactoring, I have noticed some code was not completely separated by their concerns. That is okay, I do this all the time too :)
But seeing how this project might grow, it may be worthwhile to reconsider the current architecture. Therefore I've asked gemini and this is what it proposes. Tbh I don't understand every detail, but I figured you would know whether this makes sense and this is something we should pursue.
I have tried to display everything as concise and understandable as possible.
This plan outlines the refactoring of the SimApi project to decouple the Data Provider (the daemon that maps game data) from the Client SDK (the library used by dashboards and HUDs).
1. The Core Benefit: Separation of Concerns
Currently, any application that wants to read telemetry must link against a monolithic library that contains code for every supported racing game.
Why this matters
- Maintenance – Adding support for a new game shouldn’t require recompiling every HUD and dashboard.
- Dependency hygiene – Clients (HUDs) shouldn’t need
libuvorlibconfig; only the provider (simd) needs those for process and configuration management. - Ease of use – Switch from manual memory mapping to a clean
simapi_connect()function.
2. Architecture Diagrams
Before: The Monolithic Architecture
The simapi library is a leaky abstraction containing both the public interface and the heavy mapping machinery.
graph TD
subgraph libsimapi.so [Target: simapi - The Monolith]
SDK[Public: simdata.h]
Engine[Internal: simmapper.c + mapping/]
Games[Game Headers: ac.h, rf2.h, etc.]
Engine --> SDK
Engine --> Games
end
subgraph simd_app [Target: simd]
Daemon[simd.c]
Daemon -- "Links & Includes" --> libsimapi.so
end
subgraph consumers [Consumers]
VT[view_telemetry.c]
VT -- "Manual SHM Read" --> SHM[("/dev/shm/SIMAPI.DAT")]
VT -- "Includes" --> SDK
end
Daemon -- "Writes" --> SHM
AFTER: The Layered Architecture
The mapping logic is encapsulated. The public SDK is tiny and dependency-free.
graph TD
subgraph ClientSDK [Target: libsimapi - Public SDK]
SDK[simdata.h / simapi.h]
API[simapi_client.c - NEW]
API --> SDK
end
subgraph MappingEngine [Target: libsimmapper - Internal]
Engine[simmapper.c + mapping/]
GHeaders[ac.h, rf2.h, etc.]
Engine --> GHeaders
end
subgraph Daemon [Target: simd - The Service]
Main[simd.c]
Main -- "Links" --> MappingEngine
Main -- "Links" --> ClientSDK
end
subgraph Apps [Client Applications]
HUD[view_telemetry / HUDs]
HUD -- "Links" --> ClientSDK
end
Main -- "Writes" --> SHM[("/dev/shm/SIMAPI.DAT")]
ClientSDK -- "Reads" --> SHM
3. Comparison Contrast
| Feature | Current (Monolith) | New (Layered) |
|---|---|---|
| Public API | Manual shm_open + mmap |
simapi_connect(), simapi_read() |
| Client Dependencies | libuv, libconfig, game headers |
None (standard C library only) |
| Namespace Hygiene | ac.h, rf2.h exposed to clients |
Game structures hidden in libsimmapper |
| Build Impact | Adding a game = rebuild everything | Adding a game = rebuild simd only |
| Library Size | Large (contains translation logic) | Tiny (<20KB SDK) |
4. Implementation Checklist: What Changes?
1. Structural Changes
- Move
simapi/mapping/andsimapi/simmapper.cto a new internal directory (e.g.,simapi/internal/orsimd/mapper/). - Move
ac.h,rf2.h,pcars2.h, etc., to the internal directory.
2. New Files
simapi/simapi.c: Implements the new client-facing API:SimData* simapi_connect()— handlesshm_openandmmap.void simapi_disconnect()— handlesmunmap.
simapi/simapi.h: Cleaned up to only export the two functions above and theSimDatastruct.
3. Build System (CMakeLists.txt)
- Split the simapi target:
simapi: A public SHARED library (the SDK).simmapper: A private STATIC library (the Engine).
- Update
simd: Link it against bothsimmapperandsimapi. - Update
view_telemetry: Update code to usesimapi_connect().
5. Impact on monocoque
This refactoring is highly beneficial for the Monocoque project (and other consumers like simmonitor). Since Monocoque is "sim-agnostic" by design, it currently pays a "tax" for the monolithic architecture that this refactor eliminates.
Here is exactly how it affects Monocoque:
1. Zero Breaking Changes (Data Compatibility)
- The most important point: The
SimDatastructure remains 100% identical. - Because the binary layout of the shared memory (
SIMAPI.DAT) does not change, existing versions of Monocoque will continue to work without any modifications. - It will still find the data exactly where it expects it in
/dev/shm/.
2. Radical Dependency Reduction
- Currently, if you want to compile Monocoque, you effectively have to include the logic for every single simulator
simapisupports. - Before: Monocoque (a client) has a transitive dependency on
libuv,libconfig, and all the simulator-specific mapping code (Assetto Corsa, rFactor 2, etc.). - After: Monocoque only links against the new, tiny
libsimapi. It becomes a pure "Consumer" with zero knowledge of the "Provider" complexities.
3. Simplified Integration (The SDK)
- Code Cleanup: You can delete the manual
shm_open,ftruncate, andmmapboilerplate code in Monocoque. - New API: Instead of managing file descriptors and memory pointers, Monocoque would simply do:
SimData* telemetry = simapi_connect();
// ... use telemetry->speed, etc ...
simapi_disconnect();4. Improved Portability
Because the new libsimapi will have zero external dependencies (only standard C headers), it becomes much easier to port Monocoque to different distributions or environments. You no longer need to ensure that the client environment has all the libraries required by the mapping engine.
Summary of Impact for Monocoque
| Aspect | Impact |
|---|---|
| Binary Compatibility | Perfect. No change required to run. |
| Source Code | Simplified. Can remove ~50-100 lines of SHM boilerplate. |
| Build System | Streamlined. No longer needs to link against provider-specific libs. |
| Maintenance | Better. Monocoque doesn't need a re-build when simapi adds a new game. |
In short: Monocoque goes from being "tied to the engine" to "talking to an interface."