5.2 KiB
5.2 KiB
lanspread-peer proposed protocol and architecture
This document proposes a tighter, more fault-tolerant protocol while keeping the current idea: mDNS discovery, QUIC transport, on-demand metadata, and chunked file transfers.
Goals (unchanged)
- Local LAN discovery via mDNS.
- QUIC + JSON messages for control, raw streams for file data.
- UI drives operations through
PeerCommand, peers remain headless. - Peers can appear/disappear at any time without data loss.
Peer lifecycle and message flow
1) Startup and advertise
- Start QUIC server.
- Advertise via mDNS with TXT records:
peer_id(stable ID, not tied to IP)proto_verlibrary_rev(monotonic local library revision)- optional
hostname
2) Discovery and handshake
When a peer is discovered:
- Connect and send
Hello { peer_id, proto_ver, library_rev, library_digest, features }. - Receive
HelloAck { peer_id, proto_ver, library_rev, library_digest, features }. - If the remote
peer_idis already known but the address changed, update it. - If protocol versions are incompatible, drop the peer (and keep mDNS watching).
- If library digests match, do nothing else.
- If digests differ:
- If we have a known
library_revfor that peer, requestLibraryDelta. - Otherwise request
LibrarySnapshot.
- If we have a known
3) Steady state
- Any message updates
last_seen. - Pings run only when idle (or on a longer interval), not every 5 seconds.
- Library updates are pushed as deltas, debounced and coalesced.
4) Shutdown
- Optional
Goodbye { peer_id }lets others remove the peer quickly. - If a peer vanishes without goodbye, stale timeout + ping removal handle it.
- Goodbye is a hint, never required for correctness.
Library sync protocol
Summary and snapshot
LibrarySummary { library_rev, library_digest, game_count }LibrarySnapshot { library_rev, games: Vec<GameSummary> }
Delta updates
LibraryDelta { from_rev, to_rev, added, updated, removed }removedis a list of game IDs.- Deltas are idempotent; ignore if
to_rev<= known rev.
GameSummary (concept)
id,name,eti_version,size,downloaded,installedmanifest_hash(hash of file list + sizes)availability(e.g.,ready,downloading,local_only)
When peers broadcast their game list
- Only on changes, not on a timer.
- Use a short debounce (1-2 seconds) to coalesce bursts of filesystem events.
- Send
LibraryDeltato known peers; sendLibrarySummaryon new connections.
Local game scanning: fast and low cost
Strategy
- Maintain a persistent on-disk index (per game):
manifest_hash, total size, file list (optional), and a fingerprint (version.ini mtime, .eti mtime/size, local install dir presence).
- Use filesystem watchers to update only changed games.
- Keep a fallback periodic scan with a long interval (minutes) to recover from missed events.
Fast-path scanning
- On startup, list only top-level game directories.
- For each game, read a cheap fingerprint:
.etisize + mtimeversion.inimtime (if installed)- presence of
local/content
- If fingerprint unchanged, reuse cached size and manifest hash.
- Only run a recursive scan for new or changed games.
Result
Most scans become O(number of game dirs), with full recursion only when needed.
File manifests and downloads
- Keep
GetGame/manifest requests, but keyed bymanifest_hashso repeated calls can be skipped when unchanged. - Downloads remain chunked QUIC streams with the existing integrity checks.
Fault tolerance rules
- Every peer is keyed by
peer_id, not by IP address. library_revis monotonic and guards against out-of-order updates.- Any mismatch or missing delta falls back to
LibrarySnapshot. - Loss of goodbye is harmless; stale timeout is authoritative.
TODO: roadmap from current design to this one
- Protocol updates in
lanspread-proto:- Add
Hello,HelloAck,LibrarySummary,LibrarySnapshot,LibraryDelta, and optionalGoodbye. - Add
peer_id,library_rev, andmanifest_hashto relevant types.
- Add
- Peer identity:
- Introduce stable
peer_idinPeerInfoandPeerGameDB. - Map
peer_idto currentSocketAddrand update on IP changes.
- Introduce stable
- Discovery handshake:
- Advertise TXT records in mDNS.
- Add handshake in
run_peer_discoveryor connection setup. - Keep compatibility fallback to
ListGamesfor older peers.
- Library revisioning:
- Track
library_revlocally. - Apply
LibraryDeltaand reject stale revisions. - Use
LibrarySnapshotfor first sync or delta mismatch.
- Track
- Local index + scan optimizations:
- Add cached index storage (e.g.,
.lanspread/index.json). - Implement filesystem watchers with debounce.
- Add a low-frequency full scan as a safety net.
- Add cached index storage (e.g.,
- Announce updates:
- Replace broad
AnnounceGameswith deltas. - Send
LibrarySummaryon new connections.
- Replace broad
- File manifest caching:
- Store per-game
manifest_hashand only fetch details when changed.
- Store per-game
- Liveness:
- Reduce ping frequency; update
last_seenon any message. - Add optional
Goodbyeon shutdown paths.
- Reduce ping frequency; update
- Tests:
- Delta apply/merge, rev ordering, manifest hashing, and scan cache behavior.