M205 r1: 修 config.rs 的假话与「最坏 9」的措辞,UA 说明改成事实

- download/config.rs: KEY_GH_PROXY 的「本文件没有断言把它与 schema 登记绑起来」是 M205 自己造出来的假话,改成指向 proxy.rs 的新用例(纯文字替换,400 行不变)
- addon/online/download.rs: 断言消息与边界段改说「出厂档 3x3 = 9;retry_limit 调到 N 时是 3xN(上限 10 => 30)」,别再让人把出厂值读成事实上限
- presenter/host/addon/http.rs: 「Modrinth 的请求走 get_via_engine」是错的(实际走 core::addon::online::EngineTransport -> download_bytes,带的是引擎 UA;get_via_engine 今天只有单测在用),改成事实
This commit is contained in:
tower-worker committed 2026-11-09 11:20:27 +08:00
1 parent d4aa3b23f4
commit 67a03f9402
3 files changed
+19 -14

No files matched your search

+9 -6
View File
@@ -47,21 +47,24 @@ use super::transport::{OnlineError, OnlineErrorKind, OnlineFuture};
/// 那个默认值会因为**用户的**配置而变);这里的 3 是内容库元数据请求的产品口径,没有设置键,也不该 /// 那个默认值会因为**用户的**配置而变);这里的 3 是内容库元数据请求的产品口径,没有设置键,也不该
/// 被某个设置项的出厂默认牵着走。 /// 被某个设置项的出厂默认牵着走。
/// ///
/// **边界**:最坏情况 = [`RETRY_ATTEMPTS`](外层)× [`DEFAULT_MAX_ATTEMPTS_PER_SOURCE`](引擎每个源 /// **边界**:真实请求数 = [`RETRY_ATTEMPTS`](外层)× 引擎每源预算(`download.retry_limit`,出厂
/// 一次请求内的尝试)= 9 次真实网络请求。下面两条注解级断言(编译期求值)钉住这个乘积:任一侧想改, /// [`DEFAULT_MAX_ATTEMPTS_PER_SOURCE`])。**出厂档**是 3 × 3 = 9;用户把 `retry_limit` 调到 N 时是
/// 都得先读到这段判据,而不是被一次「统一常量」的顺带改动悄悄翻倍。 /// 3 × N(schema 上限 `MAX_ATTEMPTS_PER_SOURCE` = 10 ⇒ 30)——**9 只是出厂档的数,不是事实上限**,
/// 这正是本仓反复吃亏的「把出厂值说成上限」。下面两条注解级断言(编译期求值)钉的也只是**出厂档**:
/// 出厂默认想改,就得先读到这段判据,而不是被一次「统一常量」的顺带改动悄悄翻倍。
pub const RETRY_ATTEMPTS: u32 = 3; pub const RETRY_ATTEMPTS: u32 = 3;
/// 外层预算被改了吗(改之前先读 [`RETRY_ATTEMPTS`] 的 doc:它不是引擎的每源次数)。 /// 外层预算被改了吗(改之前先读 [`RETRY_ATTEMPTS`] 的 doc:它不是引擎的每源次数)。
const _: () = assert!( const _: () = assert!(
RETRY_ATTEMPTS == 3, RETRY_ATTEMPTS == 3,
"外层下载预算变了:它不是 download::config 的每源尝试次数,改它要单独一个决定" "外层下载预算(出厂档 3)变了:它不是 download::config 的每源尝试次数,改它要单独一个决定"
); );
/// 最坏情况下的真实请求数(3 × 3)——外层与引擎每源这两个「3」不共享来源,乘积才是事实。 /// **出厂档**最坏请求数(外层 3 × 引擎每源出厂 3)——两个「3」不共享来源,乘积才是事实。
/// 用户把 `download.retry_limit` 调大后真实最坏是 3 × N,与本断言无关(那头是运行时配置,编译期钉不了)。
const _: () = assert!( const _: () = assert!(
RETRY_ATTEMPTS as u64 * DEFAULT_MAX_ATTEMPTS_PER_SOURCE as u64 == 9, RETRY_ATTEMPTS as u64 * DEFAULT_MAX_ATTEMPTS_PER_SOURCE as u64 == 9,
"最坏真实请求数变了(外层 × 引擎每源):先读 RETRY_ATTEMPTS 的 doc 再改" "出厂档最坏真实请求数变了(外层 3 × 引擎每源出厂 3 = 9;用户把 retry_limit 调到 N 时是 3 × N):先读 doc"
); );
/// 一次下载请求(只含「引擎需要什么」,不含任何站点字段)。 /// 一次下载请求(只含「引擎需要什么」,不含任何站点字段)。
+3 -3
View File
@@ -35,9 +35,9 @@ pub const KEY_CONCURRENCY: &str = "download.concurrency";
pub const KEY_RETRY_LIMIT: &str = "download.retry_limit"; pub const KEY_RETRY_LIMIT: &str = "download.retry_limit";
/// gh-proxy 前缀覆盖键(三态语义见 [`gh_proxy_override`])。**已登记**:`setting::keys::proxy` 的 /// gh-proxy 前缀覆盖键(三态语义见 [`gh_proxy_override`])。**已登记**:`setting::keys::proxy` 的
/// `specs()` 里有它(文本 / 出厂空串),presenter 与 CLI 的宿主都按这个常量读,读不到 ⇒ /// `specs()` 里有它(文本 / 出厂空串),presenter 与 CLI 的宿主都按这个常量读,读不到 ⇒
/// [`GhProxyOverride::Builtin`]。**弱在哪(别当死键删)**:本文件没有断言把它与 schema 登记绑起来, /// [`GhProxyOverride::Builtin`]。**绑定在哪(别当死键删)**:常量与 schema 登记的对应关系由
/// 常量值被改名或写错时这里不红,行为只会在宿主侧静默退化成 `Builtin`(用户填的 `off` 被忽略); /// `setting::keys::proxy` 的 `the_gh_proxy_key_is_bound_to_the_schema_registration`(M205)钉住:写错就红;
/// 拦住行为退化的是 `empty_gh_proxy_means_follow_builtin_not_off` 与 `shared` 的「调优 → 候选链」。 /// 它抓不住两侧同时改名(公开改名)。行为退化由 `empty_gh_proxy_means_follow_builtin_not_off` 与 `shared` 的候选链拦。
pub const KEY_GH_PROXY: &str = "download.gh_proxy"; pub const KEY_GH_PROXY: &str = "download.gh_proxy";
/// 引擎配置。 /// 引擎配置。
+7 -5
View File
@@ -25,18 +25,20 @@ use unlucky_core::download::{DownloadRequest, ResourceKind};
use super::super::env::HostEnv; use super::super::env::HostEnv;
/// 站点要求的 User-Agent(Modrinth 明文要求带联系方式,否则限流)。 /// 站点要求的 User-Agent(`(+联系方式)` 这一段来自 Modrinth 的 UA 政策:带联系方式,否则限流)。
/// ///
/// ## 为什么这条 UA 要单独看 /// ## 为什么这条 UA 要单独看
/// ///
/// 它**只**出现在带 header 的那条路径(`engine.client()` 直发,今天是 CurseForge 的 `X-API-KEY`), /// 它**只**出现在带 header 的那条路径(`engine.client()` 直发),而今天走这条路径的只有 CurseForge 的
/// 而 Modrinth 的请求走 [`get_via_engine`] —— 那条用的是引擎自己的 UA(`EngineConfig::user_agent`)。 /// 搜索(`x-api-key`)。**Modrinth 看到的是另一个 UA**:内容库的 Modrinth 请求经
/// 也就是说进程里同时存在两个 UA 字符串,改一处不会带动另一处。 /// `core::addon::online::EngineTransport` → `DownloadEngine::download_bytes`,带的是引擎自己的
/// `EngineConfig::user_agent`(`UnluckyLauncher/<ver>`,无联系方式)。两条 UA 同时活着,改一处不带另一处;
/// [`get_via_engine`] 那条无 header 的分支今天只有单测在用(生产里 Modrinth 不走它)。
/// ///
/// ## 版本号来自 `CARGO_PKG_VERSION`(M205) /// ## 版本号来自 `CARGO_PKG_VERSION`(M205)
/// ///
/// 此前写死 `Unlucky-Launcher/0.1`,而当时的版本已经是 0.2.3:写死的版本号只会一年一年地落后,而 /// 此前写死 `Unlucky-Launcher/0.1`,而当时的版本已经是 0.2.3:写死的版本号只会一年一年地落后,而
/// Modrinth 按 UA 做限流与「出问题怎么联系你」的登记 —— UA 里说错版本,就是给了错信息。 /// 站点按 UA 做限流与「出问题怎么联系你」的登记 —— UA 里说错版本,就是给了错信息。
/// ///
/// **产品名与联系方式的写法不跟着版本动**:`Unlucky-Launcher/<version> (+<repo URL>)` 这个形状、 /// **产品名与联系方式的写法不跟着版本动**:`Unlucky-Launcher/<version> (+<repo URL>)` 这个形状、
/// 以及那个 GitHub 地址,是站点侧识别我们、以及知道去哪儿联系的地方;改它是单独的产品决定,不在 /// 以及那个 GitHub 地址,是站点侧识别我们、以及知道去哪儿联系的地方;改它是单独的产品决定,不在