mirror of
https://github.com/Yuyi-Oak/BlueArchiveToolkit.git
synced 2026-07-22 06:56:44 +08:00
fix(daemon): 区分当前下载与历史失败状态
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
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, OfficialServerInfoSource,
|
||||
OfficialUpdateConfig, OfficialUpdateProgress, OfficialUpdateReport, OfficialUpdateService,
|
||||
OfficialUpdateStatus, OfficialVerificationSummary, OfficialVersionState, PRIVATE_FILE_MODE,
|
||||
validate_output_root, validate_runtime_state_dir, write_file_atomic,
|
||||
OfficialFailedVersionRecord, OfficialServerInfoSource, OfficialUpdateConfig,
|
||||
OfficialUpdateProgress, OfficialUpdateReport, OfficialUpdateService, OfficialUpdateStatus,
|
||||
OfficialVerificationSummary, OfficialVersionRecord, OfficialVersionState, PRIVATE_FILE_MODE,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::env;
|
||||
@@ -1990,14 +1991,34 @@ fn print_daemon_version_state_summary(version_state: &OfficialVersionState) {
|
||||
.as_ref()
|
||||
.map(|version| version.id.as_str()),
|
||||
);
|
||||
print_field("失败版本数", version_state.failed_versions.len());
|
||||
if let Some(failed) = version_state.failed_versions.last() {
|
||||
print_field("最近失败版本", &failed.version.id);
|
||||
print_field("最近失败时间", failed.failed_unix_seconds);
|
||||
print_field("最近失败原因", &failed.error);
|
||||
let historical_failures = visible_historical_failed_versions(version_state);
|
||||
print_field("历史失败版本数", historical_failures.len());
|
||||
if let Some(failed) = historical_failures.last() {
|
||||
print_field("最近历史失败版本", &failed.version.id);
|
||||
print_field("最近历史失败时间", failed.failed_unix_seconds);
|
||||
print_field("最近历史失败原因", &failed.error);
|
||||
}
|
||||
}
|
||||
|
||||
fn visible_historical_failed_versions<'a>(
|
||||
version_state: &'a OfficialVersionState,
|
||||
) -> Vec<&'a OfficialFailedVersionRecord> {
|
||||
let in_progress = version_state.in_progress_version.as_ref();
|
||||
version_state
|
||||
.failed_versions
|
||||
.iter()
|
||||
.filter(|failed| {
|
||||
!in_progress.is_some_and(|version| version_matches_for_status(&failed.version, version))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn version_matches_for_status(left: &OfficialVersionRecord, right: &OfficialVersionRecord) -> bool {
|
||||
left.app_version == right.app_version
|
||||
&& left.bundle_version == right.bundle_version
|
||||
&& left.addressables_root == right.addressables_root
|
||||
}
|
||||
|
||||
fn print_json_field(value: &serde_json::Value, key: &str, label: &str) {
|
||||
let Some(value) = value.get(key) else {
|
||||
return;
|
||||
@@ -4400,6 +4421,43 @@ mod tests {
|
||||
assert!(!formatted.contains('{'));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn daemon_status_hides_failure_superseded_by_in_progress_version() {
|
||||
let version = OfficialVersionRecord {
|
||||
id: "1.70.0-current-attempt".to_string(),
|
||||
app_version: "1.70.0".to_string(),
|
||||
bundle_version: Some("s8tloc7lo3".to_string()),
|
||||
addressables_root: "https://prod-clientpatch.bluearchiveyostar.com/r93_token"
|
||||
.to_string(),
|
||||
resource_root: PathBuf::from("/tmp/bat/.staging/current"),
|
||||
snapshot_path: PathBuf::from("/tmp/bat/.staging/current/official-sync-snapshot.json"),
|
||||
staging_path: Some(PathBuf::from("/tmp/bat/.staging/current")),
|
||||
version_path: None,
|
||||
started_unix_seconds: Some(100),
|
||||
completed_unix_seconds: None,
|
||||
};
|
||||
let older_failure = OfficialFailedVersionRecord {
|
||||
version: OfficialVersionRecord {
|
||||
id: "1.70.0-older-failure".to_string(),
|
||||
resource_root: PathBuf::from("/tmp/bat/.staging/older"),
|
||||
snapshot_path: PathBuf::from("/tmp/bat/.staging/older/official-sync-snapshot.json"),
|
||||
staging_path: Some(PathBuf::from("/tmp/bat/.staging/older")),
|
||||
started_unix_seconds: Some(90),
|
||||
..version.clone()
|
||||
},
|
||||
error: "官方 hash 校验失败 fixture".to_string(),
|
||||
failed_unix_seconds: 95,
|
||||
};
|
||||
let state = OfficialVersionState {
|
||||
in_progress_version: Some(version),
|
||||
failed_versions: vec![older_failure],
|
||||
updated_unix_seconds: 100,
|
||||
..OfficialVersionState::default()
|
||||
};
|
||||
|
||||
assert!(visible_historical_failed_versions(&state).is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn daemon_socket_path_uses_state_dir() {
|
||||
assert_eq!(
|
||||
|
||||
@@ -2020,6 +2020,7 @@ fn prepare_in_progress_version_state(
|
||||
completed_unix_seconds: None,
|
||||
},
|
||||
);
|
||||
remove_matching_version_failures(&mut state.failed_versions, &record);
|
||||
state.in_progress_version = Some(record.clone());
|
||||
state.updated_unix_seconds = now;
|
||||
write_version_state(path, &state)?;
|
||||
@@ -2049,7 +2050,7 @@ fn complete_version_state(
|
||||
..record
|
||||
});
|
||||
if let Some(current) = state.current_completed_version.as_ref() {
|
||||
remove_completed_version_failures(&mut state.failed_versions, current);
|
||||
remove_matching_version_failures(&mut state.failed_versions, current);
|
||||
}
|
||||
state.in_progress_version = None;
|
||||
state.updated_unix_seconds = unix_seconds_now();
|
||||
@@ -2132,9 +2133,10 @@ fn upsert_failed_version(
|
||||
error: &str,
|
||||
failed_unix_seconds: u64,
|
||||
) {
|
||||
if let Some(index) = failed_versions.iter().position(|failed| {
|
||||
failed_version_matches(&failed.version, &record) && failed.error == error
|
||||
}) {
|
||||
if let Some(index) = failed_versions
|
||||
.iter()
|
||||
.position(|failed| failed_version_matches(&failed.version, &record))
|
||||
{
|
||||
failed_versions.remove(index);
|
||||
}
|
||||
failed_versions.push(OfficialFailedVersionRecord {
|
||||
@@ -2144,11 +2146,11 @@ fn upsert_failed_version(
|
||||
});
|
||||
}
|
||||
|
||||
fn remove_completed_version_failures(
|
||||
fn remove_matching_version_failures(
|
||||
failed_versions: &mut Vec<OfficialFailedVersionRecord>,
|
||||
completed: &OfficialVersionRecord,
|
||||
version: &OfficialVersionRecord,
|
||||
) {
|
||||
failed_versions.retain(|failed| !failed_version_matches(&failed.version, completed));
|
||||
failed_versions.retain(|failed| !failed_version_matches(&failed.version, version));
|
||||
}
|
||||
|
||||
fn failed_version_matches(left: &OfficialVersionRecord, right: &OfficialVersionRecord) -> bool {
|
||||
@@ -2844,7 +2846,9 @@ mod tests {
|
||||
.unwrap();
|
||||
fail_version_state(&path, failed, "download 404").unwrap();
|
||||
let state = read_version_state(&path).unwrap().unwrap();
|
||||
assert_eq!(state.failed_versions.len(), 2);
|
||||
assert_eq!(state.failed_versions.len(), 1);
|
||||
assert_eq!(state.failed_versions[0].version.id, "broken-3");
|
||||
assert_eq!(state.failed_versions[0].error, "download 404");
|
||||
|
||||
let staging = temp.path().join(".staging/fixed");
|
||||
let fixed = prepare_in_progress_version_state(
|
||||
|
||||
Reference in New Issue
Block a user