All checks were successful
PR Checks / rust-gates (pull_request) Successful in 1m32s
The README opened straight into cargo build, which is the wrong first instruction for someone standing up a shard: the installer places this binary, its config, a service account and the service registration. Adds a short operator section pointing at the installer (and at INSTALL.md Appendix A3-A4 for installing by hand, still supported), marks everything below it as development, and lists the installer under related repos. Co-Authored-By: Claude <noreply@anthropic.com>
150 lines
7.6 KiB
Markdown
150 lines
7.6 KiB
Markdown
# uo-link — Rust sidecar
|
||
|
||
The **Rust sidecar** half of the Runic Gateway bridge. The ServUO shard dials out to this sidecar
|
||
over a loopback TCP socket (newline-delimited JSON); the sidecar owns the WebSocket + REST API the
|
||
website consumes, along with auth, buffering, and fan-out.
|
||
|
||
```
|
||
ServUO plugin (C#, net48) ──loopback TCP, newline-JSON──► Rust sidecar ──WebSocket/JSON──► website
|
||
(RunicGateway/servuo-plugins) >>> THIS REPO <<<
|
||
```
|
||
|
||
The shard never speaks WebSocket and exposes no port of its own — the sidecar is the only
|
||
network-facing component, which is what keeps the game unreachable from the internet.
|
||
|
||
## Running a shard? Don't build this
|
||
|
||
The [**Runic Gateway installer**](https://gitea.whitlocktech.com/RunicGateway/installer) installs
|
||
this sidecar for you — the released binary, its config, a hardened service account and the service
|
||
registration — alongside the shard plugin, in one run, on Linux or Windows:
|
||
|
||
```bash
|
||
sudo ./runicgateway-installer-linux-x86_64 install
|
||
```
|
||
|
||
It ends by printing the base URL, WebSocket URL, protocol version and auth token to paste into
|
||
**Admin → Shard** on your site. Guide:
|
||
[installer/INSTALL.md](https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/installer/INSTALL.md).
|
||
|
||
Installing it yourself is supported too — the release binaries on this repo's
|
||
[releases page](https://gitea.whitlocktech.com/RunicGateway/link/releases) are the same ones the
|
||
installer fetches, and
|
||
[INSTALL.md Appendix A3–A4](https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/installer/INSTALL.md#a3-install-the-sidecar)
|
||
covers placing the binary and registering the service by hand.
|
||
|
||
Everything below this line is for **developing on the sidecar**.
|
||
|
||
## Related repos
|
||
|
||
| Repo | What |
|
||
|------|------|
|
||
| **this** — `RunicGateway/link` | The Rust sidecar (`sidecar/`). |
|
||
| [RunicGateway/installer](https://gitea.whitlocktech.com/RunicGateway/installer) | The **installer** — deploys this sidecar and the plugin onto a shard host. The supported way to set one up. |
|
||
| [RunicGateway/servuo-plugins](https://gitea.whitlocktech.com/RunicGateway/servuo-plugins) | The **C# ServUO plugin** — the shard side of the bridge (`overlay/`, `patches/`, `deploy.ps1`, test scaffolding). |
|
||
| [RunicGateway/docs](https://gitea.whitlocktech.com/RunicGateway/docs) | All project documentation — design docs, protocol spec, integration guide, research. |
|
||
|
||
## Layout
|
||
|
||
| Path | What |
|
||
|------|------|
|
||
| `sidecar/` | The Rust sidecar crate — terminates the loopback link to the shard, exposes WS + REST to the website. See [`sidecar/README.md`](sidecar/README.md). |
|
||
| `.gitea/workflows/pr-checks.yml` | Gates every PR into `main` on `cargo fmt --check`, `cargo clippy -D warnings`, and `cargo test`. |
|
||
| `.gitea/workflows/release.yml` | Builds + releases the sidecar binary (Linux + Windows) on every merge to `main`. |
|
||
|
||
## Build & run (development)
|
||
|
||
Building from source is for working *on* the sidecar; a deployment gets its binary from a release,
|
||
via the installer or by hand. The sidecar is a standard cargo crate:
|
||
|
||
```bash
|
||
cd sidecar
|
||
cargo build --release # binary at target/release/uo-link-sidecar
|
||
cp sidecar.toml.example sidecar.toml # then edit
|
||
cargo run --release
|
||
```
|
||
|
||
Deploying it by hand rather than developing on it: `--config <PATH>` names the config file (as does
|
||
`$UOLINK_CONFIG`), and `--print-config` prints the resolved settings — **including the auth token
|
||
the website needs** — as JSON, provisioning the config file on first run. That is the supported way
|
||
to read the token back; it is not meant to be scraped from the log.
|
||
|
||
```bash
|
||
uo-link-sidecar --print-config --config /etc/runicgateway/sidecar.toml
|
||
```
|
||
|
||
### Running as a service
|
||
|
||
The same binary runs in the foreground and as a system service — there is no `--service` flag to
|
||
remember, because the process can tell how it was started.
|
||
|
||
- **Linux/systemd** supervises any foreground process, so the unit just runs the binary. `SIGTERM`
|
||
(what `systemctl stop` sends) and `SIGINT` both unwind it cleanly; logs go to the journal.
|
||
- **Windows** cannot. The service control manager only supervises a process that connects back to
|
||
it within ~30 seconds via `StartServiceCtrlDispatcher`; a plain console program registered with
|
||
`sc.exe create` is killed with **error 1053** despite running perfectly. So on Windows the sidecar
|
||
speaks that handshake: started by the SCM it runs as a service, started from a shell the connect
|
||
fails with `ERROR_FAILED_SERVICE_CONTROLLER_CONNECT` and it falls through to an ordinary
|
||
foreground run. It reports `Running` only once the shard port is bound and the store is open, and
|
||
— having no console — logs to `uo-link-sidecar.<date>.log` beside its config, rolled daily.
|
||
|
||
Only the starting and stopping is platform-specific: `src/app.rs` is the entire sidecar and is
|
||
shared, while `src/windows.rs` and `src/unix.rs` do nothing but start it and tell it when to stop.
|
||
The Windows crates are declared under `[target.'cfg(windows)'.dependencies]`, so Cargo neither
|
||
resolves nor builds them for a Linux target.
|
||
|
||
Registering the service is the installer's job; to do it by hand see
|
||
[INSTALL.md Appendix A4](https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/installer/INSTALL.md).
|
||
|
||
`.gitea/workflows/release.yml` cross-compiles Linux + Windows binaries and cuts a Gitea release on
|
||
every merge to `main` (conventional-commit versioning). See [`sidecar/README.md`](sidecar/README.md)
|
||
for configuration and the wire protocol.
|
||
|
||
Before that, `.gitea/workflows/pr-checks.yml` runs the same gates on every pull request into `main` —
|
||
`cargo fmt --check`, `cargo clippy --all-targets -- -D warnings`, then `cargo test --locked`. Run them
|
||
locally before pushing and the PR will be green:
|
||
|
||
```bash
|
||
cd sidecar
|
||
cargo fmt # or --check to just report
|
||
cargo clippy --locked --all-targets -- -D warnings
|
||
cargo test --locked
|
||
```
|
||
|
||
## Deployment & compatibility
|
||
|
||
The plugin ([RunicGateway/servuo-plugins](https://gitea.whitlocktech.com/RunicGateway/servuo-plugins))
|
||
and this sidecar are deployed **together** but built **independently**:
|
||
|
||
- The **plugin** is deployed as source into the ServUO server root and compiled by ServUO at boot —
|
||
no build artifact, no CI build.
|
||
- The **sidecar** is a standalone Rust binary released from this repo.
|
||
|
||
The only coupling is the **loopback JSON protocol** (the shard dials `127.0.0.1`). Compatibility is a
|
||
protocol concern, not a build-order one — keep the event/command catalog in sync across the two
|
||
repos. Canonical spec:
|
||
[PLAN.md](https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/link/PLAN.md) §5/§7 and
|
||
[INTEGRATION.md](https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/link/INTEGRATION.md).
|
||
Because a wedged or absent sidecar cannot stall the shard, either side can be deployed or restarted
|
||
independently.
|
||
|
||
---
|
||
|
||
## License
|
||
|
||
Runic Gateway is free software, licensed under the **GNU General Public License
|
||
v3.0 or later** — see [LICENSE.md](LICENSE.md).
|
||
|
||
Copyright (C) 2026 Runic Gateway
|
||
|
||
This program is free software: you can redistribute it and/or modify it under
|
||
the terms of the GNU General Public License as published by the Free Software
|
||
Foundation, either version 3 of the License, or (at your option) any later
|
||
version. It is distributed WITHOUT ANY WARRANTY; without even the implied
|
||
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
General Public License for more details.
|
||
|
||
Contributions are welcome — please read [CONTRIBUTING.md](CONTRIBUTING.md) (note
|
||
the **AI-usage disclosure** requirement) and our
|
||
[Code of Conduct](CODE_OF_CONDUCT.md). Report vulnerabilities privately per
|
||
[SECURITY.md](SECURITY.md).
|