From 66a78912e31f5aa24a8c3dcbd4d0edbdc8abd745 Mon Sep 17 00:00:00 2001 From: "Rodrigo Rodriguez (Pragmatismo)" Date: Fri, 20 Feb 2026 12:58:59 -0300 Subject: [PATCH] update: sync for alm --- src/core/shared/utils.rs | 123 +++++++++++++++++++++++---------------- 1 file changed, 72 insertions(+), 51 deletions(-) diff --git a/src/core/shared/utils.rs b/src/core/shared/utils.rs index 3b2a8d69..e539ac45 100644 --- a/src/core/shared/utils.rs +++ b/src/core/shared/utils.rs @@ -180,63 +180,84 @@ pub fn to_array(value: Dynamic) -> Array { } } -#[cfg(feature = "progress-bars")] pub async fn download_file(url: &str, output_path: &str) -> Result<(), anyhow::Error> { use std::time::Duration; + use tokio::time::{sleep, timeout}; let url = url.to_string(); let output_path = output_path.to_string(); let download_handle = tokio::spawn(async move { - let client = Client::builder() - .user_agent("Mozilla/5.0 (compatible; BotServer/1.0)") - .connect_timeout(Duration::from_secs(30)) - .read_timeout(Duration::from_secs(300)) - .pool_idle_timeout(Duration::from_secs(90)) - .tcp_keepalive(Duration::from_secs(60)) - .build()?; - let response = client.get(&url).send().await?; - if response.status().is_success() { - let total_size = response.content_length().unwrap_or(0); - let pb = ProgressBar::new(total_size); - pb.set_style(ProgressStyle::default_bar() - .template("{msg}\n{spinner:.green} [{elapsed_precise}] [{bar:40.cyan/blue}] {bytes}/{total_bytes} ({eta})") - .unwrap_or(ProgressStyle::default_bar()) - .progress_chars("#>-")); - pb.set_message(format!("Downloading {}", url)); - let mut file = TokioFile::create(&output_path).await?; - let bytes = response.bytes().await?; - file.write_all(&bytes).await?; - pb.set_position(bytes.len() as u64); - pb.finish_with_message(format!("Downloaded {}", output_path)); - Ok(()) - } else { - Err(anyhow::anyhow!("HTTP {}: {}", response.status(), url)) - } - }); - download_handle.await? -} - -#[cfg(not(feature = "progress-bars"))] -pub async fn download_file(url: &str, output_path: &str) -> Result<(), anyhow::Error> { - use std::time::Duration; - let url = url.to_string(); - let output_path = output_path.to_string(); - let download_handle = tokio::spawn(async move { - let client = Client::builder() - .user_agent("Mozilla/5.0 (compatible; BotServer/1.0)") - .connect_timeout(Duration::from_secs(30)) - .read_timeout(Duration::from_secs(300)) - .pool_idle_timeout(Duration::from_secs(90)) - .tcp_keepalive(Duration::from_secs(60)) - .build()?; - let response = client.get(&url).send().await?; - if response.status().is_success() { - let mut file = TokioFile::create(&output_path).await?; - let bytes = response.bytes().await?; - file.write_all(&bytes).await?; - Ok(()) - } else { - Err(anyhow::anyhow!("HTTP {}: {}", response.status(), url)) + let max_retries = 3; + for attempt in 1..=max_retries { + let client = Client::builder() + .user_agent("Mozilla/5.0 (compatible; BotServer/1.0)") + .connect_timeout(Duration::from_secs(30)) + .read_timeout(Duration::from_secs(60)) + .pool_idle_timeout(Duration::from_secs(90)) + .tcp_keepalive(Duration::from_secs(60)) + .build()?; + match client.get(&url).send().await { + Ok(mut response) if response.status().is_success() => { + let total_size = response.content_length(); + if let Ok(mut file) = TokioFile::create(&output_path).await { + let mut downloaded: u64 = 0; + let mut last_percent = 0; + let mut success = true; + loop { + match timeout(Duration::from_secs(30), response.chunk()).await { + Ok(Ok(Some(chunk))) => { + if file.write_all(&chunk).await.is_err() { + success = false; + break; + } + downloaded += chunk.len() as u64; + if let Some(total) = total_size { + let percent = (downloaded as f64 / total as f64 * 100.0) as u64; + if percent > last_percent && percent % 10 == 0 { + println!("Downloading {}: {}%", url, percent); + last_percent = percent; + } + } + } + Ok(Ok(None)) => break, + Ok(Err(e)) => { + log::warn!("Chunk error: {}", e); + success = false; + break; + } + Err(_) => { + log::warn!("Timeout reading chunk"); + success = false; + break; + } + } + } + if success { + let check_total = total_size.unwrap_or(downloaded); + if downloaded >= check_total { + println!("Downloaded {}", output_path); + return Ok(()); + } + } + } + } + Ok(response) => { + if attempt == max_retries { + return Err(anyhow::anyhow!("HTTP {}: {}", response.status(), url)); + } + } + Err(e) => { + log::warn!("Request failed: {}", e); + if attempt == max_retries { + return Err(anyhow::anyhow!("Request failed: {} - {}", url, e)); + } + } + } + if attempt < max_retries { + println!("Timeout/Error downloading {}, retrying attempt {}/{}...", url, attempt + 1, max_retries); + sleep(Duration::from_secs(5)).await; + } } + Err(anyhow::anyhow!("Failed to download {} after {} attempts", url, max_retries)) }); download_handle.await? }