mirror of
https://github.com/Yuyi-Oak/BlueArchiveToolkit.git
synced 2026-07-22 08:26:44 +08:00
fix: classify official download failures
Distinguish terminal HTTP errors from retryable CDN/network failures, record quarantined resources, and report failed download progress. Fixes #7
This commit is contained in:
@@ -5,9 +5,11 @@
|
||||
//! discover the latest Windows client package and manifest, while resource
|
||||
//! updates still come from the game client's server-info flow.
|
||||
|
||||
use crate::curl_transfer::run_curl_with_retry as run_curl_command_with_retry;
|
||||
use bat_adapters::official::launcher::{YostarJpLauncherManifestFile, YOSTAR_JP_GAME_TAG};
|
||||
use md5::{Digest, Md5};
|
||||
use serde::Deserialize;
|
||||
use std::path::Path;
|
||||
use std::process::{Command, Output};
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
|
||||
@@ -165,8 +167,8 @@ impl OfficialLauncherBootstrapService {
|
||||
return Err(format!("拒绝拉取非官方启动器 manifest URL:{manifest_url}"));
|
||||
}
|
||||
|
||||
let output = self.run_curl_with_retry(
|
||||
|| {
|
||||
let output = self
|
||||
.run_curl_with_retry(manifest_url, || {
|
||||
let mut command = Command::new(&self.curl_command);
|
||||
command
|
||||
.arg("--fail")
|
||||
@@ -176,15 +178,8 @@ impl OfficialLauncherBootstrapService {
|
||||
.arg("--url")
|
||||
.arg(manifest_url);
|
||||
command
|
||||
},
|
||||
|output| {
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
format!(
|
||||
"curl 拉取启动器 manifest 失败 {manifest_url}:{}",
|
||||
stderr.trim()
|
||||
)
|
||||
},
|
||||
)?;
|
||||
})
|
||||
.map_err(|error| format!("curl 拉取启动器 manifest 失败 {manifest_url}:{error}"))?;
|
||||
|
||||
let manifest: YostarJpLauncherRemoteManifest = serde_json::from_slice(&output.stdout)
|
||||
.map_err(|error| format!("解析官方启动器 manifest 失败:{error}"))?;
|
||||
@@ -222,8 +217,8 @@ impl OfficialLauncherBootstrapService {
|
||||
let url = launcher_api_url(path)?;
|
||||
let authorization = launcher_authorization_header(&self.launcher_version, "", None)?;
|
||||
|
||||
let output = self.run_curl_with_retry(
|
||||
|| {
|
||||
let output = self
|
||||
.run_curl_with_retry(&url, || {
|
||||
let mut command = Command::new(&self.curl_command);
|
||||
command
|
||||
.arg("--fail")
|
||||
@@ -237,12 +232,8 @@ impl OfficialLauncherBootstrapService {
|
||||
.arg("--url")
|
||||
.arg(&url);
|
||||
command
|
||||
},
|
||||
|output| {
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
format!("curl 拉取失败 {url}:{}", stderr.trim())
|
||||
},
|
||||
)?;
|
||||
})
|
||||
.map_err(|error| format!("curl 拉取失败 {url}:{error}"))?;
|
||||
|
||||
let envelope: LauncherEnvelope = serde_json::from_slice(&output.stdout)
|
||||
.map_err(|error| format!("解析官方启动器 API 响应失败:{error}"))?;
|
||||
@@ -264,30 +255,17 @@ impl OfficialLauncherBootstrapService {
|
||||
|
||||
fn run_curl_with_retry(
|
||||
&self,
|
||||
url: &str,
|
||||
mut build_command: impl FnMut() -> Command,
|
||||
failure_message: impl Fn(&Output) -> String,
|
||||
) -> Result<Output, String> {
|
||||
let attempts = self.retry_attempts.max(1);
|
||||
let mut last_error = None;
|
||||
for attempt in 1..=attempts {
|
||||
match build_command().output() {
|
||||
Ok(output) if output.status.success() => return Ok(output),
|
||||
Ok(output) => {
|
||||
last_error = Some(format!(
|
||||
"第 {attempt}/{attempts} 次尝试失败:{}",
|
||||
failure_message(&output)
|
||||
));
|
||||
}
|
||||
Err(error) => {
|
||||
last_error = Some(format!(
|
||||
"第 {attempt}/{attempts} 次尝试失败:启动 curl 命令失败 {}:{error}",
|
||||
self.curl_command
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err(last_error.unwrap_or_else(|| format!("curl 命令未执行:{}", self.curl_command)))
|
||||
run_curl_command_with_retry(
|
||||
Path::new(&self.curl_command),
|
||||
url,
|
||||
None,
|
||||
self.retry_attempts,
|
||||
&mut build_command,
|
||||
)
|
||||
.map_err(|error| error.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user