fix(m162-r1): 叶子成因穿出引擎 + 安装路径切 core 在线源 + 详情迟到结果闸门

P1-1(p1-1items 的根因):
- download/error.rs:`DownloadError` 增 `leaf: Option<DownloadErrorKind>` 与
  `effective_kind()`;`leaf_of()` 汇总规则只此一处:全 404 ⇒ NotFound、有
  Network/Timeout ⇒ Network、全 5xx ⇒ ServerError、混合按「网络错 > 5xx > 404」
  取最可诊断的那个(**不从 suppressed 文本猜状态码**)。
- download/bytes.rs:候选源循环收集逐源 kind,收尾时把叶子挂到 AllSourcesFailed 上。
- online/transport.rs:`From<DownloadError>` 改用 `effective_kind()`,于是
  NotFound/Server/Integrity 在生产路径可达(项目被删/id 拼错/限速不再画成「未联网」)。
- import/fetch.rs:新增 `FetchErrorKind::Offline`(真正的「没联网」)并与 Network 分开;
  `From<DownloadError>`/`From<OnlineError>` 都按叶子/大类映射。
- import/complete.rs:补全只在 `Offline` 时早停;404(真实 mrpack 大多托管在 CF CDN,
  Modrinth 必然 404)与 5xx 只影响那一条,不再掐掉整轮;注记「因未联网提前停止」因此
  只会在真断网时出现。

P2-1:presenter 安装路径不再自己拼 Modrinth URL / 自己解析 JSON——改用
`core::addon::online::Modrinth::versions` + `primary_file()` + `VersionFile::sha1/sha512`;
`HostTask::InstallDone.result` 改成 `Result<String, ContentFailure>`,
`InstallProgressView` 增 `failure_kind`(离线 ≠ 查无此项)。

P2-2:`app/update/content.rs` 把被详情方法抢走的「装入闸门」注释还回
`content_install_request`,详情方法只留自己那一行。

P2-3:`ContentState::apply_detail/fail_detail` 带上 project(事件与 HostTask 都携带请求时的
项目 id),迟到结果一律丢弃;`request_detail` 记下在飞项目,`detail_pending` 不再被迟到
结果清掉。

顺手项:`usable_hash` 让形状非法的那一档摘要被**丢弃**(sha512 仍校验,不再整条跳过;
两档都不可用才拒绝);`digest_file` 的 IO 失败先删落盘文件再返回。i18n 的
ContentOfflineBody 改成不暗示「有缓存」的措辞(golden 同步)。

用例:download/error.rs 叶子四档 + effective_kind;online/tests/classify.rs 5 条
(AllSourcesFailed+leaf 404 ⇒ NotFound、无叶子 ⇒ NotConnected 保守、叶子一一映射、
单源自身 kind、导入侧 404≠Offline);import_online 增「404 不停」「真离线才停」
(共 7 条);download 增「sha1 形状非法仍用 sha512 校验成功」;presenter 增详情迟到闸门。
This commit is contained in:
AskaEth committed 2026-11-07 17:28:36 +08:00
1 parent 81278f55af
commit b394316df4
30 files changed
+658 -172

No files matched your search

+2 -2
View File
@@ -54,8 +54,8 @@ macro_rules! content_entries {
ContentFailedBody => ("Check the network, then retry.", "检查网络后重试。"),
ContentOfflineTitle => ("No connection", "未联网"),
ContentOfflineBody => (
"Content search needs the network and nothing is cached yet. Check your connection, then retry.",
"内容检索需要联网,本地还没有缓存。检查网络后重试。"
"Content search needs the network. Check your connection, then retry.",
"内容检索需要联网。检查网络后重试。"
),
ContentRetry => ("Retry", "重试"),
ContentLoadMore => ("Load more", "加载更多"),
+1 -1
View File
@@ -181,7 +181,7 @@ pub(super) const ROWS: &[(&str, &str, &str)] = &[
("ContentFailedTitle", "Could not load content", "内容加载失败"),
("ContentFailedBody", "Check the network, then retry.", "检查网络后重试。"),
("ContentOfflineTitle", "No connection", "未联网"),
("ContentOfflineBody", "Content search needs the network and nothing is cached yet. Check your connection, then retry.", "内容检索需要联网,本地还没有缓存。检查网络后重试。"),
("ContentOfflineBody", "Content search needs the network. Check your connection, then retry.", "内容检索需要联网。检查网络后重试。"),
("ContentRetry", "Retry", "重试"),
("ContentLoadMore", "Load more", "加载更多"),
("ContentNoMore", "No more results", "没有更多了"),