Skip to main content

Architecture Overview

A Windows .NET worker app that bridges Microsoft Flight Simulator (via SimConnect) to the Simops backend over HTTP/WebSockets and optional RabbitMQ messaging.

Solution layout

Two projects in SimopsConnect Solution:

  • SimulatorConnect/: thin wrapper around the SimConnect SDK. Owns the Win32 message loop, manages the SimConnect lifecycle, and exposes typed observables of simulator data.
  • SimopsConnect/: the host app. Layered into Application/ (domain services) and Infrastructure/ (HTTP, WebSocket, messaging). Program.cs wires the generic host, WorkerService orchestrates the pipelines.

Runtime composition (Program.cs:19)

  1. Builds an IHost with config from Azure App Configuration + appsettings.json + filtered command-line args (sensitive keys like JWT/Messaging credentials are stripped from CLI overrides — Program.cs:78).
  2. Registers three layers via DI extension methods: AddApplication(), AddInfrastructure(), AddSimConnect().
  3. Starts WorkerService, then runs MessageWindow.MessageLoop() on the main thread (required for SimConnect's Win32 callbacks), with host.Run() on a background thread.
  4. Logging via Serilog → console.

Data flow (the core abstraction is Rx)

Infrastructure

  • HTTP (Infrastructure/Http/): HttpService listens on Http:Endpoint (default :45928), with RequestsHandlerService dispatching requests; JWT validation configured via Jwt:Issuer/Audience/JwksUri. AllowImmediateStart bypasses the start handshake.
  • WebSocket (WebSocketService): broadcasts combined aircraft state + flight info to all connected clients on :45929. Recent commit 0557aa3 added multi-client support.
  • Messaging (Infrastructure/Messaging/): RabbitMQ publisher, gated by Messaging:Enabled. Two routing keys: flights (metadata) and flightevents (telemetry tick).

Configuration model

Three options sections bound to strongly-typed configs: HttpConfig, MessagingConfig, DataConfig (the latter holds Aircraft:RefreshInterval). Azure App Config overlays per-environment values; the local appsettings.json is mostly defaults/empty placeholders.

Notable design choices

  • Reactive Extensions everywhere — services expose IObservable/Subject rather than events or async streams. This keeps the worker pipeline composable (WithLatestFrom, Where, DistinctUntilChanged) and lets the SimConnect callback loop fan out cleanly.
  • Singleton lifetime for all application services: state (connection, current flight) is held in BehaviorSubjects inside the services themselves, no external store.
  • Hidden Azure App Config endpoint
  • Win32 coupling — the app is win-x64 only because SimConnect requires a window handle for its callback model (MessageWindow.MessageLoop()).