Add comprehensive wiki documentation for RconDataBridge, covering installation, configuration, protocol details, operation references, and internal architecture.
This commit is contained in:
169
wiki/Architecture.md
Normal file
169
wiki/Architecture.md
Normal file
@@ -0,0 +1,169 @@
|
||||
# Architecture
|
||||
|
||||
This page covers how RconDataBridge is built internally: the module map,
|
||||
the boot sequence, the security model, and the Project Zomboid engine
|
||||
quirks the mod works around. It's aimed at anyone reading or modifying the
|
||||
mod's own Lua code, rather than consuming the protocol from outside; for
|
||||
that, see [Protocol Reference](Protocol-Reference) and [Operations
|
||||
Reference](Operations-Reference).
|
||||
|
||||
## Boot sequence
|
||||
|
||||
On `Events.OnServerStarted`, bootstrap code runs, in order:
|
||||
|
||||
1. Run internal self-tests (JSON and base64 codecs), if enabled.
|
||||
2. Register the base RCON options (`ProtocolVersion`, `WorldStats`,
|
||||
`Request`, `Response`, `LastResponse`).
|
||||
3. Register every operation into the operation registry.
|
||||
4. Publish the initial `RconDataBridge_ProtocolVersion` value.
|
||||
5. Start the request pipeline and the world and player telemetry pollers.
|
||||
|
||||
`Events.OnServerStarted` is known to fire more than once per boot in
|
||||
Project Zomboid, so every step above guards against running twice: option
|
||||
registration checks for an existing option first and wraps the underlying
|
||||
engine call in a protected call as a second line of defense, and each
|
||||
poller's `init()` function is guarded by a local flag, so its event
|
||||
listeners are only ever added once.
|
||||
|
||||
## Request flow
|
||||
|
||||
Once booted, a single request travels through the modules like this:
|
||||
|
||||
```text
|
||||
RCON client
|
||||
|
|
||||
| changeoption RconDataBridge_Request <base64 JSON>
|
||||
v
|
||||
RconDataBridge_Request option (single mailbox slot)
|
||||
|
|
||||
| polled every N ticks (Poll Interval setting)
|
||||
v
|
||||
Request pipeline
|
||||
|-- base64 decode, size check ----> reject: SCHEMA_ERROR / PAYLOAD_TOO_LARGE
|
||||
|-- JSON decode, envelope check --> reject: SCHEMA_ERROR
|
||||
|-- idempotency check ------------> known id: replay the cached response
|
||||
|-- rate limit check -------------> reject: RATE_LIMITED
|
||||
v
|
||||
Operation registry (allowlist, exact-name lookup)
|
||||
|-- unknown op -------------------> reject: OP_NOT_ALLOWED
|
||||
v
|
||||
Operation handler (Ops/RDB_Op*.lua)
|
||||
|-- handler throws ---------------> reject: INTERNAL_ERROR
|
||||
v
|
||||
Response envelope { ok, data } or { ok: false, error }
|
||||
|
|
||||
| every outcome above, success or rejection, is also written to the audit log
|
||||
v
|
||||
RconDataBridge_Response / RconDataBridge_LastResponse
|
||||
|
|
||||
| showoptions, base64 decode
|
||||
v
|
||||
RCON client
|
||||
```
|
||||
|
||||
See [Protocol Reference](Protocol-Reference) for what each error code
|
||||
means and how a client should consume this cycle.
|
||||
|
||||
## Module responsibilities
|
||||
|
||||
### Options registry
|
||||
|
||||
A thin wrapper over Project Zomboid's server options store. Registering an
|
||||
option needs both an "add option" call and a separate "add to public
|
||||
options" call, or it never shows up in `showoptions`, since that command
|
||||
reads a different internal list than the one a plain add populates.
|
||||
|
||||
### Request pipeline
|
||||
|
||||
Polls `RconDataBridge_Request` on a configurable tick interval, since
|
||||
there's no "option changed" event. Decodes base64 to JSON, validates the
|
||||
envelope, checks idempotency and the rate limit, dispatches through the
|
||||
operation registry, publishes the response, and always logs the outcome to
|
||||
the audit trail, including rejections.
|
||||
|
||||
### Operation registry
|
||||
|
||||
The allowlist; Dispatch is an exact-name lookup into a table, nothing more;
|
||||
new operations are added one file per operation.
|
||||
|
||||
### Security
|
||||
|
||||
Payload size cap (4096 bytes decoded), envelope schema validation, and a
|
||||
global, not per-connection, sliding-window rate limit, since RCON requests
|
||||
carry no caller identity to limit by individually.
|
||||
|
||||
### Idempotency
|
||||
|
||||
Replays the cached response for a repeated request `id` within a
|
||||
configurable window, protecting side-effecting operations, such as
|
||||
`save_server`, from retries. After the window expires, the same `id` runs
|
||||
fresh.
|
||||
|
||||
### Config
|
||||
|
||||
A facade over admin-tunable settings. A small set of values, such as the
|
||||
maximum payload size, are fixed constants; everything else is read live
|
||||
from Sandbox Options. See [Configuration](Configuration).
|
||||
|
||||
### World stats
|
||||
|
||||
Refreshed roughly once an in-game minute from the engine's game clock,
|
||||
cached in memory, and mirrored directly to `RconDataBridge_WorldStats`, so
|
||||
`get_world_stats` and the option always agree, and reading the option skips
|
||||
a request/response round trip entirely.
|
||||
|
||||
### Player snapshot
|
||||
|
||||
The source of truth for player data, both online and offline, persisted so
|
||||
it survives a restart, since the engine has no API for offline player data
|
||||
on its own.
|
||||
|
||||
### JSON and base64 codecs
|
||||
|
||||
Self-contained shared codecs with no external dependencies. Each runs its
|
||||
own self-test at boot when the debug self-test setting is enabled.
|
||||
|
||||
## Security model
|
||||
|
||||
A handful of rules define the mod's security boundary and are treated as
|
||||
hard constraints rather than style preferences:
|
||||
|
||||
- **No new transport, port, or authentication layer.** RCON access is the
|
||||
only access control, by design.
|
||||
- **No dynamic operation dispatch.** The operation registry only ever does
|
||||
an exact-name table lookup; an RCON request can never cause arbitrary
|
||||
Lua code to run.
|
||||
- **All operations are explicitly allowlisted.** An unrecognized `op` value
|
||||
returns `OP_NOT_ALLOWED` rather than being interpreted in any way.
|
||||
- **Every remote action is logged**, with its request id, operation,
|
||||
result, and timestamp, including rejected requests, through the audit
|
||||
log described above.
|
||||
- **Requests are validated and bounded** on payload size, envelope schema,
|
||||
and rate, before an operation handler ever runs.
|
||||
|
||||
## Engine constraints the mod works around
|
||||
|
||||
A number of behaviours in the code exist specifically to work around gaps
|
||||
or quirks in the Project Zomboid server engine, rather than being
|
||||
arbitrary design choices. The straightforward ones:
|
||||
|
||||
| Constraint | Why | How it's handled |
|
||||
|-------------------------------------------------|-----------------------------|------------------------------------------------------|
|
||||
| No "option changed" event | Doesn't exist in the engine | Tick-throttled polling in the request pipeline |
|
||||
| No connect or disconnect event | Doesn't exist in the engine | Diffing the online roster against the last known set |
|
||||
| No offline-player registry API | Doesn't exist in the engine | Player snapshots are persisted independently |
|
||||
| `OnServerStarted` fires more than once per boot | Engine behavior | Every initializer guards on a local flag |
|
||||
|
||||
As a special client facing quirk:
|
||||
|
||||
### RCON responses can span multiple packets
|
||||
|
||||
Confirmed from the server's own RCON response handling: a large response,
|
||||
such as a `showoptions` call once this mod's options are added to the
|
||||
roughly 140 built-in ones, gets chunked across multiple packets with no
|
||||
explicit end-of-response marker.
|
||||
|
||||
This is a client-side concern rather than a mod-side one. Any RCON client
|
||||
must accumulate every packet sharing a request id rather than resolving on
|
||||
the first one it receives. See the client checklist in [Protocol
|
||||
Reference](Protocol-Reference#9-client-implementation-checklist).
|
||||
Reference in New Issue
Block a user