synvael/docs/adr/0010-net-crate-async-runtime.md

28 lines
2.2 KiB
Markdown

# 0010. Dedicated `net` crate with a confined async runtime
- **Status:** Accepted
- **Date:** 2026-07-12
## Context
The network transport is QUIC via `quinn` which is an asynchronous library built on the `tokio` runtime and requires TLS 1.3 through `rustls`. These are heavy dependencies that pull an entire async ecosystem into the build.
The `shared` crate is mandated to stay lean and dependency-light: it is the protocol/data layer, holding pure serde message types with no async, rendering, or engine internals. Placing transport code in `shared` would violate that mandate and force every consumer of the protocol types to compile `tokio` and `rustls`. At the same time, the simulation is synchronous: the `server` runs a synchronous `bevy_ecs` loop and the `client` runs a synchronous `winit` event loop. Introducing an async runtime must not turn those loops async or leak `tokio` throughout the workspace.
## Decision
Transport lives in a dedicated `net` crate, separate from `shared`, and the `tokio` runtime is confined to it.
- `net` owns the `quinn`, `tokio`, and `rustls` dependencies, plus the QUIC endpoints, connection lifecycle, and wire framing.
- `shared` continues to hold only the protocol message *types* (serde, no async).
- Both `client` and `server` depend on `net`.
- The async runtime is bridged to the synchronous simulation over channels (`crossbeam-channel`), consistent with the message-passing concurrency model in `AGENTS.md`. The synchronous loops never `.await`; they send and receive protocol messages across the boundary.
## Consequences
- `shared` stays lean: consumers of the protocol types do not compile the async stack.
- The async surface is quarantined. Only `net` deals with `tokio`, keeping the `server` and `client` loops synchronous and unchanged.
- The workspace now has six crates. `net` sits between `shared` (types it carries) and the two binaries (which drive it).
- The channel bridge is an explicit boundary that must be maintained: work crossing between the async runtime and the sync simulation flows through channels, never through shared async state or by making the sim async.
- A crypto provider backend is required by `rustls`; the transport code must install one before building QUIC configuration.