Commit Graph
374 Commits
Author SHA1 Message Date
ddidderr e0eafa6e33 docs(peer): document authenticated sharing architecture
Update user and developer documentation for the protocol-8 system: persistent
SPKI-derived identities, exact catalog ContentId authority, pinned responder
pulls, structured runtime ownership, direct-author Call to Play, and the global
local-network sharing switch.

Remove active descriptions of repository-wide certificates, pushed deltas,
relayed histories, and metadata consensus. Keep operational and UI boundaries
aligned with the implementation, including the fail-closed production catalog
gate.

Test Plan:
- `just fmt` (passed)
- `git diff --cached --check` (passed)
2026-08-10 14:05:00 +02:00
ddidderr 4a1b08db98 test(peer-cli): verify protocol 8 transfer lifecycle
Replace legacy metadata and relay expectations with current protocol-8 JSONL
assertions. Scenarios now bind every source to authenticated PeerId and exact
ContentId, prove typed attempt lifecycle order, and fence cancellation,
quarantine, rollback, republishing, and peer-departure outcomes against vacuous
success.

Isolated topologies distinguish direct author pulls from relay and ambient mDNS
substitution. The run log records focused diagnostics and the final fresh-image
S1-S49 acceptance result without presenting Docker-host throughput as a
representative external-LAN measurement.

Test Plan:
- `LANSPREAD_S37_MIN_MIB_PER_S=100 just peer-cli-tests` -- passed S1-S49
- S37 -- passed 2,147,483,656 bytes in 17 chunks at 551.10 MiB/s
- `python3 -m py_compile crates/lanspread-peer-cli/scripts/run_extended_scenarios.py` -- passed
- `ruff check --select F,E9 crates/lanspread-peer-cli/scripts/run_extended_scenarios.py` -- passed
- `git diff --cached --check` -- passed
2026-08-10 14:00:03 +02:00
ddidderr 71dbf27d8b feat(app): expose local sharing and verified transfers
Add a durable, acknowledged Local network sharing switch with fail-closed
hydration, serialized mutation, and redacted ephemeral-identity diagnostics.
Keep local Call-to-Play state available while gating every network action on the
effective sharing generation.

Render revisioned verification, invalid-source retry, and sticky source
exhaustion states. Preserve opaque attempt IDs through progress delivery so
out-of-order webview events cannot attach stale bytes to a successor transfer,
and keep terminal exhaustion visible after the last source departs.

Own listeners, native invokes, persistence, dialogs, and companion-window
creation through webview close. Late creation is settled and cleaned before the
parent realm is destroyed.

Test Plan:
- `just frontend-test` -- passed (91/91)
- `just build` -- passed with TypeScript, Vite, and release Tauri compilation
- `just test` -- passed on the completed stack (708 workspace tests)
- `just clippy` -- passed on the completed stack
- `git diff --cached --check` -- passed
2026-08-10 13:59:40 +02:00
ddidderr 60fd7ba0c2 feat(peer)!: cut over to authenticated catalog sharing
Replace address-only trust and pushed peer state with installation identities,
SPKI-pinned QUIC, candidate-only discovery, and bounded responder-owned
protocol-8 pulls. The runtime now owns each network generation and all admitted
work through shutdown.

Add exact bundled content identities, reproducible manifest publishing,
capability-confined downloads, streaming BLAKE3 verification, quarantine and
retry, and crash-recoverable download and install transactions. Ship generated
fixture catalogs and fail closed when production manifests are absent.

The Tauri backend exposes durable sharing policy, redacted identity state, and
attempt-keyed transfer snapshots. Frontend consumption follows in the next
commit. Repository-wide test certificates and protocol-7 paths are removed.

BREAKING CHANGE: peers must use protocol 8 and exact catalog content artifacts;
protocol-7 frames and shared-certificate identities are no longer accepted.

Test Plan:
- `just test` -- passed on the completed stack (708 workspace tests)
- `just clippy` -- passed on the completed stack
- `just build` -- passed with fixture catalogs on the completed stack
- `just catalog-check-production` -- failed closed because the external
  production manifest corpus is absent
