feat(download): 把 download.region / download.mirror_preference 接进源选择(M294)

两个键此前在引擎侧零消费者:设置页画着三档 chip,改它不影响任何一次下载。
现在它们是 RegionProfile 之上的一层显式覆盖(读时叠加,不落盘,region.json
仍是自动判定的结论):

  显式 mirror_preference(official/mirror)
    > 显式 region(cn/global)
      > 自动探测(时区+语言+系统信号)与 24h 缓存

- core::download::preference(新):两个枚举的 from_raw(未知值/空串 ⇒ auto)
  与 apply;两个键都落到 RegionMode 这一个「谁在前」开关上,不造第二套排序
- region::RegionProfile::overridden:在已有判定上叠一层模式(探测逻辑不动)
- DownloadTuning 加 region / mirror_preference 与 apply_source_selection
  (组合顺序 = 优先级),shared::build 改用它;默认 Auto ⇒ 逐值等于今天
- 未进 RawTuning:CLI 的 tuning() 用完整字段字面量构造它,加字段会连累
  crates/cli(不在本 mission scope),改走 with_source_selection 入口
- presenter 的 tuning_of 读这两个键(否则 GUI 侧仍是假行)

判据断具体源名序列:不设/auto/未知 ⇒ ["bmclapi","official"] /
["official","bmclapi"] 逐项不变;official/mirror/cn/global ⇒ 顺序跟着换;
另有一条从设置原文到引擎 plan() 的端到端用例。
This commit is contained in:
worker-mirrorwire committed 2026-11-13 08:26:30 +08:00
1 parent c2fc4b7f26
commit 0f64acbd05
9 files changed
+454 -5

No files matched your search

+13 -3
View File
@@ -17,7 +17,9 @@
//! download.gh_proxy ────┼─→ DownloadTuning(core 决定默认值与夹取)─→ shared::set_tuning
//! download.throughput_floor_kib ─┤ (引擎重建时生效)
//! download.stall_timeout_secs ───┤
//! download.response_timeout_secs ┘
//! download.response_timeout_secs ┤
//! download.region ───────────────┤ M294:两个枚举键,走
//! download.mirror_preference ────┘ `with_source_selection`(回落 = auto)
//! ```
//!
//! M292:后三个键(吞吐下限 / 无进展窗口 / 单次请求上界)只经 [`tuning_of`] 进引擎,**没有**对应的
@@ -250,11 +252,15 @@ fn gh_proxy_state(state: &GhProxyOverride) -> String {
///
/// M292:六个键一起读(并发 / 单源尝试 / gh-proxy / 吞吐下限 / 无进展窗口 / 单次请求上界),
/// 缺省与越界一律由 core 的 [`DownloadTuning::from_raw`] 回落——本函数不判断任何区间。
///
/// M294:另加两个「源选择」键(`download.region` / `download.mirror_preference`),它们是**枚举**
/// 而不是数字,走 [`DownloadTuning::with_source_selection`](同一个翻译层,回落 = `auto`)。
/// 少了这一步,那两行 chip 就只是画着好看——本轮之前正是如此。
#[must_use]
pub(crate) fn tuning_of(env: &HostEnv) -> DownloadTuning {
use unlucky_core::download::config::{
RawTuning, KEY_CHUNK_STALL, KEY_CONCURRENCY, KEY_GH_PROXY, KEY_RESPONSE_TIMEOUT,
KEY_RETRY_LIMIT, KEY_THROUGHPUT_FLOOR,
RawTuning, KEY_CHUNK_STALL, KEY_CONCURRENCY, KEY_GH_PROXY, KEY_MIRROR_PREFERENCE,
KEY_REGION, KEY_RESPONSE_TIMEOUT, KEY_RETRY_LIMIT, KEY_THROUGHPUT_FLOOR,
};
let store = env.store();
let doc = store.doc();
@@ -270,6 +276,10 @@ pub(crate) fn tuning_of(env: &HostEnv) -> DownloadTuning {
stall_timeout_secs: doc.effective_i64(KEY_CHUNK_STALL),
response_timeout_secs: doc.effective_i64(KEY_RESPONSE_TIMEOUT),
})
.with_source_selection(
doc.effective_str(KEY_REGION),
doc.effective_str(KEY_MIRROR_PREFERENCE),
)
}
/// 把当前设置灌进 core 的下载调优(按数据根),返回**是否真的变了**(变了就失效该根的引擎)。
@@ -382,3 +382,17 @@ fn the_three_timeout_keys_travel_from_the_file_to_the_engine_config() {
assert_eq!(tuning_of(&env), DownloadTuning::default());
std::fs::remove_dir_all(&dir).ok();
}
/// **M294**:两个「源选择」键真的进了 `DownloadTuning`(删掉 `with_source_selection` ⇒ 两断言红)。
#[test]
fn the_two_source_selection_keys_reach_the_tuning() {
use unlucky_core::download::{MirrorPreference, RegionPreference};
let (dir, env) = env_with(
"source-selection",
serde_json::json!({ "download": { "region": "global", "mirror_preference": "official" } }),
);
let tuning = tuning_of(&env);
assert_eq!(tuning.region, RegionPreference::Global);
assert_eq!(tuning.mirror_preference, MirrorPreference::Official);
std::fs::remove_dir_all(&dir).ok();
}