mirror of
https://github.com/Drop-OSS/drop-app.git
synced 2025-11-10 04:22:13 +10:00
chore: Progress on rolling progress window
This commit is contained in:
7
src-tauri/Cargo.lock
generated
7
src-tauri/Cargo.lock
generated
@ -255,6 +255,12 @@ dependencies = [
|
||||
"system-deps",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "atomic-instant-full"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db6541700e074cda41b1c6f98c2cae6cde819967bf142078f069cad85387cdbe"
|
||||
|
||||
[[package]]
|
||||
name = "atomic-waker"
|
||||
version = "1.1.2"
|
||||
@ -1033,6 +1039,7 @@ dependencies = [
|
||||
name = "drop-app"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"atomic-instant-full",
|
||||
"boxcar",
|
||||
"chrono",
|
||||
"derive_builder",
|
||||
|
||||
@ -52,6 +52,7 @@ throttle_my_fn = "0.2.6"
|
||||
parking_lot = "0.12.3"
|
||||
merge-struct = "0.1.0"
|
||||
serde_merge = "0.1.3"
|
||||
atomic-instant-full = "0.1.0"
|
||||
|
||||
[dependencies.tauri]
|
||||
version = "2.1.1"
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
use log::{debug, info};
|
||||
use log::{debug, error};
|
||||
use tauri::AppHandle;
|
||||
|
||||
use crate::AppState;
|
||||
@ -12,7 +12,12 @@ pub fn cleanup_and_exit(app: &AppHandle, state: &tauri::State<'_, std::sync::Mut
|
||||
debug!("Cleaning up and exiting application");
|
||||
let download_manager = state.lock().unwrap().download_manager.clone();
|
||||
match download_manager.ensure_terminated() {
|
||||
Ok(_) => {},
|
||||
Ok(res) => {
|
||||
match res {
|
||||
Ok(_) => debug!("Download manager terminated correctly"),
|
||||
Err(_) => error!("Download manager failed to terminate correctly"),
|
||||
}
|
||||
},
|
||||
Err(e) => panic!("{:?}", e),
|
||||
}
|
||||
|
||||
|
||||
@ -7,10 +7,11 @@ use std::{
|
||||
time::{Duration, Instant},
|
||||
};
|
||||
|
||||
use atomic_instant_full::AtomicInstant;
|
||||
use log::info;
|
||||
use throttle_my_fn::throttle;
|
||||
|
||||
use super::download_manager::DownloadManagerSignal;
|
||||
use super::{download_manager::DownloadManagerSignal, rolling_progress_updates::RollingProgressWindow};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ProgressObject {
|
||||
@ -20,8 +21,10 @@ pub struct ProgressObject {
|
||||
sender: Sender<DownloadManagerSignal>,
|
||||
points_towards_update: Arc<AtomicUsize>,
|
||||
points_to_push_update: Arc<AtomicUsize>,
|
||||
last_update: Arc<RwLock<Instant>>,
|
||||
amount_last_update: Arc<AtomicUsize>,
|
||||
//last_update: Arc<RwLock<Instant>>,
|
||||
last_update_time: Arc<AtomicInstant>,
|
||||
bytes_last_update: Arc<AtomicUsize>,
|
||||
rolling: RollingProgressWindow<128>
|
||||
}
|
||||
|
||||
pub struct ProgressHandle {
|
||||
@ -42,7 +45,7 @@ impl ProgressHandle {
|
||||
pub fn add(&self, amount: usize) {
|
||||
self.progress
|
||||
.fetch_add(amount, std::sync::atomic::Ordering::Relaxed);
|
||||
self.progress_object.check_push_update(amount);
|
||||
push_update(&self.progress_object, amount);
|
||||
}
|
||||
}
|
||||
|
||||
@ -61,50 +64,13 @@ impl ProgressObject {
|
||||
|
||||
points_towards_update: Arc::new(AtomicUsize::new(0)),
|
||||
points_to_push_update: Arc::new(AtomicUsize::new(points_to_push_update)),
|
||||
last_update: Arc::new(RwLock::new(Instant::now())),
|
||||
amount_last_update: Arc::new(AtomicUsize::new(0)),
|
||||
last_update_time: Arc::new(AtomicInstant::now()),
|
||||
bytes_last_update: Arc::new(AtomicUsize::new(0)),
|
||||
rolling: RollingProgressWindow::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn check_push_update(&self, amount_added: usize) {
|
||||
let current_amount = self
|
||||
.points_towards_update
|
||||
.fetch_add(amount_added, Ordering::Relaxed);
|
||||
|
||||
let to_update = self.points_to_push_update.fetch_add(0, Ordering::Relaxed);
|
||||
|
||||
if current_amount >= to_update {
|
||||
self.points_towards_update
|
||||
.fetch_sub(to_update, Ordering::Relaxed);
|
||||
update_queue(self);
|
||||
}
|
||||
|
||||
let last_update = self.last_update.read().unwrap();
|
||||
let last_update_difference = Instant::now().duration_since(*last_update).as_millis();
|
||||
if last_update_difference > 1000 {
|
||||
// push update
|
||||
drop(last_update);
|
||||
let mut last_update = self.last_update.write().unwrap();
|
||||
*last_update = Instant::now();
|
||||
drop(last_update);
|
||||
|
||||
let current_amount = self.sum();
|
||||
let max = self.get_max();
|
||||
let amount_at_last_update = self.amount_last_update.fetch_add(0, Ordering::Relaxed);
|
||||
self.amount_last_update
|
||||
.store(current_amount, Ordering::Relaxed);
|
||||
|
||||
let amount_since_last_update = current_amount - amount_at_last_update;
|
||||
|
||||
let kilobytes_per_second =
|
||||
amount_since_last_update / (last_update_difference as usize).max(1);
|
||||
|
||||
let remaining = max - current_amount; // bytes
|
||||
let time_remaining = (remaining / 1000) / kilobytes_per_second.max(1);
|
||||
|
||||
update_ui(self, kilobytes_per_second, time_remaining);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub fn set_time_now(&self) {
|
||||
*self.start.lock().unwrap() = Instant::now();
|
||||
@ -136,23 +102,48 @@ impl ProgressObject {
|
||||
pub fn get(&self, index: usize) -> Arc<AtomicUsize> {
|
||||
self.progress_instances.lock().unwrap()[index].clone()
|
||||
}
|
||||
fn update_window(&self, kilobytes_per_second: usize) {
|
||||
self.rolling.update(kilobytes_per_second);
|
||||
}
|
||||
}
|
||||
|
||||
#[throttle(50, Duration::from_secs(1))]
|
||||
#[throttle(1, Duration::from_millis(100))]
|
||||
fn update_ui(progress_object: &ProgressObject, kilobytes_per_second: usize, time_remaining: usize) {
|
||||
progress_object
|
||||
.sender
|
||||
.send(DownloadManagerSignal::UpdateUIStats(
|
||||
kilobytes_per_second,
|
||||
progress_object.rolling.get_average(),
|
||||
time_remaining,
|
||||
))
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[throttle(50, Duration::from_secs(1))]
|
||||
#[throttle(1, Duration::from_millis(100))]
|
||||
fn update_queue(progress: &ProgressObject) {
|
||||
progress
|
||||
.sender
|
||||
.send(DownloadManagerSignal::UpdateUIQueue)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[throttle(1, Duration::from_millis(20))]
|
||||
pub fn push_update(progress: &ProgressObject, amount_added: usize) {
|
||||
let last_update_time = progress.last_update_time.swap(Instant::now(), Ordering::SeqCst);
|
||||
let time_since_last_update = Instant::now().duration_since(last_update_time).as_millis();
|
||||
|
||||
let current_bytes_downloaded = progress.sum();
|
||||
let max = progress.get_max();
|
||||
let bytes_at_last_update = progress.bytes_last_update.swap(current_bytes_downloaded, Ordering::Relaxed);
|
||||
|
||||
let bytes_since_last_update = current_bytes_downloaded - bytes_at_last_update;
|
||||
|
||||
let kilobytes_per_second =
|
||||
bytes_since_last_update / (time_since_last_update as usize).max(1);
|
||||
|
||||
let bytes_remaining = max - current_bytes_downloaded; // bytes
|
||||
let time_remaining = (bytes_remaining / 1000) / kilobytes_per_second.max(1);
|
||||
|
||||
progress.update_window(kilobytes_per_second);
|
||||
|
||||
update_ui(progress, kilobytes_per_second, time_remaining);
|
||||
}
|
||||
@ -9,12 +9,18 @@ pub struct RollingProgressWindow<const S: usize> {
|
||||
current: Arc<AtomicUsize>,
|
||||
}
|
||||
impl<const S: usize> RollingProgressWindow<S> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
window: Arc::new([(); S].map(|_| AtomicUsize::new(0))),
|
||||
current: Arc::new(AtomicUsize::new(0))
|
||||
}
|
||||
}
|
||||
pub fn update(&self, kilobytes_per_second: usize) {
|
||||
let index = self.current.fetch_add(1, Ordering::SeqCst);
|
||||
let current = &self.window[index % S];
|
||||
current.store(kilobytes_per_second, Ordering::Release);
|
||||
}
|
||||
pub fn get_average(&self) -> usize {
|
||||
self.window.iter().map(|x| x.load(Ordering::Relaxed)).sum()
|
||||
self.window.iter().map(|x| x.load(Ordering::Relaxed)).sum::<usize>() / S
|
||||
}
|
||||
}
|
||||
|
||||
@ -45,6 +45,7 @@ use remote::commands::{
|
||||
auth_initiate, gen_drop_url, manual_recieve_handshake, retry_connect, sign_out, use_remote,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use tauri::ipc::IpcResponse;
|
||||
use std::path::Path;
|
||||
use std::sync::Arc;
|
||||
use std::{
|
||||
@ -136,7 +137,7 @@ fn setup(handle: AppHandle) -> AppState<'static> {
|
||||
debug!("Database is set up");
|
||||
|
||||
// TODO: Account for possible failure
|
||||
let (app_status, user) = auth::setup().unwrap();
|
||||
let (app_status, user) = auth::setup();
|
||||
|
||||
let db_handle = DB.borrow_data().unwrap();
|
||||
let mut missing_games = Vec::new();
|
||||
@ -315,7 +316,7 @@ pub fn run() {
|
||||
app.webview_windows().get("main").unwrap().show().unwrap();
|
||||
}
|
||||
"quit" => {
|
||||
cleanup_and_exit(app, &state);
|
||||
cleanup_and_exit(app, &app.state());
|
||||
}
|
||||
|
||||
_ => {
|
||||
|
||||
@ -180,15 +180,19 @@ pub fn auth_initiate_logic() -> Result<(), RemoteAccessError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn setup() -> Result<(AppStatus, Option<User>), RemoteAccessError> {
|
||||
pub fn setup() -> (AppStatus, Option<User>) {
|
||||
let data = DB.borrow_data().unwrap();
|
||||
let auth = data.auth.clone();
|
||||
drop(data);
|
||||
|
||||
if auth.is_some() {
|
||||
let user_result = fetch_user()?;
|
||||
return Ok((AppStatus::SignedIn, Some(user_result)));
|
||||
let user_result = match fetch_user() {
|
||||
Ok(data) => data,
|
||||
Err(RemoteAccessError::FetchError(_)) => return (AppStatus::ServerUnavailable, None),
|
||||
Err(_) => return (AppStatus::SignedInNeedsReauth, None),
|
||||
};
|
||||
return (AppStatus::SignedIn, Some(user_result));
|
||||
}
|
||||
|
||||
Ok((AppStatus::SignedOut, None))
|
||||
(AppStatus::SignedOut, None)
|
||||
}
|
||||
|
||||
@ -57,14 +57,13 @@ pub fn sign_out(app: AppHandle) {
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn retry_connect(state: tauri::State<'_, Mutex<AppState>>) -> UserValue<(), RemoteAccessError> {
|
||||
let (app_status, user) = setup()?;
|
||||
pub fn retry_connect(state: tauri::State<'_, Mutex<AppState>>) {
|
||||
let (app_status, user) = setup();
|
||||
|
||||
let mut guard = state.lock().unwrap();
|
||||
guard.status = app_status;
|
||||
guard.user = user;
|
||||
drop(guard);
|
||||
UserValue::Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
|
||||
Reference in New Issue
Block a user