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
4 changes: 2 additions & 2 deletions src-tauri/src/instance/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -949,8 +949,8 @@ pub async fn create_instance(
.ok_or(InstanceError::ClientJsonParseError)?;

task_params.push(PTaskParam::Download(DownloadParam {
src: Url::parse(&client_download_info.url.clone())
.map_err(|_| InstanceError::ClientJsonParseError)?,
src: vec![Url::parse(&client_download_info.url.clone())
.map_err(|_| InstanceError::ClientJsonParseError)?],
dest: instance.version_path.join(format!("{}.jar", name)),
filename: None,
sha1: Some(client_download_info.sha1.clone()),
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/src/instance/helpers/loader/fabric.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ pub async fn install_fabric_loader(
&priority[0],
)?;
task_params.push(PTaskParam::Download(DownloadParam {
src,
src: vec![src],
dest: lib_dir.join(&rel),
filename: None,
sha1: None,
Expand Down
14 changes: 7 additions & 7 deletions src-tauri/src/instance/helpers/loader/forge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ pub async fn install_forge_loader(
let installer_path = lib_dir.join(&installer_rel);

task_params.push(PTaskParam::Download(DownloadParam {
src: installer_url,
src: vec![installer_url],
dest: installer_path.clone(),
filename: None,
sha1: None,
Expand Down Expand Up @@ -218,7 +218,7 @@ pub async fn download_forge_libraries(
if let Some(mojmaps) = args_map.get("{MOJMAPS}") {
if let Some(client_mappings) = client_info.downloads.get("client_mappings") {
task_params.push(PTaskParam::Download(DownloadParam {
src: client_mappings.url.parse()?,
src: vec![client_mappings.url.parse()?],
dest: lib_dir.join(mojmaps),
filename: None,
sha1: Some(client_mappings.sha1.clone()),
Expand Down Expand Up @@ -289,15 +289,15 @@ pub async fn download_forge_libraries(
}

task_params.push(PTaskParam::Download(DownloadParam {
src: convert_url_to_target_source(
src: vec![convert_url_to_target_source(
&Url::parse(url)?,
&[
ResourceType::ForgeMaven,
ResourceType::ForgeMavenNew,
ResourceType::Libraries,
],
&priority[0],
)?,
)?],
dest: lib_dir.join(&convert_library_name_to_path(name, None)?),
filename: None,
sha1: None,
Expand Down Expand Up @@ -345,15 +345,15 @@ pub async fn download_forge_libraries(

let rel = convert_library_name_to_path(&name.to_string(), None)?;
task_params.push(PTaskParam::Download(DownloadParam {
src: convert_url_to_target_source(
src: vec![convert_url_to_target_source(
&Url::parse(url)?,
&[
ResourceType::ForgeMaven,
ResourceType::ForgeMavenNew,
ResourceType::Libraries,
],
&priority[0],
)?,
)?],
dest: lib_dir.join(&rel),
filename: None,
sha1: None,
Expand Down Expand Up @@ -425,7 +425,7 @@ pub async fn download_forge_libraries(
&priority[0],
)?;
task_params.push(PTaskParam::Download(DownloadParam {
src,
src: vec![src],
dest: lib_dir.join(&rel),
filename: None,
sha1: None,
Expand Down
12 changes: 6 additions & 6 deletions src-tauri/src/instance/helpers/loader/neoforge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ pub async fn install_neoforge_loader(
let installer_path = lib_dir.join(&installer_rel);

task_params.push(PTaskParam::Download(DownloadParam {
src: installer_url,
src: vec![installer_url],
dest: installer_path.clone(),
filename: None,
sha1: None,
Expand Down Expand Up @@ -198,7 +198,7 @@ pub async fn download_neoforge_libraries(
if let Some(mojmaps) = args_map.get("{MOJMAPS}") {
if let Some(client_mappings) = client_info.downloads.get("client_mappings") {
task_params.push(PTaskParam::Download(DownloadParam {
src: client_mappings.url.parse()?,
src: vec![client_mappings.url.parse()?],
dest: lib_dir.join(mojmaps),
filename: None,
sha1: Some(client_mappings.sha1.clone()),
Expand Down Expand Up @@ -269,11 +269,11 @@ pub async fn download_neoforge_libraries(
}

task_params.push(PTaskParam::Download(DownloadParam {
src: convert_url_to_target_source(
src: vec![convert_url_to_target_source(
&Url::parse(url)?,
&[ResourceType::NeoforgeMaven, ResourceType::Libraries],
&priority[0],
)?,
)?],
dest: lib_dir.join(&convert_library_name_to_path(name, None)?),
filename: None,
sha1: None,
Expand Down Expand Up @@ -317,11 +317,11 @@ pub async fn download_neoforge_libraries(

let rel = convert_library_name_to_path(&name.to_string(), None)?;
task_params.push(PTaskParam::Download(DownloadParam {
src: convert_url_to_target_source(
src: vec![convert_url_to_target_source(
&Url::parse(url)?,
&[ResourceType::NeoforgeMaven, ResourceType::Libraries],
&priority[0],
)?,
)?],
dest: lib_dir.join(&rel),
filename: None,
sha1: None,
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/src/instance/helpers/modpack/curseforge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ impl ModpackManifest for CurseForgeManifest {
.map(|h| h.value.clone());

let task_param = PTaskParam::Download(DownloadParam {
src: url::Url::parse(&download_url).map_err(|_| InstanceError::InvalidSourcePath)?,
src: vec![url::Url::parse(&download_url).map_err(|_| InstanceError::InvalidSourcePath)?],
sha1,
dest: instance_path
.join(match class_id {
Expand Down
12 changes: 8 additions & 4 deletions src-tauri/src/instance/helpers/modpack/modrinth.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,12 +108,16 @@ impl ModpackManifest for ModrinthManifest {
.files
.iter()
.map(|file| {
let download_url = file
let urls = file
.downloads
.first()
.ok_or(InstanceError::InvalidSourcePath)?;
.iter()
.filter_map(|u| url::Url::parse(u).ok())
.collect::<Vec<_>>();
if urls.is_empty() {
return Err(InstanceError::InvalidSourcePath.into());
}
Ok(PTaskParam::Download(DownloadParam {
src: url::Url::parse(download_url).map_err(|_| InstanceError::InvalidSourcePath)?,
src: urls,
sha1: Some(file.hashes.sha1.clone()),
dest: instance_path.join(&file.path),
filename: None,
Expand Down
4 changes: 2 additions & 2 deletions src-tauri/src/launch/helpers/file_validator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ pub async fn get_invalid_library_files(
&source,
)?;
Ok(Some(PTaskParam::Download(DownloadParam {
src,
src: vec![src],
dest: file_path,
filename: None,
sha1: Some(artifact.sha1.clone()),
Expand Down Expand Up @@ -339,7 +339,7 @@ pub async fn get_invalid_assets(
.join(&path_in_repo)
.map_err(crate::error::SJMCLError::from)?;
Ok(Some(PTaskParam::Download(DownloadParam {
src,
src: vec![src],
dest,
filename: None,
sha1: Some(item.hash.clone()),
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/src/launcher_config/helpers/java.rs
Original file line number Diff line number Diff line change
Expand Up @@ -514,7 +514,7 @@ pub async fn build_mojang_java_download_params(
let (url, sha1) = (raw["url"].as_str()?, raw["sha1"].as_str()?);

Some(PTaskParam::Download(DownloadParam {
src: url.parse().ok()?,
src: vec![url.parse().ok()?],
dest: runtime_dir.join(path),
filename: None,
sha1: Some(sha1.into()),
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/src/launcher_config/helpers/updater.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ pub async fn download_target_version(
app.clone(),
format!("launcher-update?{}", fname),
vec![PTaskParam::Download(DownloadParam {
src: url::Url::parse(&url).map_err(|_| LauncherConfigError::FetchError)?,
src: vec![url::Url::parse(&url).map_err(|_| LauncherConfigError::FetchError)?],
dest: download_cache_dir.join(&fname),
filename: Some(fname),
sha1: None,
Expand Down
4 changes: 2 additions & 2 deletions src-tauri/src/resource/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ pub async fn download_game_server(
app,
format!("game-server?{}", resource_info.id),
vec![PTaskParam::Download(DownloadParam {
src: url::Url::parse(&download_info.url.clone()).map_err(|_| ResourceError::ParseError)?,
src: vec![url::Url::parse(&download_info.url.clone()).map_err(|_| ResourceError::ParseError)?],
dest: dest.clone().into(),
filename: None,
sha1: Some(download_info.sha1.clone()),
Expand Down Expand Up @@ -184,7 +184,7 @@ pub async fn update_mods(
for query in &queries {
let file_path = mods_dir.join(&query.file_name);
let download_param = DownloadParam {
src: url::Url::parse(&query.url).map_err(|_| ResourceError::ParseError)?,
src: vec![url::Url::parse(&query.url).map_err(|_| ResourceError::ParseError)?],
dest: file_path,
filename: None,
sha1: Some(query.sha1.clone()),
Expand Down
2 changes: 1 addition & 1 deletion src-tauri/src/resource/helpers/modrinth/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ pub async fn get_latest_fabric_api_mod_download(
let dest_path = mods_dir.join(&filename);

Ok(Some(DownloadParam {
src: download_url,
src: vec![download_url],
dest: dest_path,
filename: Some(filename),
sha1: Some(latest_file.sha1.clone()),
Expand Down
107 changes: 71 additions & 36 deletions src-tauri/src/tasks/download.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use crate::tasks::streams::reporter::Reporter;
use crate::tasks::streams::ProgressStream;
use crate::tasks::*;
use crate::utils::fs::validate_sha1;
use crate::utils::web::with_retry;
use async_speed_limit::Limiter;
use futures::stream::TryStreamExt;
use futures::StreamExt;
Expand All @@ -25,7 +24,7 @@ use tokio_util::compat::FuturesAsyncReadCompatExt;
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(rename_all = "camelCase")]
pub struct DownloadParam {
pub src: Url,
pub src: Vec<Url>,
pub dest: PathBuf,
pub filename: Option<String>,
pub sha1: Option<String>,
Expand Down Expand Up @@ -122,15 +121,15 @@ impl DownloadTask {
async fn send_request(
app_handle: &AppHandle,
current: i64,
param: &DownloadParam,
src: Url,
) -> SJMCLResult<reqwest::Response> {
let state = app_handle.state::<reqwest::Client>();
let client = with_retry(state.inner().clone());
let client = state.inner().clone();
let request = if current == 0 {
client.get(param.src.clone())
client.get(src.clone())
} else {
client
.get(param.src.clone())
.get(src.clone())
.header(RANGE, format!("bytes={current}-"))
};

Expand All @@ -149,14 +148,17 @@ impl DownloadTask {
async fn create_resp_stream(
app_handle: &AppHandle,
current: i64,
param: &DownloadParam,
src: Url,
) -> SJMCLResult<(
impl Stream<Item = Result<bytes::Bytes, std::io::Error>> + Send,
i64,
)> {
let resp = Self::send_request(app_handle, current, param).await?;
let resp = Self::send_request(app_handle, current, src.clone()).await?;
let total_progress = if current == 0 {
resp.content_length().unwrap() as i64
match resp.content_length() {
Some(len) => len as i64,
None => -1,
}
} else {
-1
};
Expand All @@ -177,42 +179,75 @@ impl DownloadTask {
impl Future<Output = SJMCLResult<()>> + Send,
Arc<RwLock<PTaskHandle>>,
)> {
let current = self.p_handle.desc.current;
let handle = Arc::new(RwLock::new(self.p_handle));
let task_handle = handle.clone();
let param = self.param.clone();
Ok((
async move {
let (resp, total_progress) = Self::create_resp_stream(&app_handle, current, &param).await?;
let stream = ProgressStream::new(resp, task_handle.clone());
tokio::fs::create_dir_all(&self.dest_path.parent().unwrap()).await?;
let mut file = if current == 0 {
tokio::fs::File::create(&self.dest_path).await?
} else {
let mut f = tokio::fs::OpenOptions::new().open(&self.dest_path).await?;
f.seek(std::io::SeekFrom::Start(current as u64)).await?;
f
};
{
let mut task_handle = task_handle.write().unwrap();
task_handle.set_total(total_progress);
task_handle.mark_started();
}
if let Some(lim) = limiter {
tokio::io::copy(&mut lim.limit(stream.into_async_read()).compat(), &mut file).await?;
} else {
tokio::io::copy(&mut stream.into_async_read().compat(), &mut file).await?;
let mut last_err: Option<SJMCLError> = None;
if param.src.is_empty() {
return Err(SJMCLError("No download sources provided".into()));
}
drop(file);
if task_handle.read().unwrap().status().is_cancelled() {
tokio::fs::remove_file(&self.dest_path).await?;
Ok(())
} else {
match param.sha1 {
Some(truth) => validate_sha1(param.dest, truth),
None => Ok(()),
for src in param.src.clone() {
let attempt = async {
let current = task_handle.read().unwrap().desc.current;
let (resp, total_progress) =
Self::create_resp_stream(&app_handle, current, src).await?;
let stream = ProgressStream::new(resp, task_handle.clone());
let mut file = if current == 0 {
tokio::fs::File::create(&self.dest_path).await?
} else {
let mut f = tokio::fs::OpenOptions::new()
.write(true)
.open(&self.dest_path)
.await?;
f.seek(std::io::SeekFrom::Start(current as u64)).await?;
f
};
{
let mut h = task_handle.write().unwrap();
h.set_total(total_progress);
h.mark_started();
}
if let Some(lim) = limiter.clone() {
tokio::io::copy(&mut lim.limit(stream.into_async_read()).compat(), &mut file).await?;
} else {
tokio::io::copy(&mut stream.into_async_read().compat(), &mut file).await?;
}
drop(file);
if task_handle.read().unwrap().status().is_cancelled() {
tokio::fs::remove_file(&self.dest_path).await?;
Ok(())
} else {
match &param.sha1 {
Some(truth) => validate_sha1(self.dest_path.clone(), truth.clone()),
None => Ok(()),
}
}
}
.await;

match attempt {
Ok(()) => {
if !task_handle.read().unwrap().status().is_cancelled() {
let mut h = task_handle.write().unwrap();
h.mark_completed();
}
return Ok(());
}
Err(e) => {
last_err = Some(e);
let _ = tokio::fs::remove_file(&self.dest_path).await;
{
let mut h = task_handle.write().unwrap();
h.desc.current = 0;
}
continue;
}
}
}
Err(last_err.unwrap_or_else(|| SJMCLError("All sources failed".into())))
},
handle,
))
Expand Down
2 changes: 0 additions & 2 deletions src-tauri/src/tasks/streams/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,8 +71,6 @@ where
let mut h = p.handle.write().unwrap();
if let Some(item) = &opt {
h.report_progress(cx, item.unit_size());
} else {
h.mark_completed();
}
opt
})
Expand Down
Loading
Loading