From 129259cb74a9199ddc06e987256a991ff948eb27 Mon Sep 17 00:00:00 2001 From: Lncvrt Date: Wed, 5 Nov 2025 12:12:53 -0700 Subject: [PATCH] Add ETA --- src-tauri/src/lib.rs | 18 ++++++++++++++++-- src/app/layout.tsx | 30 ++++++++++++++++++++++++++---- src/app/types/DownloadProgress.ts | 3 ++- 3 files changed, 44 insertions(+), 7 deletions(-) diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 477e05c..f20c109 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -2,6 +2,7 @@ use futures_util::stream::StreamExt; use sha2::{Digest, Sha512}; use std::fs; use std::path::Path; +use std::time::Instant; use std::{ fs::{File, create_dir_all}, io::{BufReader, copy}, @@ -135,6 +136,8 @@ async fn download( .await .unwrap(); + let start = Instant::now(); + while let Ok(Some(chunk_result)) = timeout(Duration::from_secs(5), stream.next()).await { let chunk = match chunk_result { Ok(c) => c, @@ -155,8 +158,19 @@ async fn download( 0.0 }; - app.emit("download-progress", format!("{}:{:.8}:{}", &name, progress, downloaded)) - .unwrap(); + let elapsed_secs = start.elapsed().as_secs_f64(); + let speed = downloaded as f64 / elapsed_secs; + let eta_secs = if total_size > downloaded { + (total_size - downloaded) as f64 / speed + } else { + 0.0 + }; + + app.emit( + "download-progress", + format!("{}:{:.8}:{}:{:.2}", &name, progress, downloaded, eta_secs), + ) + .unwrap(); } if total_size > 0 && downloaded < total_size { diff --git a/src/app/layout.tsx b/src/app/layout.tsx index c4c3dd4..8bb6d60 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -115,14 +115,21 @@ export default function RootLayout ({ let unlistenUninstalled: (() => void) | null = null listen('download-progress', event => { - const [versionName, progStr, totalSizeStr] = event.payload.split(':') + const [versionName, progStr, totalSizeStr, etaSecsStr] = + event.payload.split(':') const prog = Number(progStr) const progBytes = Number(totalSizeStr) + const etaSecs = Number(etaSecsStr) setDownloadProgress(prev => { const i = prev.findIndex(d => d.version === versionName) if (i === -1) return prev const copy = [...prev] - copy[i] = { ...copy[i], progress: prog, progressBytes: progBytes } + copy[i] = { + ...copy[i], + progress: prog, + progressBytes: progBytes, + etaSecs + } return copy }) }).then(f => (unlistenProgress = f)) @@ -271,7 +278,8 @@ export default function RootLayout ({ setSelectedVersionList([]) const newDownloads = list.map( - version => new DownloadProgress(version, 0, 0, false, true, false, false) + version => + new DownloadProgress(version, 0, 0, false, true, false, false, 0) ) setDownloadProgress(newDownloads) @@ -353,6 +361,20 @@ export default function RootLayout ({ return { installed, total } } + function formatEtaSmart (seconds: number) { + if (seconds < 60) return `${Math.floor(seconds)}s` + if (seconds < 3600) + return `${Math.floor(seconds / 60)}m ${Math.floor(seconds % 60)}s` + if (seconds < 86400) { + const h = Math.floor(seconds / 3600) + const m = Math.floor((seconds % 3600) / 60) + return `${h}h ${m}m` + } + const d = Math.floor(seconds / 86400) + const h = Math.floor((seconds % 86400) / 3600) + return `${d}d ${h}h` + } + return ( <> @@ -674,7 +696,7 @@ export default function RootLayout ({ maximumFractionDigits: 1 } )}{' '} - ({Math.floor(v.progress)}%) + (ETA: {formatEtaSmart(v.etaSecs)})