ddidderr d376983296 fix: terminate unrar sidecars when the launcher closes mid-install
Bug report: unrar.exe kept running after closing the launcher during a
game install. The orphaned process kept extracting in the background and
held file handles on the staging directory.

Root cause (regular install path): run_unrar_sidecar ran the unrar
sidecar via tauri-plugin-shell's Command::output(). That helper spawns
the process on a detached SharedChild OS thread and immediately drops the
CommandChild; there is no Drop impl that kills the process. On app exit
only shutdown_peer_runtime ran, and Windows does not cascade-kill child
processes, so closing the launcher left unrar running.

Fix:
- run_unrar_sidecar now uses .spawn() instead of .output(), keeping a
  killable CommandChild. It registers the child in a new
  LanSpreadState.active_unrar_children registry and an RAII
  UnrarChildGuard deregisters it on every return path. The CommandEvent
  stream is drained to reproduce the exact stdout/stderr (NEWLINE_BYTE
  is b'\n'), status code, success flag, and UnpackLogEntry the old
  .output() produced, so logging behavior is unchanged.
- kill_active_unrar_children() runs in the RunEvent::Exit handler before
  shutdown_peer_runtime, killing every in-progress unrar. Killing first
  also lets the install task unwind so the runtime stops promptly.

Two concurrency hazards were closed in the registry design:
- Children are keyed by a monotonic id, not pid. A pid key let a
  finishing install's guard deregister a different install's child after
  the OS recycled the pid, which could re-orphan a live child.
- A shutting_down latch lives in the registry under the same mutex as
  the kill sweep. The sweep is a one-shot drain, so a child registered
  after it (a task caught between spawn() and registration, or a later
  archive in a multi-archive install -- unpack_archives does not observe
  the shutdown token) would be missed. Registration now checks the latch
  under that mutex and kills the child immediately instead of inserting
  it. Since registration and the sweep serialize on one mutex, every
  interleaving kills the child.

Also hardened the streamed-install sender path (ExternalUnrarStream
Provider) with kill_on_drop(true) on its tokio unrar spawns, so a
dropped or aborted producer task cannot orphan unrar there either.

Known limitation: a hard force-kill or crash of the launcher (e.g. Task
Manager -> End Task) bypasses RunEvent::Exit and is not covered. Making
that bulletproof would require a Windows Job Object with
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; the reported "close the launcher"
case is fully fixed.

Test Plan:
- just clippy (pedantic, -D warnings): clean.
- just fmt: no changes.
- just test: all suites pass (incl. the 20 Tauri-lib unit tests).
- Manual (Windows): start a game install, close the launcher mid-extract,
  confirm no unrar.exe remains in Task Manager. Repeat with two
  concurrent installs and with a multi-archive game.
2026-06-22 07:07:45 +02:00
2026-06-21 21:15:09 +02:00
2026-06-20 20:32:40 +02:00
2026-06-20 12:01:59 +02:00
2026-05-18 16:19:27 +02:00
2026-05-18 16:19:27 +02:00

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.

Build / install

Install Rust, Deno, and just first, then bootstrap the project:

just setup

That installs the Tauri CLI with cargo install tauri-cli and installs the Deno/npm dependencies from crates/lanspread-tauri-deno-ts.

Run the desktop app in development mode:

just run

Build without bundling:

just build

Create production bundles:

just bundle

Important just commands

  • just setup - install the Tauri CLI and frontend dependencies.
  • just run - run the Tauri app in dev mode.
  • just build - build the app without bundling.
  • just bundle - create production bundles.
  • just fmt - format Rust, TOML, and the justfile.
  • just clippy - lint the Rust workspace.
  • just test - run workspace tests.
  • just frontend-test - run frontend tests.
  • just peer-cli-build - build the JSONL peer test harness.
  • just peer-cli-image - build the peer harness Docker image.
  • just peer-cli-run NAME - run one peer harness container.
S
Description
No description provided
Readme 154 MiB
Languages
Rust 58.1%
TypeScript 12.5%
JavaScript 11.8%
Python 9%
CSS 6.8%
Other 1.7%