- `git diff --cached --check` -- passed
2026-08-10 13:59:18 +02:00
ddidderr 36c4785775 fix(peer): preserve manifest entry shape consensus
Treat directory/file shape as part of each peer manifest vote and reject
portable aliases before aggregating descriptors. This keeps majority selection
deterministic and avoids collapsing conflicting entries that share a path or
size.

This preserves the previously staged consensus hardening before the protocol-8
catalog-authority cutover layered in the working tree.

Test Plan:
- `git diff --cached --check` -- passed
2026-08-10 13:58:37 +02:00
ddidderr 290af433c7 fix(peer): make streamed egress cancellation-safe
Treat cancellation as part of the Stream Install transport contract. Frame
production and QUIC egress now run as structured futures, cancellation wins at
queued sends, blocked writes, and close, and exceptional exits reset the send
stream before producer cleanup completes.

Make the unrar listing subprocess cancellation-aware and explicitly kill and
reap it on cancellation or pipe-capture failure. This ensures outbound transfer
tracking is cleared only after provider work is quiescent, which is required by
game-root mutation and directory-switch draining.

Test Plan:
- `just clippy` -- passed
- `just test` -- passed (242 lanspread-peer tests)
- `just peer-cli-build` -- passed
- `git diff --cached --check` -- passed
2026-08-09 22:01:34 +02:00
ddidderr bcdede7fad fix(peer): reject non-normalized download paths
Require catalog game IDs and every remotely described path component to use
Unicode NFC before any download transaction begins. This prevents canonically
equivalent spellings from bypassing portable alias checks on filesystems that
normalize names, while preserving the protocol's exact path spelling.

Cover accepted NFC names and both game-ID and nested-component rejection with
zero-mutation tree snapshots.

Test Plan:
- `just clippy` -- passed
- `just test` -- passed (242 lanspread-peer tests)
- `git diff --cached --check` -- passed
2026-08-09 22:01:00 +02:00
ddidderr 5bb4a8b611 fix(peer): drain cancelled download workers
Keep initial peer transfers, retry attempts, and chunk receivers structurally owned until they quiesce. Cancellation now stops opening new streams, flushes accepted file writes, and drains active work before ownership rollback can begin.

Leave operation admission owned by the running download task when liveness detects that every source disappeared, and emit the peers-gone notification only once.

Test Plan:
- just fmt (Rust and configured formatters completed; 39 pre-existing rumdl findings remain)
- just clippy
- just test
- git diff --cached --check
2026-08-09 20:05:42 +02:00
ddidderr 7a77d3ffd1 fix(peer): reject aliased ownership generations
Validate portable aliases across committed and pending ownership sets when loading persisted records. Malformed state can no longer make recovery delete the pending file through an older case-only spelling.

Test Plan:
- just clippy
- just test
- just fmt (Rust, TOML, and Prettier completed; rumdl still reports 39 pre-existing issues)
2026-08-09 19:48:21 +02:00
ddidderr 08b1cb5c1d fix(peer): preserve untracked download files
Reject exact manifest destinations that are not covered by the last committed ownership set before creating a baseline or parking version.ini. Align Windows device-name validation with the confined filesystem backend and keep cleanup capability-relative.

Replace recursive downloaded-game removal with an empty ownership generation. The operation now removes only proven-owned files and the sentinel, preserves unknown files and directories, and remains recoverable and idempotent across crashes.

Test Plan:
- just clippy
- just test
- just fmt (Rust, TOML, and Prettier completed; rumdl still reports 39 pre-existing issues)
2026-08-09 19:46:10 +02:00
ddidderr 691176e1d5 fix(peer): confine download mutations to game root handles
Remote manifests were validated before mutation, but preparation, chunk writes,
sentinel transactions, and ownership recovery later reopened ambient paths. A
link or reparse-point swap between those steps could redirect a mutation outside
the validated game root.

Introduce a retained ConfinedGameRoot capability backed by cap-primitives. Carry
typed validated destinations into chunk plans, walk every component without
following links, and perform payload, sentinel, stale-file, abort, and recovery
mutations relative to the retained handle. File writes and verification use the
same opened handle, while final durability syncs payload files and unique parent
directories before committing version.ini.

