wip
This commit is contained in:
@@ -1281,7 +1281,16 @@ async fn calculate_directory_size(dir: &Path) -> eyre::Result<u64> {
|
|||||||
Ok(total_size)
|
Ok(total_size)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn local_download_available(game_dir: &str, game_id: &str) -> bool {
|
async fn local_download_available(
|
||||||
|
game_dir: &str,
|
||||||
|
game_id: &str,
|
||||||
|
downloading_games: &Arc<RwLock<HashSet<String>>>,
|
||||||
|
) -> bool {
|
||||||
|
if downloading_games.read().await.contains(game_id) {
|
||||||
|
log::debug!("Not serving game {game_id} locally because it is still downloading");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
let game_path = PathBuf::from(game_dir).join(game_id);
|
let game_path = PathBuf::from(game_dir).join(game_id);
|
||||||
let eti_path = game_path.join(format!("{game_id}.eti"));
|
let eti_path = game_path.join(format!("{game_id}.eti"));
|
||||||
|
|
||||||
@@ -1299,6 +1308,7 @@ struct Ctx {
|
|||||||
local_game_db: Arc<RwLock<Option<GameDB>>>,
|
local_game_db: Arc<RwLock<Option<GameDB>>>,
|
||||||
peer_game_db: Arc<RwLock<PeerGameDB>>,
|
peer_game_db: Arc<RwLock<PeerGameDB>>,
|
||||||
local_peer_addr: Arc<RwLock<Option<SocketAddr>>>,
|
local_peer_addr: Arc<RwLock<Option<SocketAddr>>>,
|
||||||
|
downloading_games: Arc<RwLock<HashSet<String>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -1306,6 +1316,7 @@ struct PeerCtx {
|
|||||||
game_dir: Arc<RwLock<Option<String>>>,
|
game_dir: Arc<RwLock<Option<String>>>,
|
||||||
local_game_db: Arc<RwLock<Option<GameDB>>>,
|
local_game_db: Arc<RwLock<Option<GameDB>>>,
|
||||||
local_peer_addr: Arc<RwLock<Option<SocketAddr>>>,
|
local_peer_addr: Arc<RwLock<Option<SocketAddr>>>,
|
||||||
|
downloading_games: Arc<RwLock<HashSet<String>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Debug for PeerCtx {
|
impl std::fmt::Debug for PeerCtx {
|
||||||
@@ -1314,6 +1325,7 @@ impl std::fmt::Debug for PeerCtx {
|
|||||||
.field("game_dir", &"...")
|
.field("game_dir", &"...")
|
||||||
.field("local_game_db", &"...")
|
.field("local_game_db", &"...")
|
||||||
.field("local_peer_addr", &"...")
|
.field("local_peer_addr", &"...")
|
||||||
|
.field("downloading_games", &"...")
|
||||||
.finish()
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1334,12 +1346,14 @@ pub async fn run_peer(
|
|||||||
local_game_db: Arc::new(RwLock::new(None)),
|
local_game_db: Arc::new(RwLock::new(None)),
|
||||||
peer_game_db: Arc::new(RwLock::new(PeerGameDB::new())),
|
peer_game_db: Arc::new(RwLock::new(PeerGameDB::new())),
|
||||||
local_peer_addr: Arc::new(RwLock::new(None)),
|
local_peer_addr: Arc::new(RwLock::new(None)),
|
||||||
|
downloading_games: Arc::new(RwLock::new(HashSet::new())),
|
||||||
};
|
};
|
||||||
|
|
||||||
let peer_ctx = PeerCtx {
|
let peer_ctx = PeerCtx {
|
||||||
game_dir: ctx.game_dir.clone(),
|
game_dir: ctx.game_dir.clone(),
|
||||||
local_game_db: ctx.local_game_db.clone(),
|
local_game_db: ctx.local_game_db.clone(),
|
||||||
local_peer_addr: ctx.local_peer_addr.clone(),
|
local_peer_addr: ctx.local_peer_addr.clone(),
|
||||||
|
downloading_games: ctx.downloading_games.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Start server component
|
// Start server component
|
||||||
@@ -1519,7 +1533,7 @@ async fn try_serve_local_game(
|
|||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|
||||||
if !local_download_available(&game_dir, id).await {
|
if !local_download_available(&game_dir, id, &ctx.downloading_games).await {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1646,7 +1660,7 @@ async fn handle_download_game_files_command(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if peer_whitelist.is_empty() {
|
if peer_whitelist.is_empty() {
|
||||||
if local_download_available(&games_folder, &id).await {
|
if local_download_available(&games_folder, &id, &ctx.downloading_games).await {
|
||||||
log::info!("Using locally downloaded files for game {id}; skipping peer transfer");
|
log::info!("Using locally downloaded files for game {id}; skipping peer transfer");
|
||||||
if let Err(e) = tx_notify_ui.send(PeerEvent::DownloadGameFilesBegin { id: id.clone() })
|
if let Err(e) = tx_notify_ui.send(PeerEvent::DownloadGameFilesBegin { id: id.clone() })
|
||||||
{
|
{
|
||||||
@@ -1663,9 +1677,18 @@ async fn handle_download_game_files_command(
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut in_progress = ctx.downloading_games.write().await;
|
||||||
|
if !in_progress.insert(id.clone()) {
|
||||||
|
log::warn!("Download for {id} already in progress; ignoring new request");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let downloading_games = ctx.downloading_games.clone();
|
||||||
let tx_notify_ui = tx_notify_ui.clone();
|
let tx_notify_ui = tx_notify_ui.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
match download_game_files(
|
let result = download_game_files(
|
||||||
&id,
|
&id,
|
||||||
resolved_descriptions,
|
resolved_descriptions,
|
||||||
games_folder,
|
games_folder,
|
||||||
@@ -1673,16 +1696,19 @@ async fn handle_download_game_files_command(
|
|||||||
file_peer_map,
|
file_peer_map,
|
||||||
tx_notify_ui.clone(),
|
tx_notify_ui.clone(),
|
||||||
)
|
)
|
||||||
.await
|
.await;
|
||||||
|
|
||||||
{
|
{
|
||||||
Ok(()) => {}
|
let mut guard = downloading_games.write().await;
|
||||||
Err(e) => {
|
guard.remove(&id);
|
||||||
log::error!("Download failed for {id}: {e}");
|
}
|
||||||
if let Err(send_err) =
|
|
||||||
tx_notify_ui.send(PeerEvent::DownloadGameFilesFailed { id: id.clone() })
|
if let Err(e) = result {
|
||||||
{
|
log::error!("Download failed for {id}: {e}");
|
||||||
log::error!("Failed to send DownloadGameFilesFailed event: {send_err}");
|
if let Err(send_err) =
|
||||||
}
|
tx_notify_ui.send(PeerEvent::DownloadGameFilesFailed { id: id.clone() })
|
||||||
|
{
|
||||||
|
log::error!("Failed to send DownloadGameFilesFailed event: {send_err}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -1780,10 +1806,22 @@ async fn handle_peer_stream(
|
|||||||
Request::ListGames => {
|
Request::ListGames => {
|
||||||
// Return list of games from this peer
|
// Return list of games from this peer
|
||||||
log::info!("Received ListGames request from peer");
|
log::info!("Received ListGames request from peer");
|
||||||
let games = if let Some(ref db) = *ctx.local_game_db.read().await {
|
let snapshot = {
|
||||||
db.all_games().into_iter().cloned().collect()
|
let db_guard = ctx.local_game_db.read().await;
|
||||||
|
if let Some(ref db) = *db_guard {
|
||||||
|
db.all_games().into_iter().cloned().collect::<Vec<Game>>()
|
||||||
|
} else {
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let games = if snapshot.is_empty() {
|
||||||
|
snapshot
|
||||||
} else {
|
} else {
|
||||||
Vec::new()
|
let downloading = ctx.downloading_games.read().await;
|
||||||
|
snapshot
|
||||||
|
.into_iter()
|
||||||
|
.filter(|game| !downloading.contains(&game.id))
|
||||||
|
.collect()
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(e) = tx.send(Response::ListGames(games).encode()).await {
|
if let Err(e) = tx.send(Response::ListGames(games).encode()).await {
|
||||||
@@ -1792,7 +1830,13 @@ async fn handle_peer_stream(
|
|||||||
}
|
}
|
||||||
Request::GetGame { id } => {
|
Request::GetGame { id } => {
|
||||||
log::info!("Received GetGame request for {id} from peer");
|
log::info!("Received GetGame request for {id} from peer");
|
||||||
let response = if let Some(ref game_dir) = *ctx.game_dir.read().await {
|
let downloading = ctx.downloading_games.read().await.contains(&id);
|
||||||
|
let response = if downloading {
|
||||||
|
log::info!(
|
||||||
|
"Declining to serve GetGame for {id} because download is in progress"
|
||||||
|
);
|
||||||
|
Response::GameNotFound(id)
|
||||||
|
} else if let Some(ref game_dir) = *ctx.game_dir.read().await {
|
||||||
if let Some(ref db) = *ctx.local_game_db.read().await {
|
if let Some(ref db) = *ctx.local_game_db.read().await {
|
||||||
if db.get_game_by_id(&id).is_some() {
|
if db.get_game_by_id(&id).is_some() {
|
||||||
match get_game_file_descriptions(&id, game_dir).await {
|
match get_game_file_descriptions(&id, game_dir).await {
|
||||||
|
|||||||
Reference in New Issue
Block a user