0e970dcec7
NEXT_STEPS item 3 needed solid archive handling to be a deliberate contract instead of an incidental RAR header attribute. Add a tiny real solid RAR fixture and S41 to the extended peer-cli scenarios so the Docker harness proves this path end to end. The scenario verifies the source archive with container-bundled `unrar lt`, streams the install with the injected provider, and then asserts the receiver is installed local-only without a root archive or root `version.ini`. It also compares local payload SHA-256 hashes against `unrar p` output and checks the streamed byte count matches the extracted entries. This keeps the existing one metadata pass plus one sequential payload pass contract covered for solid archives. Test Plan: - just fmt - just test - python3 -m py_compile crates/lanspread-peer-cli/scripts/run_extended_scenarios.py - python3 crates/lanspread-peer-cli/scripts/run_extended_scenarios.py S41 --build-image - python3 crates/lanspread-peer-cli/scripts/run_extended_scenarios.py S41 - git diff --check - git diff --cached --check Refs: NEXT_STEPS.md item 3
66 lines
2.8 KiB
Markdown
66 lines
2.8 KiB
Markdown
# 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.
|
||
|
||
1. **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 external `unrar` stream provider,
|
||
and hands fetched file details to `StreamInstallGame` instead of the normal
|
||
download command.
|
||
|
||
2. **Done — Replace per-file `unrar p` with a final archive provider**
|
||
|
||
The shared external `unrar` stream provider now runs `unrar lt` once for the
|
||
archive metadata and one sequential `unrar p` pass 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.
|
||
|
||
3. **Done — Handle solid archives deliberately**
|
||
|
||
The provider exposes the RAR `solid` flag in `ArchiveBegin` and 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.
|
||
|
||
4. **Decide the integrity model**
|
||
|
||
Current prototype verifies streamed bytes against RAR CRC32 from the
|
||
sender’s 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 there’s a strong reason
|
||
|
||
6. **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 `.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.
|