Async downloader, better Proton support (#183)

* feat: async downloader + other fixes

* feat: windows command parsing + use library path for install path

* feat: better proton support

* feat: style fixes and store button now uses in-app

* feat: emulator rename + umu emulator fix

* feat: bring process creation inline with docs

* fix: clippy
This commit is contained in:
DecDuck
2026-02-06 23:24:14 +11:00
committed by GitHub
parent 1f74d35bdc
commit 16ef83228b
45 changed files with 1453 additions and 381 deletions
@@ -1,7 +1,7 @@
use std::{
collections::HashMap,
sync::RwLock,
time::{Duration, Instant},
time::{Duration, Instant}, usize,
};
use futures_util::StreamExt;
@@ -48,6 +48,12 @@ struct ServersideDepot {
const SPEEDTEST_TIMEOUT: Duration = Duration::from_secs(4);
impl Default for DepotManager {
fn default() -> Self {
Self::new()
}
}
impl DepotManager {
pub fn new() -> Self {
Self {
@@ -77,11 +83,7 @@ impl DepotManager {
}
let elapsed = start.elapsed().as_millis() as usize;
let speed = if elapsed == 0 {
usize::MAX
} else {
(total_length / elapsed) * 1000
};
let speed = total_length.checked_div(elapsed).unwrap_or(usize::MAX);
depot.latest_speed.replace(speed);
Ok(())
@@ -17,7 +17,7 @@ use crate::{
download_manager_frontend::DownloadStatus,
error::ApplicationDownloadError,
frontend_updates::{
DiskStatsUpdateEvent, DownloadStatsUpdateEvent, QueueUpdateEvent, QueueUpdateEventQueueData,
DownloadStatsUpdateEvent, QueueUpdateEvent, QueueUpdateEventQueueData,
},
};
@@ -80,3 +80,9 @@ impl From<io::Error> for ApplicationDownloadError {
ApplicationDownloadError::IoError(Arc::new(value))
}
}
impl From<RemoteAccessError> for ApplicationDownloadError {
fn from(value: RemoteAccessError) -> Self {
ApplicationDownloadError::Communication(value)
}
}
@@ -1,6 +1,6 @@
use std::{
sync::{
Arc, Mutex,
Arc, LazyLock, Mutex,
atomic::{AtomicUsize, Ordering},
},
time::Instant,
@@ -10,7 +10,7 @@ use atomic_instant_full::AtomicInstant;
use tokio::sync::mpsc::Sender;
use utils::{lock, send};
use crate::{download_manager_frontend::DownloadManagerSignal, util::progress_object};
use crate::download_manager_frontend::DownloadManagerSignal;
use super::rolling_progress_updates::RollingProgressWindow;
@@ -27,8 +27,6 @@ pub struct ProgressObject {
progress_instances: Arc<Mutex<Vec<Arc<AtomicUsize>>>>,
start: Arc<Mutex<Instant>>,
sender: Sender<DownloadManagerSignal>,
//last_update: Arc<RwLock<Instant>>,
last_update_time: Arc<AtomicInstant>,
bytes_last_update: Arc<AtomicUsize>,
rolling: RollingProgressWindow<1000>,
}
@@ -39,6 +37,8 @@ pub struct ProgressHandle {
progress_object: Arc<ProgressObject>,
}
static LAST_UPDATE_TIME: LazyLock<AtomicInstant> = LazyLock::new(AtomicInstant::now);
impl ProgressHandle {
pub fn new(progress: Arc<AtomicUsize>, progress_object: Arc<ProgressObject>) -> Self {
Self {
@@ -79,7 +79,6 @@ impl ProgressObject {
start: Arc::new(Mutex::new(Instant::now())),
sender,
last_update_time: Arc::new(AtomicInstant::now()),
bytes_last_update: Arc::new(AtomicUsize::new(0)),
rolling: RollingProgressWindow::new(),
progress_type,
@@ -125,7 +124,7 @@ impl ProgressObject {
}
pub fn spawn_update(progress: &Arc<ProgressObject>) {
let last_update_time = progress.last_update_time.load(Ordering::SeqCst);
let last_update_time = LAST_UPDATE_TIME.load(Ordering::SeqCst);
let time_since_last_update = Instant::now()
.duration_since(last_update_time)
.as_millis_f64();
@@ -136,9 +135,7 @@ pub fn spawn_update(progress: &Arc<ProgressObject>) {
}
pub async fn calculate_update(progress: Arc<ProgressObject>, time_since_last_update: f64) {
progress
.last_update_time
.swap(Instant::now(), Ordering::SeqCst);
LAST_UPDATE_TIME.swap(Instant::now(), Ordering::SeqCst);
let current_bytes_downloaded = progress.sum();
let max = progress.get_max();
@@ -4,6 +4,12 @@ pub struct SyncSemaphore {
inner: Arc<AtomicUsize>
}
impl Default for SyncSemaphore {
fn default() -> Self {
Self::new()
}
}
impl SyncSemaphore {
pub fn new() -> Self {
Self { inner: Arc::new(AtomicUsize::new(0)) }