DevelopersTechnologySpacefuel Grpc
Technology

SpaceFuel gRPC

SpacePOS talks to SpaceFuel over gRPC (local on the POS machine, with dev overrides).

Contract

  • Proto lives in the contracts/spacefuel-contracts submodule.
  • spacefuel.v1.proto defines:
    • SpaceFuelBridge/ConnectStream (bidi stream)
    • SpaceFuelBridge/GetForecourtState (unary)

SpacePOS client behavior

  • SpaceFuel responds on connect with:
    1. payload = "connected" (system)
    2. payload = { "type": "forecourt_state", "state": { ... } }
  • SpacePOS parses that envelope and maps the response to ForecourtState.

Transaction events

SpaceFuel also emits transaction events as JSON envelopes:

  • transaction_authorized
  • fueling_in_progress
  • transaction_saved

SpacePOS maps these into typed payloads and updates the dashboard state.

Endpoint resolution

SpacePOS resolves host/port in this order:

  1. Per-library config:
    • spacefuel_grpc_host
    • spacefuel_grpc_port
  2. Optional SpaceFuel state file (see below)
  3. Default: 127.0.0.1:5401

In production builds, host is forced to 127.0.0.1.

SpaceFuel state file (discovery)

If SpaceFuel is started outside SpacePOS, it can write a discovery file that SpacePOS will read on startup:

  • Path (SpacePOS data dir):
    • extensions/spacefuel/grpc.json
  • JSON schema:
{
  "host": "127.0.0.1",
  "port": 5401
}

SpacePOS uses this file as a fallback and persists the values into the library config when appropriate.

Auto-connect

On app startup, SpacePOS will auto-connect to SpaceFuel gRPC for any forecourt-master library. The gRPC client already has a retry loop, so connection failures back off and retry.

Dev overrides

In dev builds:

  • The SpaceFuel page exposes host + port fields.
  • Overrides are persisted to the library config for that library.

Event pipeline

The gRPC stream feeds fueling.events, which updates:

  • FuelingStateContext live ForecourtState
  • A capped debug event log (last 50 events)

The dashboard consumes the derived ForecourtState only, keeping UI logic clean.

Fueling panel UI (terminal + sessions)

  • A compact fueling panel drawer is available in the terminal and terminal sessions top bar.
  • Visibility is gated by library.config.is_forecourt_master.
  • Width is resizable and persisted in layoutStore.fuelingPanel.
  • The drawer renders the compact dispenser cards from the SpaceFuel dashboard.

TODO: ERP RabbitMQ emission (non-blocking)

If SpaceFuel events need to be mirrored to ERP via RabbitMQ, keep SpacePOS responsive by publishing asynchronously.

Planned approach:

  • Define the ERP event set:
    • Required: transaction_authorized, fueling_started, transaction_saved
    • Optional: fueling_in_progress (throttle or threshold)
  • Use a bounded async queue (e.g. mpsc::channel(1000)) between the event bus and the RabbitMQ publisher.
  • Never publish inline on the event handler; always enqueue and return.
  • If the queue is full, drop or merge only fueling_in_progress events.
  • Publish in a background task with retry/backoff (no blocking on POS).
  • Log publish failures and dropped progress events (rate-limited).