Clarify that `just build` is the production no-bundle launcher build, while fixture builds are explicit. Document package-directory generation, the `LANSPREAD_GAMES_DIR` and `--set GAMES_DIR` default-run forms, the metadata cache behavior, and the force-refresh override so the catalogue workflow is usable without consulting the recipe implementation. Test Plan: - `prettier --check --prose-wrap always --print-width 80 README.md CLAUDE.md` -- passed - `just --fmt --check` -- passed - `git diff --cached --check` -- passed
262 lines
11 KiB
Markdown
262 lines
11 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 test catalog:
|
|
|
|
```bash
|
|
just run
|
|
```
|
|
|
|
Build a launcher from the already-published production catalog without creating
|
|
an installer:
|
|
|
|
```bash
|
|
just build
|
|
```
|
|
|
|
Generate the production catalog from a package tree when necessary, then build
|
|
the same no-bundle launcher:
|
|
|
|
```bash
|
|
just build-production /srv/lanspread/packages
|
|
```
|
|
|
|
To make the default `just` command use a real package tree, set the directory
|
|
before invoking it. The command generates or reuses the production catalog and
|
|
then runs the launcher with the production resource map:
|
|
|
|
```bash
|
|
LANSPREAD_GAMES_DIR=/srv/lanspread/packages just
|
|
# Equivalent Just-variable form:
|
|
just --set GAMES_DIR /srv/lanspread/packages
|
|
```
|
|
|
|
The fixture-only paths remain explicit:
|
|
|
|
```bash
|
|
just run-fixture
|
|
just build-fixture
|
|
```
|
|
|
|
Run the standard checks before committing:
|
|
|
|
```bash
|
|
just fmt
|
|
just clippy
|
|
just test
|
|
just frontend-test
|
|
```
|
|
|
|
`just run` uses the fixture path only when `LANSPREAD_GAMES_DIR` is unset.
|
|
`just build` always uses the production resource map and production profile; use
|
|
`just build-fixture` when a fixture build is intended. Tauri's build script
|
|
still rejects fixture resources unless the explicit fixture opt-in is present.
|
|
|
|
## 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 `--all` recipe keeps a local metadata-only stamp in
|
|
`.lanspread/catalog-cache/production.json`. It compares the package tree's
|
|
paths, entry types, sizes, and nanosecond mtimes, plus the catalog database and
|
|
`unrar` metadata. If those values and the published output still match, the
|
|
expensive package hashing and extraction step is skipped. This is only a
|
|
performance cache: `catalog-check-production` and every production build still
|
|
validate the catalog authority. Force a refresh when needed:
|
|
|
|
```bash
|
|
LANSPREAD_CATALOG_FORCE=1 just catalog-generate-production /srv/lanspread/packages
|
|
```
|
|
|
|
The publisher first checks every selected package's `version.ini` against
|
|
`game.db`, then 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` / `just run` | Run fixtures, or real data when `LANSPREAD_GAMES_DIR` is set. |
|
|
| `just run-fixture` | Check the default fixture catalog and run the GUI. |
|
|
| `just build` | Validate production authority and build without bundling. |
|
|
| `just build-production PACKAGES_DIR` | Generate/reuse production authority and build without bundling. |
|
|
| `just build-fixture` | 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, cache, 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. |
|