Make ownership-record publication phase-aware as well. A directory-sync failure
after record rename now stops before payload mutation without performing an
unsafe old-sentinel rollback. Record the capability-root, bounded-handle,
hard-link, and unproven Windows durability tradeoffs in the decision log.

Test Plan:
- `just clippy` -- passed
- `just test` -- passed; 185 peer tests and the full workspace are green
- `just fmt` -- Rust, TOML, and Prettier completed; command remains nonzero on
  39 pre-existing rumdl issues outside this change
- `git diff --cached --check` -- passed
2026-08-09 19:22:11 +02:00
ddidderr 62cd9306bd feat(peer): journal download file ownership
Track the exact regular files owned by each completed and in-flight peer
download instead of sweeping every non-reserved path after cancellation. Bind
the record to the canonical games directory, publish pending ownership before
payload mutation, and use the final version.ini rename as the recovery commit
point.

Make replacement, cancellation, and startup recovery preserve unknown files
and install state while removing stale or partial downloader-owned bytes. Add a
new-format baseline so legacy discarded sentinels cannot make partially
modified payloads ready, sync payload and journal state in transaction order,
and serialize startup recovery against operation admission.

Document ambiguous legacy target adoption, portable alias transitions, and the
other ownership tradeoffs in the refactor decision log.

Test Plan:
- `just clippy` -- passed
- `just test` -- passed (182 peer-core tests plus the full workspace)
- `just fmt` -- Rust, TOML, and Prettier formatting completed; the command then
  stopped on 40 pre-existing rumdl findings in unrelated Markdown content
- `git diff --cached --check` -- passed
2026-08-09 18:44:40 +02:00
ddidderr a1013b028d refactor(peer): centralize game root path policy
Game scanning, manifest validation, install recovery, migration, and download
cleanup each carried their own spellings and case rules for reserved entries.
Those copies had already diverged, which made it possible for one subsystem to
accept or expose a path that another treated as application-owned state.

Introduce one game_paths module for the canonical names and conservative
portable comparison policy. Keep context-specific predicates for manifest and
scanner protection versus cancellation preservation: cancellation still sweeps
its own version transaction scratch files, while install and migration state
survive. Reuse the constants for all production path construction sites.

Test Plan:
- `just test` -- passed (175 lanspread-peer tests and full workspace)
- `just clippy` -- passed
- `just fmt` -- Rust, TOML, and Prettier completed; the recipe remains blocked
  by 39 pre-existing rumdl issues in five unrelated Markdown files
- `git diff --cached --check` -- passed
2026-08-09 17:59:01 +02:00
ddidderr a6ed60a538 feat(peer): validate manifests before download mutation
Why:
- Remote and UI-echoed file descriptions could reach transaction and storage
  code one entry at a time, so a hostile late path could mutate earlier files.
- Per-file consensus also accepted malformed peer lists and let duplicate rows
  inflate a source's vote.

What:
- Add a complete protocol-7 manifest adapter with catalog-root confinement,
  portable path and alias rules, reserved-path protection, shape and size caps,
  symlink/reparse inspection, and zero-mutation tests.
- Keep download selection in the peer core, validate every peer manifest before
  consensus, and pass only the validated manifest into storage/orchestration.
- Canonicalize locally advertised paths, cap exact chunk receives, and preserve
  the local-only install fast path.
- Record the chosen safety limits and follow-up ownership/catalog decisions.

