145 lines
7.1 KiB
Markdown
145 lines
7.1 KiB
Markdown
# straywild Discovery Server
|
|
|
|
An ephemeral public-room directory and allocation-based UDP privacy relay for straywild. Player
|
|
hosts choose direct or relay routing when they advertise through HTTPS. Browsers retrieve
|
|
compatible metadata without receiving an IP address, and relay-enabled joins give each player an
|
|
isolated relay endpoint instead of the other peer's network address. Dedicated servers are
|
|
direct-only and cannot consume shared relay capacity.
|
|
|
|
The service also runs a small UDP rendezvous. It observes packets from the host's exact ENet socket
|
|
and lets that host punch the allocated relay socket. Relay gameplay is pinned to the authenticated
|
|
joining socket and verified host endpoint, bounded by packet/byte budgets, and removed after an
|
|
idle timeout. Addresses are held only in memory and are not written to the application log.
|
|
|
|
Friend presence and live room invitations use the same service as short-lived capability channels.
|
|
There are no discovery accounts, durable friend records, or offline messages; friendship state
|
|
stays on each player's device.
|
|
|
|
## Requirements
|
|
|
|
- Python 3.11 or newer
|
|
- A TLS reverse proxy for public deployment
|
|
|
|
There are no runtime Python package dependencies.
|
|
|
|
## Run locally
|
|
|
|
```bash
|
|
python3 -m straywild_discovery
|
|
```
|
|
|
|
The default listener is `127.0.0.1:7770`.
|
|
|
|
```bash
|
|
curl http://127.0.0.1:7770/health
|
|
```
|
|
|
|
Set `straywild_DISCOVERY_BUILD_REVISION` to the deployed Git commit. The health response reports
|
|
both the package version and that build revision, which makes production/source drift visible.
|
|
|
|
Run the focused tests with:
|
|
|
|
```bash
|
|
python3 -m unittest discover -v
|
|
```
|
|
|
|
## Configuration
|
|
|
|
Environment variables are documented in
|
|
[`deploy/straywild-discovery.env.example`](deploy/straywild-discovery.env.example).
|
|
|
|
The intended public topology is:
|
|
|
|
```text
|
|
straywild client -> HTTPS reverse proxy -> 127.0.0.1:7770 discovery service
|
|
straywild client -----------------------> public UDP rendezvous:7771
|
|
direct room client ---------------------> authoritative ENet/UDP host
|
|
relay room client ----------------------> allocated UDP relay:20000-22047
|
|
allocated UDP relay --------------------> player-hosted ENet/UDP host
|
|
```
|
|
|
|
Configure the Godot client with the reverse proxy's HTTPS origin through
|
|
`network/discovery/base_url` in `project.godot`. For local development, the
|
|
same value can be overridden without modifying the project by setting
|
|
`straywild_DISCOVERY_URL` before launching the game.
|
|
|
|
The reverse proxy must preserve the client address in `X-Forwarded-For`, and
|
|
its own address must be listed in `straywild_DISCOVERY_TRUSTED_PROXY_CIDRS`.
|
|
Apply ordinary request-rate limits to the write endpoints at the proxy. Do not
|
|
expose the Python listener directly to the public Internet.
|
|
|
|
### Privacy logging policy
|
|
|
|
The discovery and relay application must not log private player information. This includes raw IP
|
|
addresses and ports, address-derived pseudonyms, request paths tied to room IDs, room or player
|
|
names, request bodies, headers, join and lease tokens, authentication material, and friendship
|
|
capabilities. HTTP access logging is disabled completely. Unexpected request failures produce only
|
|
a generic operational error without a peer address, request contents, or request-specific
|
|
traceback.
|
|
|
|
The service necessarily handles network endpoints temporarily in memory to observe routes, apply
|
|
abuse limits, and forward active relay traffic. Those endpoints expire with their room, join, or
|
|
relay state and are never written to the application log or a database. Temporary processing is
|
|
not permission to retain or repurpose that information.
|
|
|
|
Production deployments must also disable reverse-proxy access logs for every discovery route.
|
|
Default proxy log formats normally contain a client address and are not acceptable here. Do not
|
|
log forwarded addresses, request bodies, authorization headers, or tokens at the proxy, firewall,
|
|
or service wrapper. Hosting providers and upstream networks may retain connection metadata under
|
|
their own policies; operators should choose providers accordingly and disclose that boundary.
|
|
|
|
Use the sample systemd unit in [`deploy/straywild-discovery.service`](deploy/straywild-discovery.service)
|
|
as a deployment starting point. The service keeps only active leases in memory, so it requires no
|
|
database, backups, or schema migrations.
|
|
|
|
## Connectivity boundary
|
|
|
|
The game first requests UPnP forwarding, then uses same-socket UDP rendezvous and hole punching.
|
|
A player host chooses whether its public listing is direct or relay. A relay room punches a unique
|
|
allocation and both peers exchange ENet packets through it; a direct room connects through the
|
|
verified host route and consumes no relay allocation. ENet gameplay authority does not move to
|
|
discovery. Dedicated advertisements must be direct and a dedicated relay request is rejected.
|
|
Expose the configured traversal port and full relay allocation range over UDP in both the host
|
|
firewall and provider firewall.
|
|
The rendezvous listener intentionally processes its small, bounded packets serially so arbitrary
|
|
datagrams cannot create unbounded worker threads. Apply conservative edge rate limits as an
|
|
additional deployment control.
|
|
|
|
The relay prevents the player host and joiner from seeing one another's address during normal
|
|
network traffic. It is not anonymity from the relay operator, hosting provider, upstream network,
|
|
or a compromised client. The discovery process necessarily handles both endpoints in volatile
|
|
memory. Clients treat the host-selected connection mode as binding: failure to allocate or reach a
|
|
relay stops the join and never silently falls back to direct transport. Operators may explicitly
|
|
disable relay availability for private development; a player relay advertisement is then rejected.
|
|
|
|
## API
|
|
|
|
See [`docs/API.md`](docs/API.md) for the versioned HTTP contract.
|
|
|
|
## Repository relationship
|
|
|
|
This is deliberately a separate repository from the Godot game so the service can deploy and roll
|
|
back independently. Production tags follow the coordinated straywild release train: a
|
|
`vX.Y.Z-alpha` tag identifies the discovery snapshot tested for the same game and dedicated-server
|
|
release. The versioned HTTP contract remains independent from straywild's save schema and gameplay
|
|
network protocol. Each tagged deployment accepts room advertisements only from its matching game
|
|
release so incompatible rooms are never presented as publicly available.
|
|
|
|
Existing NETfishing installations can be upgraded in place. The legacy
|
|
`netfishing_discovery` module, command name, and `NETFISHING_DISCOVERY_*`
|
|
environment variables remain accepted, while new installations should use the
|
|
Straywild names shown above. When both forms of an environment setting exist,
|
|
the Straywild value takes precedence.
|
|
|
|
## Licensing
|
|
|
|
Project-owned source code is licensed under the GNU General Public License,
|
|
version 3 or, at your option, any later version
|
|
([GPL-3.0-or-later](LICENSE)).
|
|
|
|
straywild and Woofmeow branding is not granted under the GPL; see
|
|
[`TRADEMARKS.md`](TRADEMARKS.md). Unsolicited contributions are not accepted;
|
|
see [`CONTRIBUTING.md`](CONTRIBUTING.md). Historical and expressly invited
|
|
work is governed by [`CONTRIBUTOR-TERMS.md`](CONTRIBUTOR-TERMS.md).
|
|
|
|
Copyright © 2026 Woofmeow.
|