mirror of
https://github.com/Yuyi-Oak/BlueArchiveToolkit.git
synced 2026-07-23 08:55:16 +08:00
feat(official-sync): 支持本地代理下载官方资源
This commit is contained in:
@@ -1,10 +1,11 @@
|
||||
use bat_adapters::official::yostar_jp::PatchPlatform;
|
||||
use bat_infrastructure::{
|
||||
lexical_absolute, open_append_file, read_file_no_symlink, read_version_state,
|
||||
validate_output_root, validate_runtime_state_dir, write_file_atomic,
|
||||
OfficialFailedVersionRecord, OfficialServerInfoSource, OfficialUpdateConfig,
|
||||
OfficialUpdateProgress, OfficialUpdateReport, OfficialUpdateService, OfficialUpdateStatus,
|
||||
OfficialVerificationSummary, OfficialVersionRecord, OfficialVersionState, PRIVATE_FILE_MODE,
|
||||
resolve_curl_proxy, validate_output_root, validate_runtime_state_dir, write_file_atomic,
|
||||
CurlProxyConfig, CurlProxyMode, OfficialFailedVersionRecord, OfficialServerInfoSource,
|
||||
OfficialUpdateConfig, OfficialUpdateProgress, OfficialUpdateReport, OfficialUpdateService,
|
||||
OfficialUpdateStatus, OfficialVerificationSummary, OfficialVersionRecord, OfficialVersionState,
|
||||
PRIVATE_FILE_MODE,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::env;
|
||||
@@ -180,6 +181,7 @@ struct CliOptions {
|
||||
state_dir: PathBuf,
|
||||
output_explicit: bool,
|
||||
sync_option_explicit: bool,
|
||||
proxy_option_explicit: bool,
|
||||
interval: Duration,
|
||||
error_retry_interval: Duration,
|
||||
quiet_up_to_date: bool,
|
||||
@@ -201,6 +203,7 @@ impl Default for CliOptions {
|
||||
state_dir: PathBuf::from(DEFAULT_DAEMON_STATE_DIR),
|
||||
output_explicit: false,
|
||||
sync_option_explicit: false,
|
||||
proxy_option_explicit: false,
|
||||
interval: Duration::from_secs(DEFAULT_WATCH_INTERVAL_SECONDS),
|
||||
error_retry_interval: Duration::from_secs(DEFAULT_ERROR_RETRY_SECONDS),
|
||||
quiet_up_to_date: false,
|
||||
@@ -1686,6 +1689,7 @@ struct DaemonControlReport {
|
||||
fn run_daemon_restart(options: &CliOptions, command_name: &'static str) -> anyhow::Result<()> {
|
||||
let has_explicit_options = options.sync_option_explicit
|
||||
|| options.output_explicit
|
||||
|| options.proxy_option_explicit
|
||||
|| tools_are_non_default(&options.config);
|
||||
if command_name == "reload" && !has_explicit_options && daemon_rpc_available(&options.state_dir)
|
||||
{
|
||||
@@ -1839,6 +1843,7 @@ fn refresh_should_use_daemon_rpc(options: &CliOptions, command_name: &str) -> bo
|
||||
&& !options.daemon
|
||||
&& !options.daemon_child
|
||||
&& !options.output_explicit
|
||||
&& !options.proxy_option_explicit
|
||||
&& options.config.server_info_source.is_none()
|
||||
&& options.config.connection_group.is_none()
|
||||
&& options.config.app_version.is_none()
|
||||
@@ -1847,6 +1852,7 @@ fn refresh_should_use_daemon_rpc(options: &CliOptions, command_name: &str) -> bo
|
||||
&& options.config.output_root == defaults.output_root
|
||||
&& options.config.snapshot_path.is_none()
|
||||
&& options.config.curl_command == defaults.curl_command
|
||||
&& options.config.curl_proxy == defaults.curl_proxy
|
||||
&& options.config.unzip_command == defaults.unzip_command
|
||||
&& !options.config.dry_run
|
||||
&& !options.config.plan
|
||||
@@ -2459,6 +2465,7 @@ fn run_verify_command(options: &CliOptions) -> anyhow::Result<bool> {
|
||||
&verified_resource_root,
|
||||
&config.curl_command,
|
||||
)
|
||||
.with_proxy_config(config.curl_proxy.clone())
|
||||
.verify_local_download_manifest()
|
||||
.map_err(anyhow::Error::msg)?;
|
||||
let failures = verification
|
||||
@@ -2607,6 +2614,7 @@ fn run_doctor_command(options: &CliOptions) -> anyhow::Result<bool> {
|
||||
"后台状态目录安全边界通过",
|
||||
),
|
||||
command_check("curl", &options.config.curl_command),
|
||||
proxy_check(&options.config.curl_proxy),
|
||||
command_check("unzip", &options.config.unzip_command),
|
||||
];
|
||||
|
||||
@@ -2814,6 +2822,14 @@ fn command_check(name: &'static str, command: &Path) -> DoctorCheck {
|
||||
}
|
||||
}
|
||||
|
||||
fn proxy_check(config: &CurlProxyConfig) -> DoctorCheck {
|
||||
DoctorCheck {
|
||||
name: "proxy",
|
||||
ok: true,
|
||||
message: resolve_curl_proxy(config).human_summary(),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
struct CleanStableReport {
|
||||
command: &'static str,
|
||||
@@ -3162,6 +3178,20 @@ fn daemon_child_args(options: &CliOptions) -> Vec<String> {
|
||||
}
|
||||
args.push("--curl".to_string());
|
||||
args.push(config.curl_command.to_string_lossy().to_string());
|
||||
match config.curl_proxy.mode() {
|
||||
CurlProxyMode::Auto if options.proxy_option_explicit => {
|
||||
args.push("--proxy".to_string());
|
||||
args.push("auto".to_string());
|
||||
}
|
||||
CurlProxyMode::Auto => {}
|
||||
CurlProxyMode::Disabled => {
|
||||
args.push("--no-proxy".to_string());
|
||||
}
|
||||
CurlProxyMode::Url(url) => {
|
||||
args.push("--proxy".to_string());
|
||||
args.push(url.clone());
|
||||
}
|
||||
}
|
||||
args.push("--unzip".to_string());
|
||||
args.push(config.unzip_command.to_string_lossy().to_string());
|
||||
if config.force {
|
||||
@@ -3712,6 +3742,15 @@ fn parse_args_from(raw_args: impl IntoIterator<Item = String>) -> anyhow::Result
|
||||
"--curl" => {
|
||||
options.config.curl_command = PathBuf::from(next_option_value(&mut args, &flag)?);
|
||||
}
|
||||
"--proxy" => {
|
||||
options.config.curl_proxy =
|
||||
parse_proxy_config(&next_option_value(&mut args, &flag)?)?;
|
||||
options.proxy_option_explicit = true;
|
||||
}
|
||||
"--no-proxy" => {
|
||||
options.config.curl_proxy = CurlProxyConfig::disabled();
|
||||
options.proxy_option_explicit = true;
|
||||
}
|
||||
"--unzip" => {
|
||||
options.config.unzip_command = PathBuf::from(next_option_value(&mut args, &flag)?);
|
||||
}
|
||||
@@ -3829,6 +3868,7 @@ fn parse_args_from(raw_args: impl IntoIterator<Item = String>) -> anyhow::Result
|
||||
CliCommand::Status | CliCommand::Stop | CliCommand::Logs => {
|
||||
if options.sync_option_explicit
|
||||
|| options.output_explicit
|
||||
|| options.proxy_option_explicit
|
||||
|| tools_are_non_default(&options.config)
|
||||
{
|
||||
return Err(anyhow::anyhow!(
|
||||
@@ -3841,7 +3881,7 @@ fn parse_args_from(raw_args: impl IntoIterator<Item = String>) -> anyhow::Result
|
||||
CliCommand::Doctor | CliCommand::CleanStable => {
|
||||
if options.sync_option_explicit {
|
||||
return Err(anyhow::anyhow!(
|
||||
"doctor/clean-stable 只接受 --output、--state-dir、--curl 和 --unzip 等诊断参数"
|
||||
"doctor/clean-stable 只接受 --output、--state-dir、--curl、--proxy 和 --unzip 等诊断参数"
|
||||
));
|
||||
}
|
||||
options.progress = false;
|
||||
@@ -3865,6 +3905,7 @@ fn parse_args_from(raw_args: impl IntoIterator<Item = String>) -> anyhow::Result
|
||||
CliCommand::Restart | CliCommand::Reload => {
|
||||
if (options.sync_option_explicit
|
||||
|| options.output_explicit
|
||||
|| options.proxy_option_explicit
|
||||
|| tools_are_non_default(&options.config))
|
||||
&& !options.config.auto_discover
|
||||
&& options.config.server_info_source.is_none()
|
||||
@@ -3932,7 +3973,10 @@ fn ensure_command_not_set(command: CliCommand, next: &str) -> anyhow::Result<()>
|
||||
}
|
||||
|
||||
fn tools_are_non_default(config: &OfficialUpdateConfig) -> bool {
|
||||
config.curl_command != Path::new("curl") || config.unzip_command != Path::new("unzip")
|
||||
let defaults = OfficialUpdateConfig::default();
|
||||
config.curl_command != defaults.curl_command
|
||||
|| config.curl_proxy != defaults.curl_proxy
|
||||
|| config.unzip_command != defaults.unzip_command
|
||||
}
|
||||
|
||||
fn next_option_value(
|
||||
@@ -3943,6 +3987,19 @@ fn next_option_value(
|
||||
.ok_or_else(|| anyhow::anyhow!("{flag} 缺少参数值"))
|
||||
}
|
||||
|
||||
fn parse_proxy_config(value: &str) -> anyhow::Result<CurlProxyConfig> {
|
||||
let normalized = value.trim();
|
||||
if normalized.is_empty() {
|
||||
return Err(anyhow::anyhow!("--proxy 不能为空"));
|
||||
}
|
||||
|
||||
match normalized.to_ascii_lowercase().as_str() {
|
||||
"auto" | "env" => Ok(CurlProxyConfig::auto()),
|
||||
"none" | "direct" | "off" | "disabled" => Ok(CurlProxyConfig::disabled()),
|
||||
_ => Ok(CurlProxyConfig::url(normalized.to_string())),
|
||||
}
|
||||
}
|
||||
|
||||
fn print_usage(binary: &str) {
|
||||
eprintln!("BlueArchiveToolkit official resource sync");
|
||||
eprintln!();
|
||||
@@ -3989,6 +4046,8 @@ fn print_usage(binary: &str) {
|
||||
);
|
||||
eprintln!(" --snapshot <PATH> Override snapshot path (default: <output>/current/official-sync-snapshot.json)");
|
||||
eprintln!(" --curl <PATH> curl executable (default: curl)");
|
||||
eprintln!(" --proxy <URL|auto|none> curl proxy override (default: auto from env)");
|
||||
eprintln!(" --no-proxy Force direct curl connections");
|
||||
eprintln!(" --unzip <PATH> unzip executable (default: unzip)");
|
||||
eprintln!(" --dry-run Do not write sync state");
|
||||
eprintln!(" --plan Include planned URLs in dry-run");
|
||||
@@ -4157,6 +4216,26 @@ mod tests {
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parses_proxy_options() {
|
||||
let options = parse(&["bat", "--proxy", "http://127.0.0.1:7890"]).unwrap();
|
||||
assert!(options.proxy_option_explicit);
|
||||
assert_eq!(
|
||||
options.config.curl_proxy.mode(),
|
||||
&CurlProxyMode::Url("http://127.0.0.1:7890".to_string())
|
||||
);
|
||||
|
||||
let options = parse(&["bat", "--proxy", "none"]).unwrap();
|
||||
assert_eq!(options.config.curl_proxy.mode(), &CurlProxyMode::Disabled);
|
||||
|
||||
let options = parse(&["bat", "--no-proxy"]).unwrap();
|
||||
assert_eq!(options.config.curl_proxy.mode(), &CurlProxyMode::Disabled);
|
||||
|
||||
let options = parse(&["bat", "--proxy", "auto"]).unwrap();
|
||||
assert!(options.proxy_option_explicit);
|
||||
assert_eq!(options.config.curl_proxy.mode(), &CurlProxyMode::Auto);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parses_watch_defaults_to_one_hour_and_quiet_up_to_date() {
|
||||
let options = parse(&["bat", "--auto-discover", "--watch", "--interval", "30m"]).unwrap();
|
||||
@@ -4285,6 +4364,8 @@ mod tests {
|
||||
"/tmp/daemon-state",
|
||||
"--curl",
|
||||
"/usr/bin/curl",
|
||||
"--proxy",
|
||||
"http://127.0.0.1:7890",
|
||||
"--unzip",
|
||||
"/usr/bin/unzip",
|
||||
"--interval",
|
||||
@@ -4309,6 +4390,9 @@ mod tests {
|
||||
assert!(args
|
||||
.windows(2)
|
||||
.any(|pair| pair == ["--platforms", "Windows,Android"]));
|
||||
assert!(args
|
||||
.windows(2)
|
||||
.any(|pair| pair == ["--proxy", "http://127.0.0.1:7890"]));
|
||||
assert!(args.windows(2).any(|pair| pair == ["--interval", "30m"]));
|
||||
assert!(args.windows(2).any(|pair| pair == ["--error-retry", "45s"]));
|
||||
assert!(args.contains(&"--quiet-up-to-date".to_string()));
|
||||
|
||||
Reference in New Issue
Block a user