Test Plan:
- just clippy
- just test
- just frontend-test
- just build
- just fmt (Rust/TOML/Prettier completed; rumdl reports 39 pre-existing issues)
- git diff --cached --check
2026-08-09 17:51:11 +02:00
ddidderr 9268de2371 updated plan 2026-08-09 17:10:31 +02:00
ddidderr 18dd3b7e07 markdown formatting 2026-08-09 16:16:45 +02:00
ddidderr f4a6259cf3 improve PEER_AUTH_PLAN.md and re-organize files 2026-08-09 16:08:01 +02:00
ddidderr fe3c3c6520 further simplify plan 2026-08-09 13:02:04 +02:00
ddidderr 49159988a3 blake3 2026-08-09 12:55:45 +02:00
ddidderr a02c5b3c85 deno update 2026-08-09 12:54:21 +02:00
ddidderr 96c66875b5 [deps] cargo update 2026-08-09 12:50:18 +02:00
ddidderr b929ad16a5 [deps] cargo update 2026-08-09 12:49:53 +02:00
ddidderr 8dae9dfe75 PEER_AUTH_PLAN simplified drastically. GPT 5.6 Sol (ultra) was doing a great job, but with my poor prompting it completely overengineered. 2026-08-09 12:47:14 +02:00
ddidderr a886e64fc7 docs(peer): consolidate authentication plan
Replace the earlier peer-authentication proposal with the reviewed,
implementation-oriented design. The plan now records the identity-storage
state machine, pinned TLS and endpoint rules, signed Call-to-Play objects,
download-source authorization, resource limits, safe protocol phases, and
phase-owned acceptance gates.

Remove the standalone review after incorporating its findings and follow-up
adjudication into the authoritative plan, including an explicit closure matrix.
This avoids maintaining two documents with conflicting severity and guidance.

Test Plan:
- `git diff --cached --check` -- passed
- Code tests not run; documentation-only change
2026-08-09 11:15:50 +02:00
ddidderr 8d1e1a13c5 Peer auth plan 2026-07-28 07:41:30 +02:00
ddidderr f608eaa6b1 arrrrr... doch pub/private keys... 2026-07-24 07:44:08 +02:00
ddidderr 716564bc7c review_findings 2026-07-23 23:21:54 +02:00
ddidderr 2c204ac258 fix(call-to-play): explain peer startup state
Treat an unavailable actor ID or an explicit not-ready result as normal peer
startup and tell the user that LAN connection is still in progress. Clear that
message when snapshot registration succeeds.

Map obsolete, missing-history, and active-history-limit store failures to
distinct guidance without marking a healthy transport unavailable. Preserve a
generic message for unexpected publish failures.

Test Plan:
- just frontend-test
- just build
- git diff --cached --check
2026-07-23 18:07:08 +02:00
ddidderr 8d3affe19c fix(call-to-play): extend from the current deadline
Pass the effective nomination deadline into the Add time action and extend
from whichever is later: that deadline or the current time. This preserves
remaining time when a call becomes ready early while still giving an overdue
call a fresh five-minute window.

Test Plan:
- just fmt
- just frontend-test
- just build
- git diff --cached --check
2026-07-23 18:05:21 +02:00
ddidderr 9c34efa705 feat(call-to-play): retain terminal outcomes
Keep complete running and cancelled histories visible for fifteen minutes so
peers retain the roster, chat, and outcome long enough to understand what
happened. Compact them to terminal tombstones afterward without charging
settled calls against the active-history limit.

Model running and cancelled as durable read-only frontend states, exclude
them from active badges, prune retired raw events, and document the lifecycle.
Add peer scenario S49 to prove a late joiner reconstructs a terminal call with
its roster and chat intact.

Test Plan:
- just fmt
- just clippy
- just test
- just frontend-test
- just build
- just peer-cli-tests S48 S49
- python3 -m py_compile crates/lanspread-peer-cli/scripts/run_extended_scenarios.py
- git diff --cached --check
2026-07-23 18:03:57 +02:00
ddidderr e5d70ae56f fix(call-to-play): acknowledge live replication
Raise the wire protocol to version 7 and add explicit Call to Play delivery
outcomes. Live requests now wait for an application acknowledgement, allowing
the sender to distinguish applied, duplicate, obsolete, incomplete, and
rejected updates instead of treating a successful write as acceptance.

Remove source-IP equality from actor verification. The receiver now requires
the envelope peer ID to be present in its known roster and requires every live
event actor to match that envelope. This matches the cooperative-LAN trust
model without misrepresenting the shared TLS identity as per-peer
authentication.

Transport failures, malformed responses, NeedHandshake, and NeedHistory each
trigger one asynchronous Hello/HelloAck resync. Rejections are logged without
retry, and local publication remains independent of remote availability.

