diff --git a/crates/lanspread-peer-cli/src/main.rs b/crates/lanspread-peer-cli/src/main.rs index edb00da..01673b1 100644 --- a/crates/lanspread-peer-cli/src/main.rs +++ b/crates/lanspread-peer-cli/src/main.rs @@ -94,6 +94,7 @@ struct CliState { remote_games: Vec, active_operations: Vec, game_files: HashMap>, + unavailable_games: HashSet, } #[derive(Clone, serde::Serialize)] @@ -304,23 +305,32 @@ async fn game_files_for_download( shared: &SharedState, game_id: &str, ) -> eyre::Result> { - if let Some(files) = shared.state.read().await.game_files.get(game_id).cloned() { - return Ok(files); + { + let mut state = shared.state.write().await; + if let Some(files) = state.game_files.get(game_id).cloned() { + return Ok(files); + } + state.unavailable_games.remove(game_id); } sender.send(PeerCommand::GetGame(game_id.to_string()))?; let wait = async { loop { - if let Some(files) = shared.state.read().await.game_files.get(game_id).cloned() { - return files; + let state = shared.state.read().await; + if let Some(files) = state.game_files.get(game_id).cloned() { + return Ok(files); } + if state.unavailable_games.contains(game_id) { + eyre::bail!("no peers have game {game_id}"); + } + drop(state); shared.notify.notified().await; } }; tokio::time::timeout(Duration::from_secs(10), wait) .await - .wrap_err("timed out waiting for game file details") + .wrap_err("timed out waiting for game file details")? } async fn event_loop( @@ -396,7 +406,15 @@ async fn update_state_from_event(shared: &SharedState, event: PeerEvent) -> (&'s PeerEvent::UninstallGameBegin { id } => ("uninstall-begin", json!({"game_id": id})), PeerEvent::UninstallGameFinished { id } => ("uninstall-finished", json!({"game_id": id})), PeerEvent::UninstallGameFailed { id } => ("uninstall-failed", json!({"game_id": id})), - PeerEvent::NoPeersHaveGame { id } => ("no-peers-have-game", json!({"game_id": id})), + PeerEvent::NoPeersHaveGame { id } => { + shared + .state + .write() + .await + .unavailable_games + .insert(id.clone()); + ("no-peers-have-game", json!({"game_id": id})) + } PeerEvent::PeerConnected(addr) => ("peer-connected", peer_addr_json(addr)), PeerEvent::PeerDisconnected(addr) => ("peer-disconnected", peer_addr_json(addr)), PeerEvent::PeerDiscovered(addr) => ("peer-discovered", peer_addr_json(addr)),