From ccf603c81bd11864aabae5e98c9888854fe885cb Mon Sep 17 00:00:00 2001 From: Naz Date: Sun, 27 Jul 2025 14:42:21 +0100 Subject: =?UTF-8?q?=E2=9C=A8feat:=20add=20AppImage=20download=20with=20pro?= =?UTF-8?q?gress=20tracking?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib.rs | 2 ++ src/tui.rs | 14 ++++++++++++++ src/types.rs | 44 ++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 58 insertions(+), 2 deletions(-) create mode 100644 src/tui.rs (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 4604c31..5fa0a6b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,9 @@ mod args; +mod tui; mod types; pub use crate::args::*; +pub use crate::tui::*; pub use crate::types::*; use std::path::PathBuf; diff --git a/src/tui.rs b/src/tui.rs new file mode 100644 index 0000000..df3504d --- /dev/null +++ b/src/tui.rs @@ -0,0 +1,14 @@ +use indicatif::{ProgressBar, ProgressStyle}; + +pub fn make_progress_bar(size: u64) -> ProgressBar { + let bar = ProgressBar::new(size); + bar.set_style( + ProgressStyle::with_template( + "{elapsed_precise:.white.dim} {wide_bar:.cyan} {bytes}/{total_bytes} ({bytes_per_sec}, {eta})", + ) + .unwrap() + .progress_chars("█▉▊▋▌▍▎▏ "), + ); + + bar +} diff --git a/src/types.rs b/src/types.rs index 5636fe9..b20ada1 100644 --- a/src/types.rs +++ b/src/types.rs @@ -1,8 +1,9 @@ +use futures_util::StreamExt; use serde::Serialize; use std::path::PathBuf; -use tokio::fs; +use tokio::{fs, io::AsyncWriteExt}; -use crate::{index_dir}; +use crate::{appimages_dir, index_dir, make_progress_bar}; #[derive(Debug, Serialize)] pub struct AppImage { @@ -29,6 +30,45 @@ impl AppImage { let json = serde_json::to_string_pretty(self)?; fs::write(index_file, json).await?; + Ok(()) + } + pub async fn download_from_url(&self) -> Result<(), Box> { + fs::create_dir_all(&appimages_dir()).await?; + + // Try to extract filename from URL or use default + let url = &self.source.meta.url; + let filename = match url.split('/').next_back() { + Some(name) => name.to_string(), + None => format!("{}.AppImage", &self.executable), + }; + let file_path = &appimages_dir().join(filename); + + let resp = reqwest::get(&url.to_string()).await?; + let total_size = resp.content_length().unwrap_or(0); + + let bar = make_progress_bar(total_size); + let mut out = tokio::fs::File::create(&file_path).await?; + + // Stream download with progress updates + let mut stream = resp.bytes_stream(); + while let Some(chunk) = stream.next().await { + let chunk = chunk?; + let len = chunk.len() as u64; + out.write_all(&chunk).await?; + bar.inc(len); + } + + bar.finish_with_message("Download complete!"); + + // Make executable + #[cfg(unix)] + { + use std::os::unix::fs::PermissionsExt; + let mut perms = fs::metadata(&file_path).await?.permissions(); + perms.set_mode(0o755); + fs::set_permissions(&file_path, perms).await?; + } + Ok(()) } } -- cgit v1.2.3