The rust-link sidecar: it owns the loopback listener the Oxide bridge plugin dials into, and serves the website a WebSocket feed plus store-backed reads. Protocol 1 is deliberately three frames — server.hello, ping/pong, and one correlated server.status — because phase 1's job is to get every seam working at once with almost nothing in them. What is load-bearing rather than incidental: * The plugin is the TCP client and this process owns the listener, so a Rust server opens no extra port. Loopback is the trust boundary on that link and there is no token on it; the website-facing surface is the opposite, with auth always on and a token generated and persisted on first start. * Inbound lines are capped at 1 MiB from the start rather than after the first large frame arrives. An over-long line is discarded and the connection stays up: one malformed frame is not a reason to drop a link live events flow over. * Store-backed reads answer while the game is off, which is what lets a website render a server list during a wipe. /status is the one route that fails when the game is down, and /server answers 204 rather than a null when the game has never connected -- those are different answers and a client that cannot tell them apart renders a server that does not exist. * The two RPC failures get distinct codes. 503 means the game is down; 504 means it is up and did not answer. Different fixes. * rpc::REPLY_TIMEOUT is a ceiling every later command budget sits under: core classifies a budget overrun as retryable unconditionally, so an action whose budgetMs does not exceed it can never report retry:false. One defect found while building, which no unit test would have caught: a four-connection SQLite pool over :memory: hands out four separate empty databases, because an in-memory database is per connection. It presents as 'no such table' from a random subset of queries. The pool is now capped at one connection for an in-memory path, which is the only coherent reading of :memory: and is what makes it usable at all. Exercised end to end against a live Rust server: a server.hello travelled game -> sidecar -> module -> the public website API, and killing this process left the game untouched. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016wDDVXWMDz82WqE1i969r4
23 lines
810 B
TOML
23 lines
810 B
TOML
[package]
|
|
name = "rust-link-sidecar"
|
|
version = "0.1.0"
|
|
edition = "2021"
|
|
license = "GPL-3.0-or-later"
|
|
description = "Rust sidecar for the rust-link bridge: terminates the loopback link to a Rust/Oxide game server and exposes WebSocket + REST to the website."
|
|
|
|
[dependencies]
|
|
tokio = { version = "1", features = ["rt-multi-thread", "macros", "net", "io-util", "sync", "time", "signal"] }
|
|
serde = { version = "1", features = ["derive"] }
|
|
serde_json = "1"
|
|
tracing = "0.1"
|
|
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
|
|
anyhow = "1"
|
|
axum = { version = "0.7", features = ["ws"] }
|
|
sqlx = { version = "0.8", features = ["runtime-tokio", "sqlite"] }
|
|
toml = "0.8"
|
|
getrandom = "0.2"
|
|
chrono = { version = "0.4", default-features = false, features = ["std", "clock"] }
|
|
|
|
[profile.release]
|
|
opt-level = 2
|