Collections & download stability, UI (#130)

* feat: different local path in dev #73

* feat: better error output for downloads

* feat: collections in library view

* feat: improve download manager reliability

* feat: new download UI, more stable downloads

* fix: clippy

* fix: only show admin link if user is admin

* feat: check for libs before building
This commit is contained in:
DecDuck
2025-09-07 15:57:06 +10:00
committed by GitHub
parent 97b5cd5e78
commit 3f18d15d39
27 changed files with 449 additions and 195 deletions

View File

@ -23,7 +23,7 @@ use crate::remote::utils::{DROP_CLIENT_ASYNC, DROP_CLIENT_SYNC};
use log::{debug, error, info, warn};
use rayon::ThreadPoolBuilder;
use std::collections::{HashMap, HashSet};
use std::fs::{create_dir_all, OpenOptions};
use std::fs::{OpenOptions, create_dir_all};
use std::path::{Path, PathBuf};
use std::sync::mpsc::Sender;
use std::sync::{Arc, Mutex};
@ -39,6 +39,7 @@ use super::drop_data::DropData;
static RETRY_COUNT: usize = 3;
const TARGET_BUCKET_SIZE: usize = 63 * 1000 * 1000;
const MAX_FILES_PER_BUCKET: usize = (1024 / 4) - 1;
pub struct GameDownloadAgent {
pub id: String,
@ -83,6 +84,8 @@ impl GameDownloadAgent {
let stored_manifest =
DropData::generate(id.clone(), version.clone(), data_base_dir_path.clone());
let context_lock = stored_manifest.contexts.lock().unwrap().clone();
let result = Self {
id,
version,
@ -105,7 +108,14 @@ impl GameDownloadAgent {
.as_ref()
.unwrap()
.values()
.map(|e| e.lengths.iter().sum::<usize>())
.map(|e| {
e.lengths
.iter()
.enumerate()
.filter(|(i, _)| *context_lock.get(&e.checksums[*i]).unwrap_or(&false))
.map(|(_, v)| v)
.sum::<usize>()
})
.sum::<usize>() as u64;
let available_space = get_disk_available(data_base_dir_path)? as u64;
@ -298,7 +308,8 @@ impl GameDownloadAgent {
drops: vec![],
});
if *current_bucket_size + length >= TARGET_BUCKET_SIZE
if (*current_bucket_size + length >= TARGET_BUCKET_SIZE
|| current_bucket.drops.len() >= MAX_FILES_PER_BUCKET)
&& !current_bucket.drops.is_empty()
{
// Move current bucket into list and make a new one
@ -367,7 +378,8 @@ impl GameDownloadAgent {
.iter()
.map(|e| &e.version)
.collect::<HashSet<_>>()
.into_iter().cloned()
.into_iter()
.cloned()
.collect::<Vec<String>>();
info!("downloading across these versions: {versions:?}");
@ -460,6 +472,7 @@ impl GameDownloadAgent {
ApplicationDownloadError::Communication(_)
| ApplicationDownloadError::Checksum
| ApplicationDownloadError::Lock
| ApplicationDownloadError::IoError(_)
);
if i == RETRY_COUNT - 1 || !retry {
@ -626,8 +639,17 @@ impl Downloadable for GameDownloadAgent {
}
}
fn on_initialised(&self, _app_handle: &tauri::AppHandle) {
fn on_queued(&self, app_handle: &tauri::AppHandle) {
*self.status.lock().unwrap() = DownloadStatus::Queued;
let mut db_lock = borrow_db_mut_checked();
let status = ApplicationTransientStatus::Queued {
version_name: self.version.clone(),
};
db_lock
.applications
.transient_statuses
.insert(self.metadata(), status.clone());
push_game_update(app_handle, &self.id, None, (None, Some(status)));
}
fn on_error(&self, app_handle: &tauri::AppHandle, error: &ApplicationDownloadError) {
@ -636,7 +658,7 @@ impl Downloadable for GameDownloadAgent {
.emit("download_error", error.to_string())
.unwrap();
error!("error while managing download: {error}");
error!("error while managing download: {error:?}");
let mut handle = borrow_db_mut_checked();
handle
@ -662,15 +684,8 @@ impl Downloadable for GameDownloadAgent {
}
fn on_cancelled(&self, app_handle: &tauri::AppHandle) {
info!("cancelled {}", self.id);
self.cancel(app_handle);
/*
on_game_incomplete(
&self.metadata(),
self.dropdata.base_path.to_string_lossy().to_string(),
app_handle,
)
.unwrap();
*/
}
fn status(&self) -> DownloadStatus {