Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 37 additions & 13 deletions src/project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -180,6 +183,20 @@ fn find_existing_dependency(dep: &Dependency, _config: &Config) -> Result<Found,
}
}

fn download_index_dependency(url: &str) -> Result<Vec<u8>, 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<Found, String> {
info!("Fetching dependency from index");
let found = index::get_mod_versions(
Expand All @@ -199,23 +216,30 @@ fn find_index_dependency(dep: &Dependency, config: &Config) -> Result<Found, Str
info!("Dependency found: {}, version {}", dep.id, first.version);
info!("Downloading dependency");

let client = reqwest::blocking::Client::new();
// try to download multiple times

let result = client
.get(&first.download_link)
.send()
.map_err(|x| format!("Failed to download dependency: {}", x))?;
let mut bytes = None;
for _ in 0..DEPENDENCY_DOWNLOAD_ATTEMPTS {
match download_index_dependency(&first.download_link) {
Ok(b) => {
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");
Expand Down
46 changes: 40 additions & 6 deletions src/sdk.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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,
Expand Down Expand Up @@ -52,7 +55,14 @@ enum UserShell {
}

fn download_url(url: &str, file_name: &Path) -> Result<(), Box<dyn std::error::Error>> {
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)?;
Expand Down Expand Up @@ -657,16 +667,40 @@ fn install_binaries(config: &mut Config, platform: Option<String>, 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");
Expand Down