Fix forge install issues (#18)
* Fix forge install issues * remove mac garb
This commit is contained in:
parent
8b16cd1b36
commit
4274a8ed68
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "daedalus"
|
name = "daedalus"
|
||||||
version = "0.2.0"
|
version = "0.2.1"
|
||||||
authors = ["Jai A <jai@modrinth.com>"]
|
authors = ["Jai A <jai@modrinth.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "daedalus_client"
|
name = "daedalus_client"
|
||||||
version = "0.2.0"
|
version = "0.2.1"
|
||||||
authors = ["Jai A <jai@modrinth.com>"]
|
authors = ["Jai A <jai@modrinth.com>"]
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
|||||||
@ -17,6 +17,7 @@ pub async fn fetch_fabric(
|
|||||||
"fabric",
|
"fabric",
|
||||||
"https://meta.fabricmc.net/v2",
|
"https://meta.fabricmc.net/v2",
|
||||||
"https://maven.fabricmc.net/",
|
"https://maven.fabricmc.net/",
|
||||||
|
&[],
|
||||||
semaphore,
|
semaphore,
|
||||||
upload_files,
|
upload_files,
|
||||||
mirror_artifacts,
|
mirror_artifacts,
|
||||||
@ -34,7 +35,11 @@ pub async fn fetch_quilt(
|
|||||||
daedalus::modded::CURRENT_QUILT_FORMAT_VERSION,
|
daedalus::modded::CURRENT_QUILT_FORMAT_VERSION,
|
||||||
"quilt",
|
"quilt",
|
||||||
"https://meta.quiltmc.org/v3",
|
"https://meta.quiltmc.org/v3",
|
||||||
"https://meta.quiltmc.org/",
|
"https://maven.quiltmc.org/repository/release/",
|
||||||
|
&[
|
||||||
|
// This version is broken as it contains invalid library coordinates
|
||||||
|
"0.17.5-beta.4",
|
||||||
|
],
|
||||||
semaphore,
|
semaphore,
|
||||||
upload_files,
|
upload_files,
|
||||||
mirror_artifacts,
|
mirror_artifacts,
|
||||||
@ -48,6 +53,7 @@ async fn fetch(
|
|||||||
mod_loader: &str,
|
mod_loader: &str,
|
||||||
meta_url: &str,
|
meta_url: &str,
|
||||||
maven_url: &str,
|
maven_url: &str,
|
||||||
|
skip_versions: &[&str],
|
||||||
semaphore: Arc<Semaphore>,
|
semaphore: Arc<Semaphore>,
|
||||||
upload_files: &DashMap<String, UploadFile>,
|
upload_files: &DashMap<String, UploadFile>,
|
||||||
mirror_artifacts: &DashMap<String, MirrorArtifact>,
|
mirror_artifacts: &DashMap<String, MirrorArtifact>,
|
||||||
@ -76,6 +82,7 @@ async fn fetch(
|
|||||||
.game_versions
|
.game_versions
|
||||||
.iter()
|
.iter()
|
||||||
.any(|x| x.loaders.iter().any(|x| x.id == version.version))
|
.any(|x| x.loaders.iter().any(|x| x.id == version.version))
|
||||||
|
&& !skip_versions.contains(&&*version.version)
|
||||||
{
|
{
|
||||||
fetch_versions.push(version);
|
fetch_versions.push(version);
|
||||||
}
|
}
|
||||||
@ -98,7 +105,11 @@ async fn fetch(
|
|||||||
(fetch_versions, fetch_intermediary_versions)
|
(fetch_versions, fetch_intermediary_versions)
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
fabric_manifest.loader.iter().collect(),
|
fabric_manifest
|
||||||
|
.loader
|
||||||
|
.iter()
|
||||||
|
.filter(|x| !skip_versions.contains(&&*x.version))
|
||||||
|
.collect(),
|
||||||
fabric_manifest.intermediary.iter().collect(),
|
fabric_manifest.intermediary.iter().collect(),
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
@ -109,7 +120,9 @@ async fn fetch(
|
|||||||
for x in &fetch_intermediary_versions {
|
for x in &fetch_intermediary_versions {
|
||||||
insert_mirrored_artifact(
|
insert_mirrored_artifact(
|
||||||
&x.maven,
|
&x.maven,
|
||||||
maven_url.to_string(),
|
None,
|
||||||
|
vec![maven_url.to_string()],
|
||||||
|
false,
|
||||||
mirror_artifacts,
|
mirror_artifacts,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
@ -142,13 +155,24 @@ async fn fetch(
|
|||||||
let new_name = lib
|
let new_name = lib
|
||||||
.name
|
.name
|
||||||
.replace(DUMMY_GAME_VERSION, DUMMY_REPLACE_STRING);
|
.replace(DUMMY_GAME_VERSION, DUMMY_REPLACE_STRING);
|
||||||
|
|
||||||
|
// Hard-code: This library is not present on fabric's maven, so we fetch it from MC libraries
|
||||||
|
if &*lib.name == "net.minecraft:launchwrapper:1.12" {
|
||||||
|
lib.url = Some(
|
||||||
|
"https://libraries.minecraft.net/".to_string(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// If a library is not intermediary, we add it to mirror artifacts to be mirrored
|
// If a library is not intermediary, we add it to mirror artifacts to be mirrored
|
||||||
if lib.name == new_name {
|
if lib.name == new_name {
|
||||||
insert_mirrored_artifact(
|
insert_mirrored_artifact(
|
||||||
&new_name,
|
&new_name,
|
||||||
lib.url
|
None,
|
||||||
|
vec![lib
|
||||||
|
.url
|
||||||
.clone()
|
.clone()
|
||||||
.unwrap_or_else(|| maven_url.to_string()),
|
.unwrap_or_else(|| maven_url.to_string())],
|
||||||
|
false,
|
||||||
mirror_artifacts,
|
mirror_artifacts,
|
||||||
)?;
|
)?;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
use crate::util::{download_file, fetch_json, fetch_xml, format_url};
|
use crate::util::{
|
||||||
|
download_file, fetch_json, fetch_xml, format_url, sha1_async,
|
||||||
|
};
|
||||||
use crate::{insert_mirrored_artifact, Error, MirrorArtifact, UploadFile};
|
use crate::{insert_mirrored_artifact, Error, MirrorArtifact, UploadFile};
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, Utc};
|
||||||
use daedalus::get_path_from_artifact;
|
use daedalus::get_path_from_artifact;
|
||||||
@ -246,6 +248,7 @@ async fn fetch(
|
|||||||
raw: bytes::Bytes,
|
raw: bytes::Bytes,
|
||||||
loader: &ForgeVersion,
|
loader: &ForgeVersion,
|
||||||
maven_url: &str,
|
maven_url: &str,
|
||||||
|
mod_loader: &str,
|
||||||
upload_files: &DashMap<String, UploadFile>,
|
upload_files: &DashMap<String, UploadFile>,
|
||||||
mirror_artifacts: &DashMap<String, MirrorArtifact>,
|
mirror_artifacts: &DashMap<String, MirrorArtifact>,
|
||||||
) -> Result<PartialVersionInfo, Error> {
|
) -> Result<PartialVersionInfo, Error> {
|
||||||
@ -399,16 +402,28 @@ async fn fetch(
|
|||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|mut lib| {
|
.map(|mut lib| {
|
||||||
// For all libraries besides the forge lib extracted, we mirror them from maven servers
|
// For all libraries besides the forge lib extracted, we mirror them from maven servers
|
||||||
if lib.name != install_profile.install.path {
|
// unless the URL is empty/null or available on Minecraft's servers
|
||||||
// TODO: add mirrors "https://maven.creeperhost.net/", "https://libraries.minecraft.net/"
|
if let Some(url) = lib.url {
|
||||||
|
if lib.name != install_profile.install.path
|
||||||
|
&& !url.is_empty()
|
||||||
|
&& !url.contains(
|
||||||
|
"https://libraries.minecraft.net/",
|
||||||
|
)
|
||||||
|
{
|
||||||
insert_mirrored_artifact(
|
insert_mirrored_artifact(
|
||||||
&lib.name,
|
&lib.name,
|
||||||
lib.url.clone().unwrap_or_else(|| {
|
None,
|
||||||
maven_url.to_string()
|
vec![
|
||||||
}),
|
url,
|
||||||
|
"https://maven.creeperhost.net/"
|
||||||
|
.to_string(),
|
||||||
|
maven_url.to_string(),
|
||||||
|
],
|
||||||
|
false,
|
||||||
mirror_artifacts,
|
mirror_artifacts,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
lib.url = Some(format_url("maven/"));
|
lib.url = Some(format_url("maven/"));
|
||||||
|
|
||||||
@ -468,6 +483,7 @@ async fn fetch(
|
|||||||
async fn mirror_forge_library(
|
async fn mirror_forge_library(
|
||||||
mut zip: ZipFileReader,
|
mut zip: ZipFileReader,
|
||||||
mut lib: daedalus::minecraft::Library,
|
mut lib: daedalus::minecraft::Library,
|
||||||
|
maven_url: &str,
|
||||||
upload_files: &DashMap<String, UploadFile>,
|
upload_files: &DashMap<String, UploadFile>,
|
||||||
mirror_artifacts: &DashMap<String, MirrorArtifact>,
|
mirror_artifacts: &DashMap<String, MirrorArtifact>,
|
||||||
) -> Result<daedalus::minecraft::Library, Error>
|
) -> Result<daedalus::minecraft::Library, Error>
|
||||||
@ -480,7 +496,9 @@ async fn fetch(
|
|||||||
if !artifact.url.is_empty() {
|
if !artifact.url.is_empty() {
|
||||||
insert_mirrored_artifact(
|
insert_mirrored_artifact(
|
||||||
&lib.name,
|
&lib.name,
|
||||||
artifact.url.clone(),
|
Some(artifact.sha1.clone()),
|
||||||
|
vec![artifact.url.clone()],
|
||||||
|
true,
|
||||||
mirror_artifacts,
|
mirror_artifacts,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -491,10 +509,18 @@ async fn fetch(
|
|||||||
}
|
}
|
||||||
} else if let Some(url) = &lib.url {
|
} else if let Some(url) = &lib.url {
|
||||||
if !url.is_empty() {
|
if !url.is_empty() {
|
||||||
// TODO: add mirrors "https://maven.creeperhost.net/", "https://libraries.minecraft.net/"
|
|
||||||
insert_mirrored_artifact(
|
insert_mirrored_artifact(
|
||||||
&lib.name,
|
&lib.name,
|
||||||
|
None,
|
||||||
|
vec![
|
||||||
url.clone(),
|
url.clone(),
|
||||||
|
"https://libraries.minecraft.net/"
|
||||||
|
.to_string(),
|
||||||
|
"https://maven.creeperhost.net/"
|
||||||
|
.to_string(),
|
||||||
|
maven_url.to_string(),
|
||||||
|
],
|
||||||
|
false,
|
||||||
mirror_artifacts,
|
mirror_artifacts,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@ -531,6 +557,7 @@ async fn fetch(
|
|||||||
mirror_forge_library(
|
mirror_forge_library(
|
||||||
zip.clone(),
|
zip.clone(),
|
||||||
lib,
|
lib,
|
||||||
|
maven_url,
|
||||||
upload_files,
|
upload_files,
|
||||||
mirror_artifacts,
|
mirror_artifacts,
|
||||||
)
|
)
|
||||||
@ -560,7 +587,7 @@ async fn fetch(
|
|||||||
value: &str,
|
value: &str,
|
||||||
upload_files: &DashMap<String, UploadFile>,
|
upload_files: &DashMap<String, UploadFile>,
|
||||||
libs: &mut Vec<daedalus::minecraft::Library>,
|
libs: &mut Vec<daedalus::minecraft::Library>,
|
||||||
install_profile_path: Option<&str>,
|
mod_loader: &str,
|
||||||
version: &ForgeVersion,
|
version: &ForgeVersion,
|
||||||
) -> Result<String, Error> {
|
) -> Result<String, Error> {
|
||||||
let extract_file =
|
let extract_file =
|
||||||
@ -595,11 +622,9 @@ async fn fetch(
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
let path = format!(
|
let path = format!(
|
||||||
"{}:{}@{}",
|
"com.modrinth.daedalus:{}-installer-extracts:{}:{}@{}",
|
||||||
install_profile_path.unwrap_or(&*format!(
|
mod_loader,
|
||||||
"net.minecraftforge:forge:{}",
|
version.raw,
|
||||||
version.raw
|
|
||||||
)),
|
|
||||||
file_name,
|
file_name,
|
||||||
ext
|
ext
|
||||||
);
|
);
|
||||||
@ -634,7 +659,7 @@ async fn fetch(
|
|||||||
&entry.client,
|
&entry.client,
|
||||||
upload_files,
|
upload_files,
|
||||||
&mut version_info.libraries,
|
&mut version_info.libraries,
|
||||||
install_profile.path.as_deref(),
|
mod_loader,
|
||||||
loader,
|
loader,
|
||||||
)
|
)
|
||||||
.await?
|
.await?
|
||||||
@ -649,7 +674,7 @@ async fn fetch(
|
|||||||
&entry.server,
|
&entry.server,
|
||||||
upload_files,
|
upload_files,
|
||||||
&mut version_info.libraries,
|
&mut version_info.libraries,
|
||||||
install_profile.path.as_deref(),
|
mod_loader,
|
||||||
loader,
|
loader,
|
||||||
)
|
)
|
||||||
.await?
|
.await?
|
||||||
@ -686,6 +711,7 @@ async fn fetch(
|
|||||||
raw,
|
raw,
|
||||||
loader,
|
loader,
|
||||||
maven_url,
|
maven_url,
|
||||||
|
mod_loader,
|
||||||
upload_files,
|
upload_files,
|
||||||
mirror_artifacts,
|
mirror_artifacts,
|
||||||
)
|
)
|
||||||
|
|||||||
@ -72,12 +72,28 @@ async fn main() -> Result<()> {
|
|||||||
futures::future::try_join_all(mirror_artifacts.iter().map(|x| {
|
futures::future::try_join_all(mirror_artifacts.iter().map(|x| {
|
||||||
upload_url_to_bucket_mirrors(
|
upload_url_to_bucket_mirrors(
|
||||||
format!("maven/{}", x.key()),
|
format!("maven/{}", x.key()),
|
||||||
x.value().mirrors.iter().map(|x| x.key().clone()).collect(),
|
x.value()
|
||||||
|
.mirrors
|
||||||
|
.iter()
|
||||||
|
.map(|mirror| {
|
||||||
|
if mirror.entire_url {
|
||||||
|
mirror.path.clone()
|
||||||
|
} else {
|
||||||
|
format!("{}{}", mirror.path, x.key())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect(),
|
||||||
|
x.sha1.clone(),
|
||||||
&semaphore,
|
&semaphore,
|
||||||
)
|
)
|
||||||
}))
|
}))
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
|
if dotenvy::var("CLOUDFLARE_INTEGRATION")
|
||||||
|
.ok()
|
||||||
|
.and_then(|x| x.parse::<bool>().ok())
|
||||||
|
.unwrap_or(false)
|
||||||
|
{
|
||||||
if let Ok(token) = dotenvy::var("CLOUDFLARE_TOKEN") {
|
if let Ok(token) = dotenvy::var("CLOUDFLARE_TOKEN") {
|
||||||
if let Ok(zone_id) = dotenvy::var("CLOUDFLARE_ZONE_ID") {
|
if let Ok(zone_id) = dotenvy::var("CLOUDFLARE_ZONE_ID") {
|
||||||
let cache_clears = upload_files
|
let cache_clears = upload_files
|
||||||
@ -115,6 +131,7 @@ async fn main() -> Result<()> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -125,21 +142,37 @@ pub struct UploadFile {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct MirrorArtifact {
|
pub struct MirrorArtifact {
|
||||||
pub mirrors: DashSet<String>,
|
pub sha1: Option<String>,
|
||||||
|
pub mirrors: DashSet<Mirror>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Eq, PartialEq, Hash)]
|
||||||
|
pub struct Mirror {
|
||||||
|
path: String,
|
||||||
|
entire_url: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tracing::instrument(skip(mirror_artifacts))]
|
||||||
pub fn insert_mirrored_artifact(
|
pub fn insert_mirrored_artifact(
|
||||||
artifact: &str,
|
artifact: &str,
|
||||||
mirror: String,
|
sha1: Option<String>,
|
||||||
|
mirrors: Vec<String>,
|
||||||
|
entire_url: bool,
|
||||||
mirror_artifacts: &DashMap<String, MirrorArtifact>,
|
mirror_artifacts: &DashMap<String, MirrorArtifact>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
mirror_artifacts
|
let mut val = mirror_artifacts
|
||||||
.entry(get_path_from_artifact(artifact)?)
|
.entry(get_path_from_artifact(artifact)?)
|
||||||
.or_insert(MirrorArtifact {
|
.or_insert(MirrorArtifact {
|
||||||
|
sha1,
|
||||||
mirrors: DashSet::new(),
|
mirrors: DashSet::new(),
|
||||||
})
|
});
|
||||||
.mirrors
|
|
||||||
.insert(mirror);
|
for mirror in mirrors {
|
||||||
|
val.mirrors.insert(Mirror {
|
||||||
|
path: mirror,
|
||||||
|
entire_url,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
use crate::{Error, ErrorKind};
|
use crate::{Error, ErrorKind};
|
||||||
use bytes::{Bytes, BytesMut};
|
use bytes::Bytes;
|
||||||
use futures::StreamExt;
|
|
||||||
use s3::creds::Credentials;
|
use s3::creds::Credentials;
|
||||||
use s3::{Bucket, Region};
|
use s3::{Bucket, Region};
|
||||||
use serde::de::DeserializeOwned;
|
use serde::de::DeserializeOwned;
|
||||||
@ -95,8 +94,9 @@ pub async fn upload_file_to_bucket(
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn upload_url_to_bucket_mirrors(
|
pub async fn upload_url_to_bucket_mirrors(
|
||||||
base: String,
|
upload_path: String,
|
||||||
mirrors: Vec<String>,
|
mirrors: Vec<String>,
|
||||||
|
sha1: Option<String>,
|
||||||
semaphore: &Arc<Semaphore>,
|
semaphore: &Arc<Semaphore>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
if mirrors.is_empty() {
|
if mirrors.is_empty() {
|
||||||
@ -108,8 +108,9 @@ pub async fn upload_url_to_bucket_mirrors(
|
|||||||
|
|
||||||
for (index, mirror) in mirrors.iter().enumerate() {
|
for (index, mirror) in mirrors.iter().enumerate() {
|
||||||
let result = upload_url_to_bucket(
|
let result = upload_url_to_bucket(
|
||||||
&base,
|
upload_path.clone(),
|
||||||
&format!("{}{}", mirror, base),
|
mirror.clone(),
|
||||||
|
sha1.clone(),
|
||||||
semaphore,
|
semaphore,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
@ -124,154 +125,18 @@ pub async fn upload_url_to_bucket_mirrors(
|
|||||||
|
|
||||||
#[tracing::instrument(skip(semaphore))]
|
#[tracing::instrument(skip(semaphore))]
|
||||||
pub async fn upload_url_to_bucket(
|
pub async fn upload_url_to_bucket(
|
||||||
path: &str,
|
path: String,
|
||||||
url: &str,
|
url: String,
|
||||||
|
sha1: Option<String>,
|
||||||
semaphore: &Arc<Semaphore>,
|
semaphore: &Arc<Semaphore>,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let _permit = semaphore.acquire().await?;
|
let data = download_file(&url, sha1.as_deref(), semaphore).await?;
|
||||||
|
|
||||||
const RETRIES: i32 = 3;
|
upload_file_to_bucket(path, data, None, semaphore).await?;
|
||||||
for attempt in 1..=(RETRIES + 1) {
|
|
||||||
tracing::trace!("Attempting streaming file upload, attempt {attempt}");
|
|
||||||
|
|
||||||
let result: Result<(), Error> = {
|
|
||||||
let response =
|
|
||||||
REQWEST_CLIENT.get(url).send().await.map_err(|err| {
|
|
||||||
ErrorKind::Fetch {
|
|
||||||
inner: err,
|
|
||||||
item: url.to_string(),
|
|
||||||
}
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let content_type = response
|
|
||||||
.headers()
|
|
||||||
.get(reqwest::header::CONTENT_TYPE)
|
|
||||||
.and_then(|ct| ct.to_str().ok())
|
|
||||||
.unwrap_or("application/octet-stream")
|
|
||||||
.to_string();
|
|
||||||
|
|
||||||
let total_size = response.content_length().unwrap_or(0);
|
|
||||||
|
|
||||||
const MIN_PART_SIZE: usize = 5 * 1024 * 1024;
|
|
||||||
|
|
||||||
if total_size < MIN_PART_SIZE as u64 {
|
|
||||||
let data =
|
|
||||||
response.bytes().await.map_err(|err| ErrorKind::Fetch {
|
|
||||||
inner: err,
|
|
||||||
item: url.to_string(),
|
|
||||||
})?;
|
|
||||||
BUCKET.put_object(&path, &data).await.map_err(|err| {
|
|
||||||
ErrorKind::S3 {
|
|
||||||
inner: err,
|
|
||||||
file: path.to_string(),
|
|
||||||
}
|
|
||||||
})?;
|
|
||||||
} else {
|
|
||||||
let mut stream = response.bytes_stream();
|
|
||||||
|
|
||||||
let multipart = BUCKET
|
|
||||||
.initiate_multipart_upload(path, &content_type)
|
|
||||||
.await
|
|
||||||
.map_err(|err| ErrorKind::S3 {
|
|
||||||
inner: err,
|
|
||||||
file: path.to_string(),
|
|
||||||
})?;
|
|
||||||
|
|
||||||
let mut parts = Vec::new();
|
|
||||||
let mut buffer = BytesMut::new();
|
|
||||||
|
|
||||||
async fn upload_part(
|
|
||||||
parts: &mut Vec<s3::serde_types::Part>,
|
|
||||||
buffer: Vec<u8>,
|
|
||||||
path: &str,
|
|
||||||
upload_id: &str,
|
|
||||||
content_type: &str,
|
|
||||||
) -> Result<(), Error> {
|
|
||||||
let part = BUCKET
|
|
||||||
.put_multipart_chunk(
|
|
||||||
buffer,
|
|
||||||
path,
|
|
||||||
(parts.len() + 1) as u32,
|
|
||||||
upload_id,
|
|
||||||
content_type,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.map_err(|err| ErrorKind::S3 {
|
|
||||||
inner: err,
|
|
||||||
file: path.to_string(),
|
|
||||||
})?;
|
|
||||||
|
|
||||||
parts.push(part);
|
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
while let Some(chunk) = stream.next().await {
|
|
||||||
let chunk = chunk.map_err(|err| ErrorKind::Fetch {
|
|
||||||
inner: err,
|
|
||||||
item: url.to_string(),
|
|
||||||
})?;
|
|
||||||
|
|
||||||
buffer.extend_from_slice(&chunk);
|
|
||||||
|
|
||||||
if buffer.len() >= MIN_PART_SIZE {
|
|
||||||
upload_part(
|
|
||||||
&mut parts,
|
|
||||||
buffer.to_vec(),
|
|
||||||
path,
|
|
||||||
&multipart.upload_id,
|
|
||||||
&content_type,
|
|
||||||
)
|
|
||||||
.await?;
|
|
||||||
buffer.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if !buffer.is_empty() {
|
|
||||||
let part = BUCKET
|
|
||||||
.put_multipart_chunk(
|
|
||||||
buffer.to_vec(),
|
|
||||||
path,
|
|
||||||
(parts.len() + 1) as u32,
|
|
||||||
&multipart.upload_id,
|
|
||||||
&content_type,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.map_err(|err| ErrorKind::S3 {
|
|
||||||
inner: err,
|
|
||||||
file: path.to_string(),
|
|
||||||
})?;
|
|
||||||
|
|
||||||
parts.push(part);
|
|
||||||
}
|
|
||||||
|
|
||||||
BUCKET
|
|
||||||
.complete_multipart_upload(
|
|
||||||
path,
|
|
||||||
&multipart.upload_id,
|
|
||||||
parts,
|
|
||||||
)
|
|
||||||
.await
|
|
||||||
.map_err(|err| ErrorKind::S3 {
|
|
||||||
inner: err,
|
|
||||||
file: path.to_string(),
|
|
||||||
})?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
};
|
|
||||||
|
|
||||||
match result {
|
|
||||||
Ok(_) => return Ok(()),
|
|
||||||
Err(_) if attempt <= RETRIES => continue,
|
|
||||||
Err(_) => {
|
|
||||||
result?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tracing::instrument(skip(bytes))]
|
#[tracing::instrument(skip(bytes))]
|
||||||
pub async fn sha1_async(bytes: Bytes) -> Result<String, Error> {
|
pub async fn sha1_async(bytes: Bytes) -> Result<String, Error> {
|
||||||
let hash = tokio::task::spawn_blocking(move || {
|
let hash = tokio::task::spawn_blocking(move || {
|
||||||
@ -294,7 +159,7 @@ pub async fn download_file(
|
|||||||
const RETRIES: u32 = 10;
|
const RETRIES: u32 = 10;
|
||||||
for attempt in 1..=(RETRIES + 1) {
|
for attempt in 1..=(RETRIES + 1) {
|
||||||
let result = REQWEST_CLIENT
|
let result = REQWEST_CLIENT
|
||||||
.get(url)
|
.get(&url.replace("http://", "https://"))
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
.and_then(|x| x.error_for_status());
|
.and_then(|x| x.error_for_status());
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user