This commit is contained in:
2025-11-13 19:25:45 +01:00
parent 16aeade138
commit d96d191c13
+67 -15
View File
@@ -1,4 +1,4 @@
import { useEffect, useState } from 'react'; import { useEffect, useRef, useState } from 'react';
import { invoke } from '@tauri-apps/api/core'; import { invoke } from '@tauri-apps/api/core';
import { listen } from '@tauri-apps/api/event'; import { listen } from '@tauri-apps/api/event';
import { open } from '@tauri-apps/plugin-dialog'; import { open } from '@tauri-apps/plugin-dialog';
@@ -8,6 +8,7 @@ import "./App.css";
const FILE_STORAGE = 'launcher-settings.json'; const FILE_STORAGE = 'launcher-settings.json';
const GAME_DIR_KEY = 'game-directory'; const GAME_DIR_KEY = 'game-directory';
const CHECKING_PEERS_TIMEOUT_MS = 5000;
// enum with install status // enum with install status
enum InstallStatus { enum InstallStatus {
@@ -38,11 +39,45 @@ const App = () => {
const [gameItems, setGameItems] = useState<Game[]>([]); const [gameItems, setGameItems] = useState<Game[]>([]);
const [searchTerm, setSearchTerm] = useState(''); const [searchTerm, setSearchTerm] = useState('');
const [gameDir, setGameDir] = useState(''); const [gameDir, setGameDir] = useState('');
const checkingPeersTimeouts = useRef<Record<string, ReturnType<typeof setTimeout>>>({});
const filteredGames = gameItems.filter(item => const filteredGames = gameItems.filter(item =>
item.name.toLowerCase().includes(searchTerm.toLowerCase()) item.name.toLowerCase().includes(searchTerm.toLowerCase())
); );
const clearCheckingPeersTimeout = (gameId: string) => {
const timeoutId = checkingPeersTimeouts.current[gameId];
if (timeoutId !== undefined) {
clearTimeout(timeoutId);
delete checkingPeersTimeouts.current[gameId];
}
};
const scheduleCheckingPeersFallback = (gameId: string, fallbackMessage?: string, fallbackLevel?: StatusLevel) => {
clearCheckingPeersTimeout(gameId);
checkingPeersTimeouts.current[gameId] = setTimeout(() => {
setGameItems(prev => prev.map(item => {
if (item.id !== gameId || item.install_status !== InstallStatus.CheckingPeers) {
return item;
}
return {
...item,
install_status: item.installed ? InstallStatus.Installed : InstallStatus.NotInstalled,
status_message: fallbackMessage ?? 'No peers currently have this game.',
status_level: fallbackLevel ?? 'error',
};
}));
delete checkingPeersTimeouts.current[gameId];
}, CHECKING_PEERS_TIMEOUT_MS);
};
useEffect(() => {
return () => {
Object.values(checkingPeersTimeouts.current).forEach(clearTimeout);
checkingPeersTimeouts.current = {};
};
}, []);
const getInitialGameDir = async () => { const getInitialGameDir = async () => {
// update game directory from storage (if exists) // update game directory from storage (if exists)
// only if it's not already set // only if it's not already set
@@ -60,6 +95,7 @@ const App = () => {
const unlisten = await listen('game-download-failed', (event) => { const unlisten = await listen('game-download-failed', (event) => {
const game_id = event.payload as string; const game_id = event.payload as string;
console.log(`❌ game-download-failed ${game_id} event received`); console.log(`❌ game-download-failed ${game_id} event received`);
clearCheckingPeersTimeout(game_id);
setGameItems(prev => prev.map(item => item.id === game_id setGameItems(prev => prev.map(item => item.id === game_id
? { ? {
...item, ...item,
@@ -85,6 +121,7 @@ const App = () => {
const unlisten = await listen('game-no-peers', (event) => { const unlisten = await listen('game-no-peers', (event) => {
const game_id = event.payload as string; const game_id = event.payload as string;
console.log(`⚠️ game-no-peers ${game_id} event received`); console.log(`⚠️ game-no-peers ${game_id} event received`);
clearCheckingPeersTimeout(game_id);
setGameItems(prev => prev.map(item => item.id === game_id setGameItems(prev => prev.map(item => item.id === game_id
? { ? {
...item, ...item,
@@ -107,6 +144,7 @@ const App = () => {
const unlisten = await listen('game-unpack-finished', (event) => { const unlisten = await listen('game-unpack-finished', (event) => {
const game_id = event.payload as string; const game_id = event.payload as string;
console.log(`🗲 game-unpack-finished ${game_id} event received`); console.log(`🗲 game-unpack-finished ${game_id} event received`);
clearCheckingPeersTimeout(game_id);
setGameItems(prev => prev.map(item => item.id === game_id setGameItems(prev => prev.map(item => item.id === game_id
? { ? {
...item, ...item,
@@ -183,6 +221,7 @@ const App = () => {
const unlisten_game_download_begin = await listen('game-download-begin', (event) => { const unlisten_game_download_begin = await listen('game-download-begin', (event) => {
const game_id = event.payload as string; const game_id = event.payload as string;
console.log(`🗲 game-download-begin ${game_id} event received`); console.log(`🗲 game-download-begin ${game_id} event received`);
clearCheckingPeersTimeout(game_id);
setGameItems(prev => prev.map(item => item.id === game_id setGameItems(prev => prev.map(item => item.id === game_id
? { ? {
...item, ...item,
@@ -197,6 +236,7 @@ const App = () => {
const unlisten_game_download_finished = await listen('game-download-finished', (event) => { const unlisten_game_download_finished = await listen('game-download-finished', (event) => {
const game_id = event.payload as string; const game_id = event.payload as string;
console.log(`🗲 game-download-finished ${game_id} event received`); console.log(`🗲 game-download-finished ${game_id} event received`);
clearCheckingPeersTimeout(game_id);
setGameItems(prev => prev.map(item => item.id === game_id setGameItems(prev => prev.map(item => item.id === game_id
? { ? {
...item, ...item,
@@ -247,15 +287,21 @@ const App = () => {
const success = await invoke('install_game', { id }); const success = await invoke('install_game', { id });
if (success) { if (success) {
console.log(`✅ Game install for id=${id} started...`); console.log(`✅ Game install for id=${id} started...`);
let fallbackMessage: string | undefined;
let fallbackLevel: StatusLevel | undefined;
// update install status in gameItems for this game // update install status in gameItems for this game
setGameItems(prev => prev.map(item => item.id === id setGameItems(prev => prev.map(item => {
? { if (item.id === id) {
...item, fallbackMessage = item.status_message;
install_status: InstallStatus.CheckingPeers, fallbackLevel = item.status_level;
status_message: undefined, return {
status_level: undefined, ...item,
install_status: InstallStatus.CheckingPeers,
};
} }
: item)); return item;
}));
scheduleCheckingPeersFallback(id, fallbackMessage, fallbackLevel);
} else { } else {
// game is already being installed // game is already being installed
console.warn(`🚧 Game with id=${id} is already being installed`); console.warn(`🚧 Game with id=${id} is already being installed`);
@@ -271,15 +317,21 @@ const App = () => {
const success = await invoke('update_game', { id }); const success = await invoke('update_game', { id });
if (success) { if (success) {
console.log(`✅ Game update for id=${id} started...`); console.log(`✅ Game update for id=${id} started...`);
let fallbackMessage: string | undefined;
let fallbackLevel: StatusLevel | undefined;
// update install status in gameItems for this game // update install status in gameItems for this game
setGameItems(prev => prev.map(item => item.id === id setGameItems(prev => prev.map(item => {
? { if (item.id === id) {
...item, fallbackMessage = item.status_message;
install_status: InstallStatus.CheckingPeers, fallbackLevel = item.status_level;
status_message: undefined, return {
status_level: undefined, ...item,
install_status: InstallStatus.CheckingPeers,
};
} }
: item)); return item;
}));
scheduleCheckingPeersFallback(id, fallbackMessage, fallbackLevel);
} else { } else {
// game is already being installed/updated // game is already being installed/updated
console.warn(`🚧 Game with id=${id} is already being updated`); console.warn(`🚧 Game with id=${id} is already being updated`);