fix(peer): refresh settled install state after operations
The follow-up review found a few stale lifecycle edges around local game transactions. Recovery could sweep active roots, post-operation refreshes still re-ran full startup recovery, and the UI kept inferring local-only state from downloaded and installed flags instead of the backend availability. This updates the peer lifecycle so startup recovery skips active operations, install/update/uninstall refresh only the affected game after the operation guard is dropped, and path-changing game-directory updates are rejected while operations are active. It also removes the dead UpdateGame command, drops the unused manifest_hash write field while preserving old JSON reads, renames the internal install-finished event, and carries availability through the DB, peer summaries, Tauri refreshes, and the React model. The included follow-up documents record the review source, implementation decisions, and the remaining FOLLOW_UP_2.md work so later commits can stay small instead of reopening the completed plan items. Test Plan: - git diff --check - just fmt - just clippy - just test Follow-up-Plan: FOLLOW_UP_PLAN.md
This commit is contained in:
@@ -7,10 +7,10 @@ use std::{
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use lanspread_db::db::{Game, GameFileDescription};
|
||||
use lanspread_db::db::{AVAILABILITY_READY, Game, GameFileDescription};
|
||||
use lanspread_proto::{Availability, GameSummary, LibraryDelta, LibrarySnapshot};
|
||||
|
||||
use crate::library::compute_library_digest;
|
||||
use crate::{library::compute_library_digest, local_games::availability_label};
|
||||
pub type PeerId = String;
|
||||
|
||||
/// Information about a discovered peer.
|
||||
@@ -293,6 +293,10 @@ impl PeerGameDB {
|
||||
}
|
||||
if game_is_ready(game) {
|
||||
existing.downloaded = true;
|
||||
existing.availability = AVAILABILITY_READY.to_string();
|
||||
} else if !existing.downloaded {
|
||||
existing.availability =
|
||||
availability_label(&game.availability).to_string();
|
||||
}
|
||||
if game.installed {
|
||||
existing.installed = true;
|
||||
@@ -744,6 +748,7 @@ fn summary_to_game(summary: &GameSummary) -> Game {
|
||||
size: summary.size,
|
||||
downloaded: summary.downloaded,
|
||||
installed: summary.installed,
|
||||
availability: availability_label(&summary.availability).to_string(),
|
||||
eti_game_version,
|
||||
local_version: None,
|
||||
peer_count: 0,
|
||||
@@ -754,6 +759,8 @@ fn summary_to_game(summary: &GameSummary) -> Game {
|
||||
mod tests {
|
||||
use std::net::SocketAddr;
|
||||
|
||||
use lanspread_db::db::AVAILABILITY_LOCAL_ONLY;
|
||||
|
||||
use super::*;
|
||||
|
||||
fn addr(port: u16) -> SocketAddr {
|
||||
@@ -817,6 +824,7 @@ mod tests {
|
||||
assert_eq!(games.len(), 1);
|
||||
assert_eq!(games[0].peer_count, 0);
|
||||
assert!(!games[0].downloaded);
|
||||
assert_eq!(games[0].availability, AVAILABILITY_LOCAL_ONLY);
|
||||
assert_eq!(games[0].eti_game_version, None);
|
||||
|
||||
assert!(db.peers_with_game("game").is_empty());
|
||||
|
||||
Reference in New Issue
Block a user