738095235f
Updating or removing a local game rewrites its on-disk files. Peers that were mid-download of that game would keep streaming bytes from files that are being deleted or replaced, handing them a corrupt or stale copy. There was also no authoritative notion of which game version a peer should serve or accept, so a peer could serve whatever happened to be on disk and downloaders could aggregate files from peers running mismatched versions. This introduces a reader-writer coordination scheme between outbound file transfers (readers) and local mutation operations (writers), and gates both serving and downloading on an authoritative game catalog version. Reader-writer coordination: - Track active outbound transfers per game in a shared `OutboundTransfers` map of (id, CancellationToken), threaded through `Ctx`/`PeerCtx` and registered by a `TransferGuard` in the stream service. The guard is registered *before* the serve-eligibility check to close a TOCTOU window where a writer could miss an in-flight reader. - `stream_file_bytes` now honors a cancellation token at every await point (file read, network send, stream close) via `tokio::select!`, so a transfer aborts promptly instead of hanging on a stalled receiver. - `begin_operation` marks a game active first, then cancels its outbound transfers and waits for the count to reach zero before any Updating/RemovingDownload work touches the filesystem. - Active games are now hidden from library snapshots entirely while an operation is in flight, instead of freezing their last announced state, so peers stop discovering a game that is being mutated. Authoritative version catalog: - Replace the `HashSet<String>` catalog with `GameCatalog`, mapping each game id to its expected version (from the bundled game.db / ETI data). - Serving requires the local `version.ini` to match the catalog version (`local_download_matches_catalog`); peer selection, file aggregation, and majority size validation all filter on the expected version (`peers_with_expected_version`, `aggregated_game_files`, and friends). User-visible changes: - The GUI shows confirmation dialogs before Update and Remove, and surfaces a sharing-status indicator on game cards and the detail modal. - A new `OutboundTransferCountChanged` event lets the UI reflect live outbound transfer activity. Test Plan: - just test - just frontend-test - just clippy
52 lines
1.5 KiB
TOML
52 lines
1.5 KiB
TOML
[package]
|
|
name = "lanspread-tauri-deno-ts"
|
|
version = "0.1.0"
|
|
description = "A Tauri App"
|
|
authors = ["you"]
|
|
edition = "2024"
|
|
|
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
|
|
[lib]
|
|
# The `_lib` suffix may seem redundant but it is necessary
|
|
# to make the lib name unique and wouldn't conflict with the bin name.
|
|
# This seems to be only an issue on Windows, see https://github.com/rust-lang/cargo/issues/8519
|
|
name = "lanspread_tauri_deno_ts_lib"
|
|
crate-type = ["staticlib", "cdylib", "rlib"]
|
|
test = true
|
|
doctest = false
|
|
|
|
[lints.clippy]
|
|
pedantic = { level = "warn", priority = -1 }
|
|
todo = "warn"
|
|
unwrap_used = "warn"
|
|
needless_pass_by_value = "allow"
|
|
|
|
[build-dependencies]
|
|
tauri-build = { version = "2", features = [] }
|
|
|
|
[dependencies]
|
|
# local
|
|
lanspread-peer = { path = "../../lanspread-peer" }
|
|
lanspread-db = { path = "../../lanspread-db" }
|
|
lanspread-compat = { path = "../../lanspread-compat" }
|
|
|
|
# external
|
|
base64 = { workspace = true }
|
|
eyre = { workspace = true }
|
|
log = { workspace = true }
|
|
mimalloc = { workspace = true }
|
|
serde = { workspace = true }
|
|
serde_json = { workspace = true }
|
|
tauri = { workspace = true }
|
|
tauri-plugin-log = { workspace = true }
|
|
tauri-plugin-shell = { workspace = true }
|
|
tauri-plugin-dialog = { workspace = true }
|
|
tauri-plugin-store = { workspace = true }
|
|
tokio = { workspace = true }
|
|
tokio-util = { workspace = true }
|
|
walkdir = { workspace = true }
|
|
|
|
[target.'cfg(windows)'.dependencies]
|
|
windows = { workspace = true }
|