This commit is contained in:
2025-11-05 12:12:53 -07:00
parent 1dfeb0be93
commit 129259cb74
3 changed files with 44 additions and 7 deletions

View File

@@ -2,6 +2,7 @@ use futures_util::stream::StreamExt;
use sha2::{Digest, Sha512}; use sha2::{Digest, Sha512};
use std::fs; use std::fs;
use std::path::Path; use std::path::Path;
use std::time::Instant;
use std::{ use std::{
fs::{File, create_dir_all}, fs::{File, create_dir_all},
io::{BufReader, copy}, io::{BufReader, copy},
@@ -135,6 +136,8 @@ async fn download(
.await .await
.unwrap(); .unwrap();
let start = Instant::now();
while let Ok(Some(chunk_result)) = timeout(Duration::from_secs(5), stream.next()).await { while let Ok(Some(chunk_result)) = timeout(Duration::from_secs(5), stream.next()).await {
let chunk = match chunk_result { let chunk = match chunk_result {
Ok(c) => c, Ok(c) => c,
@@ -155,7 +158,18 @@ async fn download(
0.0 0.0
}; };
app.emit("download-progress", format!("{}:{:.8}:{}", &name, progress, downloaded)) 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(); .unwrap();
} }

View File

@@ -115,14 +115,21 @@ export default function RootLayout ({
let unlistenUninstalled: (() => void) | null = null let unlistenUninstalled: (() => void) | null = null
listen<string>('download-progress', event => { listen<string>('download-progress', event => {
const [versionName, progStr, totalSizeStr] = event.payload.split(':') const [versionName, progStr, totalSizeStr, etaSecsStr] =
event.payload.split(':')
const prog = Number(progStr) const prog = Number(progStr)
const progBytes = Number(totalSizeStr) const progBytes = Number(totalSizeStr)
const etaSecs = Number(etaSecsStr)
setDownloadProgress(prev => { setDownloadProgress(prev => {
const i = prev.findIndex(d => d.version === versionName) const i = prev.findIndex(d => d.version === versionName)
if (i === -1) return prev if (i === -1) return prev
const copy = [...prev] const copy = [...prev]
copy[i] = { ...copy[i], progress: prog, progressBytes: progBytes } copy[i] = {
...copy[i],
progress: prog,
progressBytes: progBytes,
etaSecs
}
return copy return copy
}) })
}).then(f => (unlistenProgress = f)) }).then(f => (unlistenProgress = f))
@@ -271,7 +278,8 @@ export default function RootLayout ({
setSelectedVersionList([]) setSelectedVersionList([])
const newDownloads = list.map( 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) setDownloadProgress(newDownloads)
@@ -353,6 +361,20 @@ export default function RootLayout ({
return { installed, total } 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 ( return (
<> <>
<html lang='en' className={roboto.className}> <html lang='en' className={roboto.className}>
@@ -674,7 +696,7 @@ export default function RootLayout ({
maximumFractionDigits: 1 maximumFractionDigits: 1
} }
)}{' '} )}{' '}
({Math.floor(v.progress)}%) (ETA: {formatEtaSmart(v.etaSecs)})
</span> </span>
<ProgressBar <ProgressBar
progress={v.progress} progress={v.progress}

View File

@@ -6,6 +6,7 @@ export class DownloadProgress {
public failed: boolean, public failed: boolean,
public queued: boolean, public queued: boolean,
public hash_checking: boolean, public hash_checking: boolean,
public finishing: boolean public finishing: boolean,
public etaSecs: number
) { } ) { }
} }