Files
lanspread/NEXT_STEPS.md
T
ddidderr 373def6d44 feat(peer): prototype streamed installs
Add a streamed-install prototype that can receive archive-derived install bytes
straight into local/ without first storing the peer-owned root archive payload.
This is intended for low-disk clients that want to install a game but opt out of
becoming a downloadable peer source for that game.

The protocol gains a current-version-only StreamInstall request and framed
StreamInstallFrame responses. The peer core owns the generic transport,
transaction, path validation, size checks, CRC32 verification, and lifecycle
state. The archive-specific work is hidden behind StreamInstallProvider so the
prototype can use unrar while the final implementation can swap in a better
provider without rewriting the peer command path.

The receiver writes into .local.installing and only promotes to local/ after the
full stream verifies. It deliberately does not write the root version.ini or
archive files, so the settled local state is installed=true, downloaded=false,
and availability=LocalOnly. That preserves the existing rule that local/ is not
served to peers and makes streamed receivers non-sources by construction.

The CLI is the only caller for now. It exposes stream-install and provides the
prototype unrar implementation with unrar lt for entry metadata and unrar p for
file bytes. This is simple and good enough to prove non-solid archive streaming,
but it is not the production provider shape for solid archives because per-file
unrar p would repeatedly decompress prefixes. The Tauri app explicitly passes
stream_install_provider: None, so the GUI behavior stays unchanged until a real
product path is designed.

Document the production-readiness work in NEXT_STEPS.md. The main follow-up is
to make the provider abstraction final-ish and replace the per-file CLI unrar
provider with a one-pass archive provider, then wire a deliberate GUI low-disk
mode, retry semantics, and broader failure scenarios.

Test Plan:
- just fmt
- RUSTC_WRAPPER= CARGO_BUILD_RUSTC_WRAPPER= just test
- python3 crates/lanspread-peer-cli/scripts/run_extended_scenarios.py \
  S39 S40 --build-image
- RUSTC_WRAPPER= CARGO_BUILD_RUSTC_WRAPPER= just clippy
- git diff --check
- git diff --cached --check

Follow-up: NEXT_STEPS.md
2026-06-07 20:32:05 +02:00

2.4 KiB
Raw Blame History

Streamed Install Next Steps

Id treat the prototype as proof of the hard part: “can we stream archive-derived install bytes into local/ without making the receiver a source?” Yes. Next Id harden the pieces that decide whether this is product-ready.

  1. Move from CLI-only to real app integration

    Add a GUI command/control path for “stream install / low disk mode”, probably behind an explicit option. The Tauri crate currently opts out with stream_install_provider: None, so the GUI cannot use it yet.

  2. Replace per-file unrar p with a final archive provider

    The prototype provider is intentionally simple: unrar lt, then unrar p per file. Good for non-solid archives, bad for solid archives. Final shape should be a one-pass provider with real entry boundaries, likely via libunrar or a purpose-built wrapper.

  3. Handle solid archives deliberately

    Add archive inspection that decides:

    • non-solid: per-file streaming is fine
    • solid: one sequential archive pass only

    This is the big architectural fork we discussed, and the prototypes provider is the thing to swap.

  4. Decide the integrity model

    Current prototype verifies streamed bytes against RAR CRC32 from the senders archive headers. That catches corruption and provider bugs. It does not protect against a malicious peer lying. If you care about that, the next step is catalog-side trusted hashes for archive or extracted files.

  5. Upgrade retry/resume semantics

    Right now, failed stream means failed operation and rollback. Next useful step:

    • retry whole stream from another trusted peer
    • later, maybe keep completed files and restart only the interrupted file
    • avoid byte-offset resume until theres a strong reason
  6. Expand scenario coverage

    Id add cases for:

    • sender disconnect mid-stream
    • receiver cancel mid-stream
    • corrupted/truncated stream fails and leaves no local/
    • already-installed game rejects streamed install
    • multi-archive .eti roots stream in sorted order
  7. Clean product semantics

    Decide how the UI labels this state. It is installed but not downloaded, so “Local only” is technically correct, but users may need a clear affordance like “Installed, not shareable”.

My recommended next slice: make the provider abstraction final-ish, then implement a real one-pass provider. Everything else builds cleanly on that.