feat(m162): Modrinth 在线内容源(匿名)+ 远端条目按 sha512 补全 + 离线态
core:新增 addon::online —— 按 Modrinth v2 真实形状建模(search facets / project /
project versions / version_file by hash),网络出口只有 Transport 一个 trait,生产实现
EngineTransport 走既有 DownloadEngine::download_bytes(零新依赖);错误分大类,网络类
失败映射成 NotConnected(= 未联网),不再用空列表冒充「没有结果」。
core:online::download::download_verified —— sha1 交给引擎流式校验、sha512 落盘后复核
(download::HashAlgo 没有 Sha512,改它超出 scope,已登记 finding),不符/失败删文件重试,
最多 3 次尝试且不留半截文件。
core:远端条目补全 —— PackFetcher::modrinth_file_by_sha512(默认 Unsupported = 补不出),
import 管线与新增的 scan_pack_online 都会在「有 path 但缺 hashes.sha1」时按 sha512 反查;
补出的 sha1 走 M160 同一套 judge 与合并判定,补不出仍进 unknown_remote 计数(口径未改)。
DownloadEngineFetcher 改用 download_verified,FetchRequest 增 sha512。
presenter:Modrinth 检索/详情改由 core 的 online 客户端提供(不再自己拼 URL、不再读错
date_modified);ContentFailure{kind} 取代裸字符串,无网 = Offline;新增
ContentDetailRequest/ContentDetail + LoadContentDetail 命令与 CoreEvent::ContentDetail 通道;
预检改走 scan_pack_online;内容库安装也走 download_verified(sha1+sha512)。
app-iced:Status::Offline 独立一态(未联网 ≠ 空列表 ≠ 普通失败),详情面板消费新 DTO
显示可用版本;选中项目即拉详情。i18n 新增 6 个键并同步金表。
测试:online 模块 24 个离线用例(录制 JSON + 假字节:搜索/详情/版本/按摘要反查/校验失败
即删/重试/离线分类/补全),import 侧 6 个(离线计数不变、补全后判冲突、补错摘要 ⇒ Failed),
presenter/app-iced 各补失败分类与详情状态机用例。
This commit is contained in:
1 parent
0241f793b2
commit
81278f55af
50 files changed
+3794
-222
No files matched your search
@@ -4,8 +4,9 @@ use std::time::Duration;
|
||||
|
||||
use super::http::{encode, retry_after, retryable};
|
||||
use super::install::safe_file_name;
|
||||
use super::sources::{all_kinds, curseforge_loader, date_part};
|
||||
use crate::dto::ContentKind;
|
||||
use super::sources::{all_kinds, curseforge_loader, date_part, failure_of};
|
||||
use crate::dto::{ContentFailureKind, ContentKind};
|
||||
use unlucky_core::addon::online::{OnlineError, OnlineErrorKind};
|
||||
|
||||
#[test]
|
||||
fn percent_encoding_keeps_the_query_readable_and_escapes_the_rest() {
|
||||
@@ -83,3 +84,34 @@ fn the_four_content_kinds_are_the_four_side_entries() {
|
||||
["modpack", "mod", "resourcepack", "shader"]
|
||||
);
|
||||
}
|
||||
|
||||
// ------------------------------------------------ M162:失败分类(core → DTO)
|
||||
|
||||
/// core 的 `OnlineErrorKind` → DTO 的 `ContentFailureKind`:**一一映射,不重新判**。
|
||||
///
|
||||
/// 「没联网」是单独一类:页面据此画离线态(说「检查网络」),而不是画「换个关键词」。
|
||||
#[test]
|
||||
fn core_errors_map_to_dto_failure_kinds() {
|
||||
let cases = [
|
||||
(OnlineErrorKind::NotConnected, ContentFailureKind::Offline),
|
||||
(OnlineErrorKind::NotFound, ContentFailureKind::NotFound),
|
||||
(OnlineErrorKind::Server, ContentFailureKind::Server),
|
||||
(
|
||||
OnlineErrorKind::Unsupported,
|
||||
ContentFailureKind::Unsupported,
|
||||
),
|
||||
(OnlineErrorKind::Malformed, ContentFailureKind::Other),
|
||||
(OnlineErrorKind::Io, ContentFailureKind::Other),
|
||||
(OnlineErrorKind::Integrity, ContentFailureKind::Other),
|
||||
];
|
||||
for (core, expected) in cases {
|
||||
let failure = failure_of(OnlineError::new(core, "x"));
|
||||
assert_eq!(failure.kind, expected, "{} 映射错了", core.as_str());
|
||||
}
|
||||
assert!(failure_of(OnlineError::offline("connect timed out")).is_offline());
|
||||
// 详情/版本列表的文案要带出 core 的原话(不是二次包装的「出错了」)
|
||||
assert_eq!(
|
||||
failure_of(OnlineError::offline("connect timed out")).detail,
|
||||
"connect timed out"
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user