Claude: Added download speed and estimated remaining time
This commit is contained in:
parent
6f90e4bf68
commit
b2fcbbffe1
@ -27,6 +27,8 @@ pub enum InstallerState {
|
||||
#[derive(Default)]
|
||||
pub struct DownloadState {
|
||||
pub progress: f32,
|
||||
pub speed: f64,
|
||||
pub estimated_remaining: std::time::Duration,
|
||||
pub completed: bool,
|
||||
pub files: Option<Vec<PathBuf>>,
|
||||
pub error: Option<String>,
|
||||
@ -38,6 +40,8 @@ pub struct SinfarInstallerApp<> {
|
||||
pub install_path: Option<PathBuf>,
|
||||
pub ee_exe_path: Option<PathBuf>,
|
||||
pub download_progress: f32,
|
||||
pub download_speed: f64,
|
||||
pub estimated_remaining: std::time::Duration,
|
||||
pub extraction_progress: f32,
|
||||
pub download_error: Option<String>,
|
||||
pub install_error: Option<String>,
|
||||
@ -47,13 +51,15 @@ pub struct SinfarInstallerApp<> {
|
||||
}
|
||||
|
||||
impl SinfarInstallerApp<> {
|
||||
pub fn new(cc: &eframe::CreationContext<>, runtime: Arc<tokio::runtime::Runtime>) -> Self {
|
||||
pub fn new(_cc: &eframe::CreationContext<>, runtime: Arc<tokio::runtime::Runtime>) -> Self {
|
||||
Self {
|
||||
state: InstallerState::GameSelection,
|
||||
game_type: Some(GameType::Diamond),
|
||||
install_path: None,
|
||||
ee_exe_path: None,
|
||||
download_progress: 0.0,
|
||||
download_speed: 0.0,
|
||||
estimated_remaining: std::time::Duration::new(0, 0),
|
||||
extraction_progress: 0.0,
|
||||
download_error: None,
|
||||
install_error: None,
|
||||
@ -91,14 +97,8 @@ impl<> eframe::App for SinfarInstallerApp<> {
|
||||
if self.state == InstallerState::Download {
|
||||
if let Ok(state) = self.download_state.lock() {
|
||||
self.download_progress = state.progress;
|
||||
|
||||
// if state.completed {
|
||||
// if let Some(files) = &state.files {
|
||||
// // Store the files for installation
|
||||
// //self.next_state(); // Proceed to installation
|
||||
// //self.start_installation();
|
||||
// }
|
||||
// }
|
||||
self.download_speed = state.speed;
|
||||
self.estimated_remaining = state.estimated_remaining;
|
||||
|
||||
if let Some(error) = &state.error {
|
||||
self.download_error = Some(error.clone());
|
||||
@ -178,12 +178,10 @@ impl<> eframe::App for SinfarInstallerApp<> {
|
||||
// Implementation of key installer functions
|
||||
impl SinfarInstallerApp<> {
|
||||
pub fn start_download(&mut self) {
|
||||
|
||||
// let temp_dir = std::env::temp_dir().join("sinfar_installer");
|
||||
// println!("{}", temp_dir.display())
|
||||
|
||||
// Reset progress and errors
|
||||
self.download_progress = 0.0;
|
||||
self.download_speed = 0.0;
|
||||
self.estimated_remaining = std::time::Duration::from_secs(0);
|
||||
self.download_error = None;
|
||||
|
||||
// Initialize download state
|
||||
@ -203,10 +201,12 @@ impl SinfarInstallerApp<> {
|
||||
// Create a download manager with progress callback
|
||||
let progress_state = download_state.clone();
|
||||
|
||||
let manager = DownloadManager::new(move |progress, _file| {
|
||||
let manager = DownloadManager::new(move |progress, _file, speed, remaining| {
|
||||
// Update progress through shared state
|
||||
if let Ok(mut state) = progress_state.lock() {
|
||||
state.progress = progress;
|
||||
state.speed = speed;
|
||||
state.estimated_remaining = remaining;
|
||||
repaint_ctx_progress.request_repaint();
|
||||
}
|
||||
});
|
||||
|
@ -9,20 +9,19 @@ use futures_util::StreamExt;
|
||||
use tokio::sync::Mutex;
|
||||
use std::fs::metadata;
|
||||
use reqwest::header::{HeaderMap, HeaderValue, RANGE, USER_AGENT};
|
||||
use log::{info, warn, error};
|
||||
use tokio::fs::File;
|
||||
use crate::app::{GameType};
|
||||
use log::{info, warn};
|
||||
use crate::app::GameType;
|
||||
|
||||
pub struct DownloadManager {
|
||||
client: Client,
|
||||
progress_callback: Arc<Mutex<Box<dyn Fn(f32, &str) + Send + Sync>>>,
|
||||
progress_callback: Arc<Mutex<Box<dyn Fn(f32, &str, f64, Duration) + Send + Sync>>>,
|
||||
temp_dir: PathBuf,
|
||||
}
|
||||
|
||||
impl DownloadManager {
|
||||
pub fn new<F>(progress_callback: F) -> Self
|
||||
where
|
||||
F: Fn(f32, &str) + Send + Sync + 'static
|
||||
F: Fn(f32, &str, f64, Duration) + Send + Sync + 'static
|
||||
{
|
||||
let client = Client::builder()
|
||||
.timeout(Duration::from_secs(1800))
|
||||
@ -45,6 +44,13 @@ impl DownloadManager {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_progress_callback<F>(&mut self, callback: F)
|
||||
where
|
||||
F: Fn(f32, &str, f64, Duration) + Send + Sync + 'static,
|
||||
{
|
||||
self.progress_callback = Arc::new(Mutex::new(Box::new(callback)));
|
||||
}
|
||||
|
||||
/// Downloads a file with resume capability and progress tracking
|
||||
pub async fn download_file(&self, url: &str, output_path: &Path) -> Result<()> {
|
||||
info!("Starting download of {} to {}", url, output_path.display());
|
||||
@ -126,6 +132,8 @@ impl DownloadManager {
|
||||
.unwrap_or("file");
|
||||
|
||||
let mut last_update = std::time::Instant::now();
|
||||
let mut last_downloaded_size = downloaded_size;
|
||||
let start_time = std::time::Instant::now();
|
||||
|
||||
while let Some(chunk_result) = stream.next().await {
|
||||
let chunk = chunk_result?;
|
||||
@ -138,10 +146,25 @@ impl DownloadManager {
|
||||
if now.duration_since(last_update) > Duration::from_millis(100) || content_length == downloaded_size {
|
||||
if content_length > 0 {
|
||||
let progress = downloaded_size as f32 / content_length as f32;
|
||||
|
||||
// Calculate speed in bytes per second
|
||||
let elapsed = now.duration_since(last_update).as_secs_f64();
|
||||
let bytes_since_last = downloaded_size - last_downloaded_size;
|
||||
let speed = bytes_since_last as f64 / elapsed;
|
||||
|
||||
// Calculate estimated time remaining
|
||||
let remaining_bytes = content_length - downloaded_size;
|
||||
let estimated_remaining = if speed > 0.0 {
|
||||
Duration::from_secs_f64(remaining_bytes as f64 / speed)
|
||||
} else {
|
||||
Duration::from_secs(0)
|
||||
};
|
||||
|
||||
let callback = progress_callback.lock().await;
|
||||
callback(progress, filename);
|
||||
callback(progress, filename, speed, estimated_remaining);
|
||||
}
|
||||
last_update = now;
|
||||
last_downloaded_size = downloaded_size;
|
||||
}
|
||||
}
|
||||
|
||||
@ -166,7 +189,7 @@ impl DownloadManager {
|
||||
} else {
|
||||
// File exists, update progress to 100%
|
||||
let callback = self.progress_callback.lock().await;
|
||||
callback(1.0, "sinfar_all_files_v30.7z");
|
||||
callback(1.0, "sinfar_all_files_v30.7z", 0.0, Duration::from_secs(0));
|
||||
}
|
||||
|
||||
downloaded_files.push(content_zip_path);
|
||||
@ -182,7 +205,7 @@ impl DownloadManager {
|
||||
).await?;
|
||||
} else {
|
||||
let callback = self.progress_callback.lock().await;
|
||||
callback(1.0, "sinfarx.exe");
|
||||
callback(1.0, "sinfarx.exe", 0.0, Duration::from_secs(0));
|
||||
}
|
||||
|
||||
downloaded_files.push(launcher_path);
|
||||
@ -199,7 +222,7 @@ impl DownloadManager {
|
||||
).await?;
|
||||
} else {
|
||||
let callback = self.progress_callback.lock().await;
|
||||
callback(1.0, "sinfarLauncher.zip");
|
||||
callback(1.0, "sinfarLauncher.zip", 0.0, Duration::from_secs(0));
|
||||
}
|
||||
|
||||
downloaded_files.push(launcher_zip_path);
|
||||
@ -216,7 +239,7 @@ impl DownloadManager {
|
||||
).await?;
|
||||
} else {
|
||||
let callback = self.progress_callback.lock().await;
|
||||
callback(1.0, "sinfarLauncher.zip");
|
||||
callback(1.0, "sinfarLauncher.zip", 0.0, Duration::from_secs(0));
|
||||
}
|
||||
|
||||
downloaded_files.push(launcher_zip_path);
|
||||
|
@ -1,5 +1,4 @@
|
||||
pub mod downloader;
|
||||
pub mod downloaderv2;
|
||||
pub mod extractor;
|
||||
pub mod validator;
|
||||
pub mod shortcut;
|
@ -1,14 +1,47 @@
|
||||
pub mod download_progress {
|
||||
use eframe::egui::{Ui, ProgressBar};
|
||||
use crate::app::SinfarInstallerApp;
|
||||
use std::time::Duration;
|
||||
|
||||
fn format_bytes(bytes: f64) -> String {
|
||||
const KB: f64 = 1024.0;
|
||||
const MB: f64 = KB * 1024.0;
|
||||
|
||||
if bytes >= MB {
|
||||
format!("{:.1} MB/s", bytes / MB)
|
||||
} else if bytes >= KB {
|
||||
format!("{:.1} KB/s", bytes / KB)
|
||||
} else {
|
||||
format!("{:.0} B/s", bytes)
|
||||
}
|
||||
}
|
||||
|
||||
fn format_duration(duration: Duration) -> String {
|
||||
let secs = duration.as_secs();
|
||||
if secs >= 3600 {
|
||||
format!("{:02}:{:02}:{:02} remaining", secs / 3600, (secs % 3600) / 60, secs % 60)
|
||||
} else {
|
||||
format!("{:02}:{:02} remaining", secs / 60, secs % 60)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(ui: &mut Ui, app: &mut SinfarInstallerApp) {
|
||||
ui.heading("Downloading Sinfar Custom Content");
|
||||
ui.add_space(10.0);
|
||||
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Downloading:");
|
||||
ui.add(ProgressBar::new(app.download_progress).show_percentage());
|
||||
ui.vertical(|ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label("Downloading:");
|
||||
ui.add(ProgressBar::new(app.download_progress).show_percentage());
|
||||
});
|
||||
|
||||
if app.download_progress > 0.0 && app.download_progress < 1.0 {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label(format_bytes(app.download_speed));
|
||||
ui.label(" • ");
|
||||
ui.label(format_duration(app.estimated_remaining));
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(error) = &app.download_error {
|
||||
|
Loading…
x
Reference in New Issue
Block a user