This commit is contained in:
2025-11-13 09:22:05 +01:00
parent f37d93c417
commit 16aeade138
4 changed files with 108 additions and 8 deletions
+6
View File
@@ -120,6 +120,9 @@ pub enum PeerEvent {
DownloadGameFilesFailed {
id: String,
},
NoPeersHaveGame {
id: String,
},
PeerConnected(SocketAddr),
PeerDisconnected(SocketAddr),
PeerDiscovered(SocketAddr),
@@ -1315,6 +1318,9 @@ async fn handle_get_game_command(ctx: &Ctx, tx_notify_ui: &UnboundedSender<PeerE
let peers = { ctx.peer_game_db.read().await.peers_with_game(&id) };
if peers.is_empty() {
log::warn!("No peers have game {id}");
if let Err(e) = tx_notify_ui.send(PeerEvent::NoPeersHaveGame { id: id.clone() }) {
log::error!("Failed to send NoPeersHaveGame event: {e}");
}
return;
}
@@ -663,6 +663,21 @@ pub fn run() {
}
}
PeerEvent::NoPeersHaveGame { id } => {
log::warn!("PeerEvent::NoPeersHaveGame received for {id}");
if let Err(e) = app_handle.emit("game-no-peers", Some(id.clone())) {
log::error!("PeerEvent::NoPeersHaveGame: Failed to emit game-no-peers event: {e}");
}
app_handle
.state::<LanSpreadState>()
.inner()
.games_in_download
.write()
.await
.remove(&id);
}
PeerEvent::DownloadGameFilesBegin { id } => {
log::info!("PeerEvent::DownloadGameFilesBegin received");
@@ -216,3 +216,15 @@ h1.align-center {
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.3);
}
.item-info {
min-height: 18px;
margin: 8px 10px 16px;
font-size: 0.85em;
color: #8892b0;
text-align: center;
}
.item-info.error {
color: #ff6666;
}
+75 -8
View File
@@ -18,16 +18,20 @@ enum InstallStatus {
Installed = 'Installed',
}
type StatusLevel = 'info' | 'error';
interface Game {
id: string;
name: string;
description: string;
size: number;
thumbnail: Uint8Array;
thumbnail: Uint8Array | number[];
installed: boolean;
install_status: InstallStatus;
eti_game_version?: string;
local_version?: string;
status_message?: string;
status_level?: StatusLevel;
}
const App = () => {
@@ -57,7 +61,12 @@ const App = () => {
const game_id = event.payload as string;
console.log(`❌ game-download-failed ${game_id} event received`);
setGameItems(prev => prev.map(item => item.id === game_id
? {...item, install_status: InstallStatus.NotInstalled}
? {
...item,
install_status: item.installed ? InstallStatus.Installed : InstallStatus.NotInstalled,
status_message: 'Download failed. Please try again.',
status_level: 'error',
}
: item));
// Convert to string explicitly and verify it's not empty
@@ -72,7 +81,24 @@ const App = () => {
return unlisten;
};
const setupNoPeersListener = async () => {
const unlisten = await listen('game-no-peers', (event) => {
const game_id = event.payload as string;
console.log(`⚠️ game-no-peers ${game_id} event received`);
setGameItems(prev => prev.map(item => item.id === game_id
? {
...item,
install_status: item.installed ? InstallStatus.Installed : InstallStatus.NotInstalled,
status_message: 'No peers currently have this game.',
status_level: 'error',
}
: item));
});
return unlisten;
};
setupDownloadFailedListener();
setupNoPeersListener();
}, [gameDir]);
useEffect(() => {
@@ -82,7 +108,12 @@ const App = () => {
const game_id = event.payload as string;
console.log(`🗲 game-unpack-finished ${game_id} event received`);
setGameItems(prev => prev.map(item => item.id === game_id
? {...item, install_status: InstallStatus.Installed}
? {
...item,
install_status: InstallStatus.Installed,
status_message: undefined,
status_level: undefined,
}
: item));
// Convert to string explicitly and verify it's not empty
@@ -131,7 +162,20 @@ const App = () => {
console.log('🗲 Received games-list-updated event');
const games = event.payload as Game[];
console.log(`🎮 ${games.length} Games received`);
setGameItems(games);
setGameItems(prev => {
const previousById = new Map(prev.map(item => [item.id, item]));
return games.map(game => {
const previous = previousById.get(game.id);
const installStatus = previous?.install_status
?? (game.installed ? InstallStatus.Installed : InstallStatus.NotInstalled);
return {
...game,
install_status: installStatus,
status_message: previous?.status_message,
status_level: previous?.status_level,
};
});
});
getInitialGameDir();
});
@@ -140,7 +184,12 @@ const App = () => {
const game_id = event.payload as string;
console.log(`🗲 game-download-begin ${game_id} event received`);
setGameItems(prev => prev.map(item => item.id === game_id
? { ...item, install_status: InstallStatus.Downloading }
? {
...item,
install_status: InstallStatus.Downloading,
status_message: undefined,
status_level: undefined,
}
: item));
});
@@ -149,7 +198,12 @@ const App = () => {
const game_id = event.payload as string;
console.log(`🗲 game-download-finished ${game_id} event received`);
setGameItems(prev => prev.map(item => item.id === game_id
? { ...item, install_status: InstallStatus.Unpacking }
? {
...item,
install_status: InstallStatus.Unpacking,
status_message: undefined,
status_level: undefined,
}
: item));
});
@@ -195,7 +249,12 @@ const App = () => {
console.log(`✅ Game install for id=${id} started...`);
// update install status in gameItems for this game
setGameItems(prev => prev.map(item => item.id === id
? { ...item, install_status: InstallStatus.CheckingPeers }
? {
...item,
install_status: InstallStatus.CheckingPeers,
status_message: undefined,
status_level: undefined,
}
: item));
} else {
// game is already being installed
@@ -214,7 +273,12 @@ const App = () => {
console.log(`✅ Game update for id=${id} started...`);
// update install status in gameItems for this game
setGameItems(prev => prev.map(item => item.id === id
? { ...item, install_status: InstallStatus.CheckingPeers }
? {
...item,
install_status: InstallStatus.CheckingPeers,
status_message: undefined,
status_level: undefined,
}
: item));
} else {
// game is already being installed/updated
@@ -337,6 +401,9 @@ const App = () => {
: 'Update'
: 'Play'}
</div>
<div className={`item-info${item.status_level ? ` ${item.status_level}` : ''}`}>
{item.status_message ?? ''}
</div>
</div>
);
})}