Test Plan:
- `just fmt` -- passed
- `just clippy` -- passed
- `just test` -- passed
- `git diff --cached --check` -- passed
2026-07-23 17:49:01 +02:00
ddidderr be7ad2e560 refactor(call-to-play): merge histories atomically
Replace per-event insertion with a transactional batch merge. The store now
validates and deduplicates an entire history before committing it, rejects
conflicting event IDs without partial mutation, evaluates retention after all
batch events are present, and reports applied, duplicate, obsolete, and
missing-root outcomes explicitly.

Derive event identity from retained history instead of preserving an unbounded
ID set. Expired histories can therefore be restored by a complete Create plus
AddTime batch, while orphan actions request history and terminal tombstones
continue to reject stale resurrection. Capacity applies only to unresolved
history, allowing Start and Cancel to settle a full call.

Only retained events reach the UI or live broadcast path. Handshake and live
merge callers log invalid or incomplete histories without publishing events
that compaction discarded.

Test Plan:
- `just fmt` -- passed
- `just clippy` -- passed
- `just test` -- passed
- `git diff --cached --check` -- passed
2026-07-23 17:44:03 +02:00
ddidderr 872692e3f4 plan 2026-07-23 17:07:32 +02:00
ddidderr e141229805 fable5findings 2026-07-23 13:06:21 +02:00
ddidderr d58307c328 fix(call-to-play): compact expired snapshots
Expired call histories were removed on the next store insertion, so an otherwise
idle peer could continue carrying stale payload through handshakes after the
five-minute UI retention ended.

Run the same inactive-call compaction before local and handshake snapshots. This
makes the expiry boundary exact without trimming any event from an active call.

Test Plan:
- `just fmt` -- passed
- `just clippy` -- passed
- `just test` -- passed, 147 peer tests
- `git diff --cached --check` -- passed
2026-07-21 22:59:48 +02:00
ddidderr 383e8f4855 fix(call-to-play): resync after live delivery failure
A failed fire-and-forget event left one peer's active call state divergent until
some later discovery or reconnect happened. During a LAN party that could leave
different players looking at different rosters or chat.

Fall back to the existing bidirectional handshake whenever a live Call to Play
send fails. Its active-history exchange heals both sides immediately when the
failure was transient. Document the related wall-clock synchronization
assumption for deadline and countdown presentation.

Test Plan:
- `just fmt` -- passed
- `just clippy` -- passed
- `just test` -- passed, 147 peer tests
- `just peer-cli-tests S48` -- passed
- `git diff --cached --check` -- passed
2026-07-21 22:58:19 +02:00
ddidderr cc7dacf6c3 fix(call-to-play): expire elapsed calls clearly
Deadline completion previously shared the green Ready presentation with a full
roster and remained visible forever. An abandoned call therefore looked ready
to launch and required its creator to return and cancel it.

Give elapsed calls a distinct Time's up state and a five-minute grace period in
which the creator can start or extend them. After that, both the reducer and
peer store remove the call as a unit. Filled calls remain ready until their
deadline, and active calls continue to retain complete history for late joiners.

Test Plan:
- `just fmt` -- passed
- `just clippy` -- passed
- `just test` -- passed, 147 peer tests
- `just frontend-test` -- passed, 22 tests
- `just build` -- passed
- `git diff --cached --check` -- passed
2026-07-21 22:56:02 +02:00
ddidderr 640d81d919 fix(call-to-play): explain unavailable game calls
Calls for a game missing from the local catalog still contributed to the badge
but were discarded by both the ticker and overlay. Opening the badge could
therefore show a blank modal with no explanation.

Render those calls with an unavailable-game label, the sender and game ID, the
normal roster and chat, and safe coordination actions. The creator can mark the
match started, but automatic launch remains disabled until catalog data exists.

Test Plan:
- `just fmt` -- passed
- `just frontend-test` -- passed, 21 tests
- `just build` -- passed
- `git diff --cached --check` -- passed
2026-07-21 22:50:09 +02:00
ddidderr 4b7725db16 fix(call-to-play): compact terminal histories
The 4,096-event store retained every completed call forever and local commands
only reported that they reached the queue. Once the bound was reached, GUI
actions could therefore fail with no user-visible result. The CLI snapshot wait
could also be satisfied by an unrelated live event.

