Add small Justfile entry points for generating the complete production catalog authority or safely regenerating one game. Keep fixture validation separate and allow operators to select a trusted unrar executable. Document the complete package layout, BLAKE3 and ContentId model, full/incremental publication procedure, verification and bundle gates, and peer-CLI workflows. Record the fresh final local acceptance run without presenting Docker throughput as physical-LAN evidence. Test Plan: - just fixture-catalogs-check - just test - just clippy - just frontend-test - just build - LANSPREAD_S37_MIN_MIB_PER_S=100 just peer-cli-tests - just catalog-check-production (expected fail-closed: production manifests absent) - deno fmt --check README.md organize/testing/PEER_CLI_SCENARIOS.md - rumdl check --flavor commonmark README.md organize/testing/PEER_CLI_SCENARIOS.md - just --fmt --check - git diff --check
220 lines
8.9 KiB
Markdown
220 lines
8.9 KiB
Markdown
# lanspread
|
|
|
|
Peer-to-peer game library sharing for LAN parties. Peers discover each other on
|
|
the local network via mDNS, exchange library metadata over QUIC, and let users
|
|
browse and download games from each other. Ships as a Tauri desktop app.
|
|
|
|
## Peer identity and protocol status
|
|
|
|
Each desktop installation creates and reuses one Ed25519 identity in its Tauri
|
|
app-data directory. Its `PeerId` is lowercase unpadded RFC 4648 base32 of BLAKE3
|
|
over the certificate's complete canonical DER SubjectPublicKeyInfo; certificates
|
|
and private keys are never distributed from the repository. Outbound QUIC
|
|
connections authenticate the responder against the exact expected `PeerId`. Wire
|
|
protocol 8 (`lanspread/8`) is the only supported protocol. Peers exchange
|
|
responder-owned, revisioned snapshots over identity-pinned endpoints; file and
|
|
streamed-install requests name the catalog's exact `ContentId`. There are no
|
|
legacy wire fallbacks or repository-shared identity keys.
|
|
|
|
## First-time setup
|
|
|
|
Install Rust, Deno, and `just` first, then bootstrap the project:
|
|
|
|
```bash
|
|
just setup
|
|
```
|
|
|
|
That installs the Tauri CLI and the locked frontend dependencies. All routine
|
|
repository work should go through `just`; the recipes carry the catalog mode and
|
|
Tauri resource configuration needed to keep fixture authority out of production
|
|
builds.
|
|
|
|
## Daily development
|
|
|
|
Run the desktop app with the checked-in development catalog:
|
|
|
|
```bash
|
|
just run
|
|
```
|
|
|
|
Build without bundling:
|
|
|
|
```bash
|
|
just build
|
|
```
|
|
|
|
Run the standard checks before committing:
|
|
|
|
```bash
|
|
just fmt
|
|
just clippy
|
|
just test
|
|
just frontend-test
|
|
```
|
|
|
|
`just run` and `just build` first check the default development catalog. The
|
|
workspace Rust commands explicitly opt into that exact fixture resource map so
|
|
Tauri's build script does not mistake test data for production authority.
|
|
|
|
## Catalog checksums and production manifests
|
|
|
|
Lanspread does not trust file descriptions received from peers. The release
|
|
catalog contains the expected bytes for each game version. The catalog publisher
|
|
derives that authority from the canonical game packages and writes:
|
|
|
|
- one `<game_id>.json` manifest containing every ordinary file's size, full-file
|
|
BLAKE3, and BLAKE3 for each 128 MiB transfer chunk;
|
|
- BLAKE3 and size for every file obtained by extracting the root-level `.eti`
|
|
archives, which authorizes Stream Install output; and
|
|
- `catalog-content-index-v1.jsonl`, which binds every catalog game/version to
|
|
its complete manifest `ContentId` and Stream Install capability.
|
|
|
|
The `ContentId` is a digest of the canonical manifest transcript, not merely a
|
|
hash of one archive. Never calculate or edit these values by hand.
|
|
|
|
### Prepare the package tree
|
|
|
|
Place the canonical packages under one directory, with each direct child named
|
|
exactly like the `game_id` in the production `game.db`:
|
|
|
|
```text
|
|
/srv/lanspread/packages/
|
|
├── alienswarm/
|
|
│ ├── version.ini
|
|
│ ├── alienswarm.eti
|
|
│ └── ...
|
|
├── bf1942/
|
|
│ ├── version.ini
|
|
│ ├── bf1942.eti
|
|
│ └── ...
|
|
└── ...
|
|
```
|
|
|
|
Each `version.ini` must match that game's `game_version` in `game.db`. Package
|
|
entries must be regular files/directories with canonical portable names; links,
|
|
reparse points, special files, aliases, unsafe archive output, or changing bytes
|
|
make generation fail closed.
|
|
|
|
The default publisher uses the checked-in Linux `unrar` sidecar. Select another
|
|
trusted executable when generating on a different supported host:
|
|
|
|
```bash
|
|
LANSPREAD_UNRAR=/absolute/path/to/unrar \
|
|
just catalog-generate-production /srv/lanspread/packages
|
|
```
|
|
|
|
### Generate and verify all checksums
|
|
|
|
Generate the complete production manifest set:
|
|
|
|
```bash
|
|
just catalog-generate-production /srv/lanspread/packages
|
|
```
|
|
|
|
The publisher independently reads and hashes each selected package twice before
|
|
publication. Under a durable publication marker, it atomically replaces each
|
|
manifest and writes the complete content index last. Interruption leaves the
|
|
marker in place so later checks and builds fail closed instead of accepting a
|
|
mixed generation.
|
|
|
|
Verify the published database/index/manifest set without rereading the package
|
|
corpus:
|
|
|
|
```bash
|
|
just catalog-check-production
|
|
```
|
|
|
|
This is a packaging integrity check, not a substitute for retaining the
|
|
canonical packages and the successful generation log as provenance. The output
|
|
prints the `game_id`, `game_version`, and `content_id` for every checked game.
|
|
|
|
### Regenerate one changed game
|
|
|
|
After a complete manifest set exists, update one game without rehashing every
|
|
package:
|
|
|
|
```bash
|
|
just catalog-generate-production-game /srv/lanspread/packages alienswarm
|
|
just catalog-check-production
|
|
```
|
|
|
|
Incremental generation refuses to bootstrap a partial catalog. Under its durable
|
|
publication marker it revalidates every unselected manifest/index identity,
|
|
rebuilds the complete index, and then publishes the selected game. Use the full
|
|
generation command for a new catalog or any intentionally broad catalog change.
|
|
|
|
### Build a production bundle
|
|
|
|
Only after the production check succeeds, create the installer/bundle:
|
|
|
|
```bash
|
|
just bundle
|
|
```
|
|
|
|
`just bundle` repeats the production catalog gate before Tauri packaging. It
|
|
never falls back to fixture manifests. This checkout does not include the
|
|
canonical 186-game package corpus, so the command intentionally fails until that
|
|
external corpus has been processed into
|
|
`crates/lanspread-tauri-deno-ts/src-tauri/manifests/`.
|
|
|
|
## Fixture catalogs and peer-CLI acceptance
|
|
|
|
The committed fixture profiles are test authority only:
|
|
|
|
```bash
|
|
just fixture-catalog-check # default GUI/CLI profile
|
|
just fixture-catalogs-check # default + solid + multi + unknown profiles
|
|
just fixture-catalogs # explicitly regenerate all committed profiles
|
|
```
|
|
|
|
The solid, multi-archive, and unknown-game profiles intentionally describe
|
|
different package bytes, so the peer-CLI matrix checks all of them before
|
|
building its Docker image. Normal GUI development needs only the default
|
|
profile.
|
|
|
|
Build or run the JSONL peer harness:
|
|
|
|
```bash
|
|
just peer-cli-build
|
|
just peer-cli-image
|
|
just peer-cli-tests S1 S2 S3
|
|
just peer-cli-run alpha
|
|
```
|
|
|
|
Run the entire S1-S49 acceptance matrix by omitting scenario arguments:
|
|
|
|
```bash
|
|
just peer-cli-tests
|
|
```
|
|
|
|
For an interactive three-peer session, start these in separate terminals:
|
|
|
|
```bash
|
|
just peer-cli-alpha
|
|
just peer-cli-bravo
|
|
just peer-cli-charlie
|
|
```
|
|
|
|
## Important just commands
|
|
|
|
| Command | Purpose |
|
|
| --------------------------------------------------- | ------------------------------------------------------------------------ |
|
|
| `just setup` | Install the Tauri CLI and frontend dependencies. |
|
|
| `just run` | Check the default fixture catalog and run the GUI. |
|
|
| `just build` | Check the default fixture catalog and build without bundling. |
|
|
| `just bundle` | Check production authority and build production bundles. |
|
|
| `just catalog-generate-production PACKAGES_DIR` | Hash and publish the complete production package corpus. |
|
|
| `just catalog-generate-production-game DIR GAME_ID` | Safely regenerate one game in an already complete catalog. |
|
|
| `just catalog-check-production` | Validate all production database/index/manifest artifacts. |
|
|
| `just fixture-catalog-check` | Validate the default development fixture catalog. |
|
|
| `just fixture-catalogs-check` | Validate every peer-CLI fixture profile. |
|
|
| `just fixture-catalogs` | Regenerate all committed fixture profiles from their packages. |
|
|
| `just fmt` | Format Rust, TOML, Markdown, and the Justfile. |
|
|
| `just clippy` | Lint every Rust workspace target with warnings denied. |
|
|
| `just test` | Run every Rust workspace test target. |
|
|
| `just frontend-test` | Run the frontend reducer/lifecycle tests. |
|
|
| `just peer-cli-build` | Build the JSONL peer harness. |
|
|
| `just peer-cli-image` | Check fixture authority and build the harness Docker image. |
|
|
| `just peer-cli-tests [SCENARIO ...]` | Run selected scenarios, or the complete matrix when no IDs are supplied. |
|
|
| `just peer-cli-run NAME` | Start one persistent-state interactive harness peer. |
|