NEXT_STEPS item 5 needs streamed installs to have an explicit retry policy. The handler already retries whole-stream attempts across the majority-validated peer set, so add S42 to prove that behavior with the Docker harness instead of leaving it implicit. S42 starts two catalog-version-matching `cnctw` sources. The first source sorts first in retry order but has `--unrar /missing-unrar`, so its stream attempt fails before sending chunks. The second source then completes a fresh whole-stream attempt. The scenario asserts local-only installed state, no root archive or sentinel, no `.local.installing` staging leftover, chunk events only from the good source, matching streamed byte count, and SHA-256 payload equality against the good source's `unrar p`. This pins the current policy: retry the entire stream from another validated peer, do not preserve partial files across attempts, and do not promise byte-offset resume. Test Plan: - python3 -m py_compile crates/lanspread-peer-cli/scripts/run_extended_scenarios.py - python3 crates/lanspread-peer-cli/scripts/run_extended_scenarios.py S42 - git diff --check - git diff --cached --check Refs: NEXT_STEPS.md item 5
3.0 KiB
Streamed Install Next Steps
I’d 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 I’d harden the pieces that decide whether this is
product-ready.
-
Done — Move from CLI-only to real app integration
The GUI now has an explicit “Low disk install” action in the game detail modal for remote-only games. The Tauri backend queues that path through
stream_install_game, injects the shared externalunrarstream provider, and hands fetched file details toStreamInstallGameinstead of the normal download command. -
Done — Replace per-file
unrar pwith a final archive providerThe shared external
unrarstream provider now runsunrar ltonce for the archive metadata and one sequentialunrar ppass per archive for payload bytes. It frames directories, file starts, file chunks, and file ends from the technical listing, so CLI and GUI callers use one purpose-built provider instead of a per-file extraction loop. -
Done — Handle solid archives deliberately
The provider exposes the RAR
solidflag inArchiveBeginand always uses one sequential payload pass per archive, which is the safe path for solid archives. S41 now verifies a real solid RAR fixture through the Docker peer-cli flow, including local-only final state, absent root archive/sentinel, byte count, and extracted payload SHA-256 hashes. -
Done — Decide the integrity model
Streamed installs intentionally verify against sender archive metadata for now: each file must match the RAR-advertised size and CRC32. That catches transport corruption, truncation, and provider bugs, but does not claim malicious-peer protection. Trusted content remains a separate catalog schema step: add catalog-owned archive or extracted-file SHA-256 hashes, then verify those at the receiver before commit.
-
Done — Upgrade retry/resume semantics
Streamed install attempts now use the same majority-validated peer set as normal downloads, and each failed attempt rolls back its staging transaction before trying the next peer. S42 pins the policy: retry the whole stream from another validated peer, keep no partial files across attempts, and do not add byte-offset resume until there is a strong reason.
-
Expand scenario coverage
I’d 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
.etiroots stream in sorted order
-
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.