Keep the complete event and chat history for every active call so late joiners
receive full context. When the creator starts or cancels a call, replace its
history with a single terminal tombstone; this bounds retained payload while
still healing peers that missed the live terminal action. Publish commands now
reply with the actual store result, and CLI snapshots use a direct reply.

Test Plan:
- `just fmt` -- passed
- `just clippy` -- passed
- `just test` -- passed, including full-cap terminal compaction
- `just build` -- passed
- `just peer-cli-tests S48` -- passed
- `git diff --cached --check` -- passed
2026-07-21 22:48:19 +02:00
ddidderr 29eacabcc0 fix(call-to-play): key actors by stable peer identity
Participant maps and creator authorization previously used display names, so
two peers left at the default Commander name collapsed into one participant
and could exercise each other's creator controls through the normal client.

Carry a stable actor_id separately from actor_name. The peer overwrites actor_id
on every local publish, and live event envelopes are accepted only when the
known peer, source, and event actor match. The frontend keys participants and
authorization by actor_id while retaining actor_name for display. This follows
the trusted-LAN model and is not cryptographic authentication against a hostile
peer.

Test Plan:
- `just fmt` -- passed
- `just clippy` -- passed
- `just test` -- passed
- `just frontend-test` -- passed, 21 tests
- `just build` -- passed
- `just peer-cli-tests S48` -- passed
- `git diff --cached --check` -- passed
2026-07-21 22:40:59 +02:00
ddidderr 0f53bc4b78 feat(call-to-play)!: coordinate game sessions across peers
Implement the launcher design as a production peer-to-peer feature. Call to
Play actions are immutable, validated events broadcast over the existing QUIC
control channel, deduplicated in a bounded in-memory history, and exchanged in
Hello/HelloAck so late joiners reconstruct current calls.

Add the Tauri bridge and modular launcher surfaces for play-now and scheduled
calls, check-in, readiness buffers, role-aware controls, chat, tickers, and
actual caller launch. A deterministic frontend reducer derives presentation
state from replicated history. Extend the JSONL peer harness with publish/list
commands and a three-peer live-delivery and late-join scenario.

This intentionally raises the only supported wire protocol from version 5 to
version 6; older builds are not supported. Document the transport architecture
and exclude generated peer-test state from Docker build contexts.

Test Plan:
- `just fmt` -- passed
- `just clippy` -- passed
- `just test` -- passed
- `just frontend-test` -- passed, 20 tests
- `just build` -- passed
- `just peer-cli-tests S2 S48` -- passed
- `git diff --cached --check` -- passed
2026-07-21 22:30:11 +02:00
ddidderr 8f151e38b4 docs(launcher): add Call to Play specification and design reference
Extend the launcher design specification and prototype reference with the
"Call to Play" multiplayer coordination feature and clean up top-bar chrome.

Key additions and changes:
- Spec & Roadmap: Document Call to Play mechanics in SPEC.md, including Play
  Now / Scheduled call flavors, 15-minute check-in windows, top-bar button
  with active count badge, quick-bar ticker stack above grid, overlay modal,
  and per-call group chat. Update design/README.md.
- Components & Logic: Add calltoplay.jsx and ctp-chat.jsx components for call
  creation, status progression, and chat. Extend data.jsx with a mock peer
  roster (PEERS) and helper functions for peer install count tracking.
- Top-bar Cleanup: Move game-folder configuration from top bar into Settings ->
  Library, freeing top-bar space for the Call to Play action button.
- Styling & Layout: Add CTP quick-bar, ticker, badge, card, and chat styles to
  styles.css, and integrate CTP components into launcher.jsx, components.jsx,
  and SoftLAN Launcher.html.

