diff --git a/src/project.rs b/src/project.rs index 4af689c..29f81e4 100644 --- a/src/project.rs +++ b/src/project.rs @@ -18,12 +18,15 @@ use serde::Deserialize; use serde_json::json; use serde_json::Value; use std::env; +use std::time::Duration; use std::{ collections::HashMap, fs, path::{Path, PathBuf}, }; +const DEPENDENCY_DOWNLOAD_ATTEMPTS: usize = 3; + #[derive(Debug, Deserialize, Hash, PartialEq, Eq, Clone, Copy, ValueEnum)] #[serde(rename_all = "lowercase")] pub enum ResourceType { @@ -180,6 +183,20 @@ fn find_existing_dependency(dep: &Dependency, _config: &Config) -> Result Result, String> { + let client = reqwest::blocking::Client::new(); + + Ok(client + .get(url) + .send() + .map_err(|x| format!("Failed to download dependency: {x}"))? + .error_for_status() + .map_err(|x| format!("Error downloading dependency: {x}"))? + .bytes() + .map_err(|x| format!("Failed to read dependency bytes: {x}"))? + .into()) +} + fn find_index_dependency(dep: &Dependency, config: &Config) -> Result { info!("Fetching dependency from index"); let found = index::get_mod_versions( @@ -199,23 +216,30 @@ fn find_index_dependency(dep: &Dependency, config: &Config) -> Result { + bytes = Some(b); + break; + } - if !result.status().is_success() { - return Err(format!( - "Failed to download dependency. Bad status code: {}", - result.status() - )); + Err(e) => { + warn!("Failed to download dependency: {e}"); + warn!("Waiting a second and trying again..."); + std::thread::sleep(Duration::from_secs(2)); + } + } } - let bytes = result - .bytes() - .map_err(|x| format!("Failed to parse dependency binary: {}", x))?; + let Some(bytes) = bytes else { + return Err(format!( + "Failed to download dependency after {} attempts", + DEPENDENCY_DOWNLOAD_ATTEMPTS + )); + }; info!("Success"); info!("Writing dependency to temp file"); diff --git a/src/sdk.rs b/src/sdk.rs index 0e40545..c51b1e7 100644 --- a/src/sdk.rs +++ b/src/sdk.rs @@ -15,6 +15,7 @@ use std::ffi::OsStr; use std::fs; use std::path::{Path, PathBuf}; use std::process::Command; +use std::time::Duration; #[cfg(target_os = "macos")] use crate::launchctl; @@ -25,6 +26,8 @@ use winreg::RegKey; use crate::confirm; use crate::{done, fail, fatal, info, warn, NiceUnwrap}; +const BINARIES_DOWNLOAD_ATTEMPTS: usize = 5; + #[derive(Deserialize)] struct GithubReleaseAsset { name: String, @@ -52,7 +55,14 @@ enum UserShell { } fn download_url(url: &str, file_name: &Path) -> Result<(), Box> { - let res = reqwest::blocking::get(url)?; + let client = reqwest::blocking::Client::new(); + + let res = client + .get(url) + .send()? + .error_for_status() + .map_err(|e| format!("server returned error: {e}"))?; + let mut file = fs::File::create(file_name)?; let mut content = std::io::Cursor::new(res.bytes()?); std::io::copy(&mut content, &mut file)?; @@ -657,16 +667,40 @@ fn install_binaries(config: &mut Config, platform: Option, version: Opti } } - if target_url.is_none() { + let Some(target_url) = target_url else { fatal!("No binaries found for current platform! ({platform})"); - } + }; fs::create_dir_all(&target_dir).nice_unwrap("Unable to create directory for binaries"); + let temp_zip = target_dir.join("temp.zip"); - info!("Downloading"); + let mut successful = false; + for i in 0..BINARIES_DOWNLOAD_ATTEMPTS { + if i == 0 { + info!("Downloading"); + } else { + info!("Downloading (attempt {})", i + 1); + } - let temp_zip = target_dir.join("temp.zip"); - download_url(&target_url.unwrap(), &temp_zip).nice_unwrap("Downloading binaries failed"); + match download_url(&target_url, &temp_zip) { + Ok(()) => { + successful = true; + break; + } + + Err(e) => { + warn!("Failed to download binaries, waiting and trying again: {e}"); + std::thread::sleep(Duration::from_secs(2)); + } + } + } + + if !successful { + fatal!( + "Failed to download binaries after {} attempts", + BINARIES_DOWNLOAD_ATTEMPTS + ); + } let file = fs::File::open(&temp_zip).nice_unwrap("Unable to read downloaded ZIP"); let mut zip = zip::ZipArchive::new(file).nice_unwrap("Downloaded ZIP appears to be corrupted");