Test Plan:
- `git diff --cached --check` -- passed (no trailing whitespace or conflict markers)
- `cargo check --workspace` -- passed cleanly
- Manual review of staged diff across 9 design/launcher files -- confirmed clean staging
2026-07-21 20:00:07 +02:00
ddidderr 8d54e6e954 [deps] cargo update
Adding   syn                 v3.0.2
Updating anyhow              v1.0.103 -> v1.0.104
Updating bytemuck            v1.25.1  -> v1.25.2
Updating cc                  v1.2.67  -> v1.3.0
Updating fastrand            v2.4.1   -> v2.5.0
Updating futures-channel     v0.3.32  -> v0.3.33
Updating futures-core        v0.3.32  -> v0.3.33
Updating futures-executor    v0.3.32  -> v0.3.33
Updating futures-io          v0.3.32  -> v0.3.33
Updating futures-macro       v0.3.32  -> v0.3.33
Updating futures-sink        v0.3.32  -> v0.3.33
Updating futures-task        v0.3.32  -> v0.3.33
Updating futures-util        v0.3.32  -> v0.3.33
Updating futures             v0.3.32  -> v0.3.33
Updating glob                v0.3.3   -> v0.3.4
Updating hyper               v1.10.1  -> v1.11.0
Updating libc                v0.2.186 -> v0.2.188
Updating proc-macro2         v1.0.106 -> v1.0.107
Updating quote               v1.0.46  -> v1.0.47
Updating ref-cast-impl       v1.0.25  -> v1.0.26
Updating ref-cast            v1.0.25  -> v1.0.26
Updating serde_core          v1.0.228 -> v1.0.229
Updating serde_derive        v1.0.228 -> v1.0.229
Updating serde_json          v1.0.150 -> v1.0.151
Updating serde_repr          v0.1.20  -> v0.1.21
Updating serde               v1.0.228 -> v1.0.229
Updating tauri-plugin-dialog v2.7.1   -> v2.7.2
Updating tauri-plugin-store  v2.4.3   -> v2.4.4
Updating thiserror-impl      v2.0.18  -> v2.0.19
Updating thiserror           v2.0.18  -> v2.0.19
Updating time-macros         v0.2.31  -> v0.2.32
Updating time                v0.3.53  -> v0.3.54
Updating tokio-util          v0.7.18  -> v0.7.19
Updating tokio               v1.53.0  -> v1.53.1
Updating zerocopy-derive     v0.8.54  -> v0.8.55
Updating zerocopy            v0.8.54  -> v0.8.55
2026-07-21 19:54:03 +02:00
ddidderr fa8bd86281 [deps] cargo update
Updating aws-lc-rs      v1.17.1             -> v1.17.3
Updating aws-lc-sys     v0.42.0             -> v0.43.0
Updating bitflags       v2.13.0             -> v2.13.1
Updating http-body-util v0.1.3              -> v0.1.4
Updating http-body      v1.0.1              -> v1.1.0
Updating mdns-sd        v0.20.1             -> v0.20.2
Updating mio            v1.2.1              -> v1.2.2
Updating regex-automata v0.4.15             -> v0.4.16
Updating regex          v1.13.0             -> v1.13.1
Updating rustls         v0.23.41            -> v0.23.42
Updating simd-adler32   v0.3.9              -> v0.3.10
Updating socket2        v0.6.4              -> v0.6.5
Updating spin           v0.9.8              -> v0.9.9
Updating syn            v2.0.118            -> v2.0.119
Updating tokio-macros   v2.7.0              -> v2.7.1
Updating tokio          v1.52.3             -> v1.53.0
Updating toml_edit      v0.25.12+spec-1.1.0 -> v0.25.13+spec-1.1.0
Updating toml           v1.1.2+spec-1.1.0   -> v1.1.3+spec-1.1.0
Updating toml_writer    v1.1.1+spec-1.1.0   -> v1.1.2+spec-1.1.0
Updating uuid           v1.23.4             -> v1.24.0
Updating winnow         v1.0.3              -> v1.0.4
Updating zmij           v1.0.21             -> v1.0.23
2026-07-18 01:16:56 +02:00
ddidderr 6379e97db4 [deps] cargo update
Removing flume                      v0.11.1
Removing pathdiff                   v0.2.3
Removing utf-8                      v0.7.6
Updating anyhow                     v1.0.102 -> v1.0.103
Updating aws-lc-rs                  v1.17.0  -> v1.17.1
Updating aws-lc-sys                 v0.41.0  -> v0.42.0
Updating bytemuck                   v1.25.0  -> v1.25.1
Updating bytes                      v1.12.0  -> v1.12.1
Updating camino                     v1.2.3   -> v1.2.4
Updating cc                         v1.2.65  -> v1.2.67
Updating chacha20                   v0.10.0  -> v0.10.1
Updating crossbeam-channel          v0.5.15  -> v0.5.16
Updating crossbeam-queue            v0.3.12  -> v0.3.13
Updating crossbeam-utils            v0.8.21  -> v0.8.22
Updating dbus                       v0.9.11  -> v0.9.12
Updating embed-resource             v3.0.9   -> v3.0.11
Updating inotify-sys                v0.1.5   -> v0.1.8
Updating inotify                    v0.11.2  -> v0.11.4
Updating jobserver                  v0.1.34  -> v0.1.35
Updating js-sys                     v0.3.102 -> v0.3.103
Updating libredox                   v0.1.17  -> v0.1.18
Updating log                        v0.4.32  -> v0.4.33
Updating mdns-sd                    v0.20.0  -> v0.20.1
Updating memchr                     v2.8.2   -> v2.8.3
Updating open                       v5.3.5   -> v5.4.0
Updating plist                      v1.9.0   -> v1.10.0
Updating quick-xml                  v0.39.4  -> v0.41.0
Updating quote                      v1.0.45  -> v1.0.46
Updating rand                       v0.10.1  -> v0.10.2
Updating regex-automata             v0.4.14  -> v0.4.15
Updating regex                      v1.12.4  -> v1.13.0
Updating rustc-hash                 v2.1.2   -> v2.1.3
Updating rustls-pki-types           v1.14.1  -> v1.15.0
Updating rustls                     v0.23.40 -> v0.23.41
Updating rustversion                v1.0.22  -> v1.0.23
Updating s2n-codec                  v0.82.0  -> v0.83.0
Updating s2n-quic-core              v0.82.0  -> v0.83.0
Updating s2n-quic-crypto            v0.82.0  -> v0.83.0
Updating s2n-quic-platform          v0.82.0  -> v0.83.0
Updating s2n-quic-rustls            v0.82.0  -> v0.83.0
Updating s2n-quic-tls-default       v0.82.0  -> v0.83.0
Updating s2n-quic-tls               v0.82.0  -> v0.83.0
Updating s2n-quic-transport         v0.82.0  -> v0.83.0
Updating s2n-quic                   v1.82.0  -> v1.83.0
Updating s2n-tls-sys                v0.3.38  -> v0.3.40
Updating s2n-tls                    v0.3.38  -> v0.3.40
Updating socket-pktinfo             v0.3.2   -> v0.4.0
Updating tauri-runtime-wry          v2.11.3  -> v2.11.4
Updating tauri                      v2.11.3  -> v2.11.5
Updating tendril                    v0.5.0   -> v0.5.1
Updating thread_local               v1.1.9   -> v1.1.10
Updating time-macros                v0.2.29  -> v0.2.31
Updating time                       v0.3.49  -> v0.3.53
Updating tinyvec                    v1.11.0  -> v1.12.0
Updating uuid                       v1.23.3  -> v1.23.4
Updating wasm-bindgen-futures       v0.4.75  -> v0.4.76
Updating wasm-bindgen-macro-support v0.2.125 -> v0.2.126
Updating wasm-bindgen-macro         v0.2.125 -> v0.2.126
Updating wasm-bindgen-shared        v0.2.125 -> v0.2.126
Updating wasm-bindgen               v0.2.125 -> v0.2.126
Updating web-sys                    v0.3.102 -> v0.3.103
Updating zerocopy-derive            v0.8.52  -> v0.8.54
Updating zerocopy                   v0.8.52  -> v0.8.54
2026-07-12 17:12:11 +02:00
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
ddidderr 9d1cc771fc design: implement the actual SoftLAN wordmark 2026-06-21 21:27:54 +02:00
ddidderr 6415a4e517 design: updated design docs 2026-06-21 21:15:09 +02:00
ddidderr d9a6181ae2 design: seamless logo snake implemented 2026-06-21 20:49:30 +02:00
ddidderr 3d9d9cb450 design: seamless logo snake 2026-06-21 20:27:08 +02:00