refactor(download): 纯搬移为 M289 腾出行数余量(config 单测 / engine 只读查询面)
两个文件都是 400 行零余量的硬线,本 mission 要加超时字段与失速诊断,先纯搬移: * `config.rs` 的 `#[cfg(test)] mod tests`(174 行)→ `config/tests.rs`, 原文件用 `#[cfg(test)] #[path = "config/tests.rs"] mod tests;` 声明; * `engine.rs` 的七个只读 getter(`config` / `concurrency_probe` / `client` / `region` / `mirrors` / `health` / `cache`,44 行)→ `engine/inspect.rs`。 逐字节未改:搬移块去缩进后与 HEAD 原文 `diff` 均为 exit 0。 行为零变化(同一批测试仍全绿);新文件都在 `crates/core/src/download/**` 内, 外部路径(`download::config::EngineConfig` 等)不变。
This commit is contained in:
1 parent
8b48c494cd
commit
61c8a4eff9
4 files changed
+237
-219
No files matched your search
@@ -223,178 +223,5 @@ pub fn publish(cache_root: &Path, next: DownloadTuning) -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
#[path = "config/tests.rs"]
|
||||||
use super::*;
|
mod tests;
|
||||||
use crate::setting::keys::{launcher_schema, launcher_version};
|
|
||||||
|
|
||||||
/// **守门③**:schema 的默认值 / 区间 / 键名与 `EngineConfig::default()` / 调优默认值取同一组常量。
|
|
||||||
/// 变异证明(只改实现侧):`EngineConfig::default()` 的并发写回 64、schema 默认值写成 16、
|
|
||||||
/// `MAX_CONCURRENCY` 改了而 schema 仍写 64 ⇒ 各自红。
|
|
||||||
#[test]
|
|
||||||
fn the_schema_contract_is_single_sourced() {
|
|
||||||
let schema = launcher_schema();
|
|
||||||
assert_eq!(schema.version(), launcher_version());
|
|
||||||
let cfg = EngineConfig::default();
|
|
||||||
let tune = DownloadTuning::default();
|
|
||||||
|
|
||||||
// 并发 1~64(0 张许可没意义);尝试次数 **0**~10(P2-1:0 = 只试一次,旧配置里真有)。
|
|
||||||
let contract: [(&str, i64, i64, usize); 2] = [
|
|
||||||
(
|
|
||||||
KEY_CONCURRENCY,
|
|
||||||
i64::try_from(DEFAULT_MAX_CONCURRENCY).expect("装得下"),
|
|
||||||
1,
|
|
||||||
MAX_CONCURRENCY,
|
|
||||||
),
|
|
||||||
(
|
|
||||||
KEY_RETRY_LIMIT,
|
|
||||||
i64::from(DEFAULT_MAX_ATTEMPTS_PER_SOURCE),
|
|
||||||
0,
|
|
||||||
usize::try_from(MAX_ATTEMPTS_PER_SOURCE).expect("装得下"),
|
|
||||||
),
|
|
||||||
];
|
|
||||||
for (key, default, min, max) in contract {
|
|
||||||
let spec = schema.spec(key).expect("键已登记");
|
|
||||||
assert_eq!(spec.default, serde_json::json!(default), "{key}");
|
|
||||||
assert_eq!(
|
|
||||||
spec.kind,
|
|
||||||
crate::setting::spec::ValueKind::Int {
|
|
||||||
min,
|
|
||||||
max: i64::try_from(max).expect("装得下"),
|
|
||||||
},
|
|
||||||
"{key}"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
assert_eq!(cfg.max_concurrency, DEFAULT_MAX_CONCURRENCY);
|
|
||||||
assert_eq!(tune.max_concurrency, DEFAULT_MAX_CONCURRENCY);
|
|
||||||
assert_eq!(cfg.max_attempts_per_source, DEFAULT_MAX_ATTEMPTS_PER_SOURCE);
|
|
||||||
assert_eq!(
|
|
||||||
tune.max_attempts_per_source,
|
|
||||||
DEFAULT_MAX_ATTEMPTS_PER_SOURCE
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `SettingSpec.doc` 是 `&'static str`(`concat!` 插不进常量),描述里的数字只能手写——这条钉住它,
|
|
||||||
/// 改常量不改文案就红(`catalog.rs` 会把这些 doc 当 JSON schema 的 description 发出去)。
|
|
||||||
#[test]
|
|
||||||
fn the_key_docs_quote_the_real_limits() {
|
|
||||||
let schema = launcher_schema();
|
|
||||||
let doc = |key: &str| schema.spec(key).expect("键已登记").doc;
|
|
||||||
assert!(doc(KEY_CONCURRENCY).contains(&format!("1~{MAX_CONCURRENCY}")));
|
|
||||||
assert!(doc(KEY_CONCURRENCY).contains(&format!("出厂 {DEFAULT_MAX_CONCURRENCY}")));
|
|
||||||
assert!(doc(KEY_RETRY_LIMIT).contains(&format!("出厂 {DEFAULT_MAX_ATTEMPTS_PER_SOURCE}")));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 未填 / 越界回落默认(不阻断下载);**`retry_limit: 0` 是合法值**,语义 = 只试一次。
|
|
||||||
///
|
|
||||||
/// 变异证明:把并发的区间过滤删掉 ⇒ `0` / `9999` 两条红;把尝试次数的 `.max(1)` 删掉 ⇒
|
|
||||||
/// `0 → 1` 那条红(引擎会拿到 0 次尝试);把 `0` 判成越界 ⇒ 同样红。
|
|
||||||
#[test]
|
|
||||||
fn missing_or_illegal_values_fall_back_to_the_defaults() {
|
|
||||||
assert_eq!(
|
|
||||||
DownloadTuning::from_settings(None, None, None),
|
|
||||||
DownloadTuning::default()
|
|
||||||
);
|
|
||||||
|
|
||||||
let just_over = i64::try_from(MAX_CONCURRENCY).expect("上限装得下") + 1;
|
|
||||||
for bad in [0_i64, -1, 9_999, just_over] {
|
|
||||||
let tune = DownloadTuning::from_settings(Some(bad), None, None);
|
|
||||||
assert_eq!(tune.max_concurrency, DEFAULT_MAX_CONCURRENCY, "{bad}");
|
|
||||||
}
|
|
||||||
// 0 与 1 都 = 只试一次:旧配置里的 0 不许回落成出厂 3(那正是「界面 0、引擎 3」)。
|
|
||||||
for zero_or_one in [0_i64, 1] {
|
|
||||||
let tune = DownloadTuning::from_settings(None, Some(zero_or_one), None);
|
|
||||||
assert_eq!(tune.max_attempts_per_source, 1, "{zero_or_one}");
|
|
||||||
}
|
|
||||||
for bad in [-1_i64, 9_999] {
|
|
||||||
let tune = DownloadTuning::from_settings(None, Some(bad), None);
|
|
||||||
assert_eq!(
|
|
||||||
tune.max_attempts_per_source,
|
|
||||||
DEFAULT_MAX_ATTEMPTS_PER_SOURCE
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let tune = DownloadTuning::from_settings(Some(2), Some(2), None);
|
|
||||||
assert_eq!(tune.max_concurrency, 2);
|
|
||||||
assert_eq!(tune.max_attempts_per_source, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 三态:**空串 ≠ 关**(这条是「设置项说假话」的高发点,M197 的键语义同源)。
|
|
||||||
#[test]
|
|
||||||
fn empty_gh_proxy_means_follow_builtin_not_off() {
|
|
||||||
assert_eq!(gh_proxy_override(""), GhProxyOverride::Builtin);
|
|
||||||
assert_eq!(gh_proxy_override(" "), GhProxyOverride::Builtin);
|
|
||||||
for off in [
|
|
||||||
"off", "OFF", " none ", "direct", "disable", "disabled", "no",
|
|
||||||
] {
|
|
||||||
assert_eq!(gh_proxy_override(off), GhProxyOverride::Off, "{off}");
|
|
||||||
}
|
|
||||||
assert_eq!(
|
|
||||||
gh_proxy_override(" https://gh.example/ "),
|
|
||||||
GhProxyOverride::Prefix("https://gh.example/".to_string())
|
|
||||||
);
|
|
||||||
// 未填(键不存在)也是 Builtin,不是 Off。
|
|
||||||
assert_eq!(
|
|
||||||
DownloadTuning::from_settings(None, None, None).gh_proxy,
|
|
||||||
GhProxyOverride::Builtin
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `apply_gh_proxy` 的三档真的改到档案上、并且**改到候选链上**(`expand()` 读的就是档案里那个
|
|
||||||
/// 前缀;自定义前缀那一档的链断言在 `shared.rs`)。变异证明:`Off` 分支改成原样返回 ⇒ `off` 红。
|
|
||||||
#[test]
|
|
||||||
fn gh_proxy_override_reaches_the_profile_and_the_chain() {
|
|
||||||
use crate::download::mirrors::{MirrorTable, SOURCE_GH_PROXY};
|
|
||||||
use crate::download::types::ResourceKind;
|
|
||||||
|
|
||||||
let url = "https://github.com/o/r/releases/download/v1/a.jar";
|
|
||||||
let table = MirrorTable::builtin();
|
|
||||||
let sources = |profile: &RegionProfile| -> Vec<String> {
|
|
||||||
table
|
|
||||||
.expand(url, ResourceKind::Other, profile)
|
|
||||||
.into_iter()
|
|
||||||
.map(|candidate| candidate.source)
|
|
||||||
.collect()
|
|
||||||
};
|
|
||||||
|
|
||||||
let mirror_first = RegionProfile::mirror_first(0);
|
|
||||||
let kept = DownloadTuning::default().apply_gh_proxy(mirror_first.clone());
|
|
||||||
assert_eq!(kept.gh_proxy, mirror_first.gh_proxy, "Builtin 不该动档案");
|
|
||||||
assert!(
|
|
||||||
sources(&kept).contains(&SOURCE_GH_PROXY.to_string()),
|
|
||||||
"出厂套前缀"
|
|
||||||
);
|
|
||||||
|
|
||||||
let off = DownloadTuning::from_settings(None, None, Some("off"))
|
|
||||||
.apply_gh_proxy(mirror_first.clone());
|
|
||||||
assert!(
|
|
||||||
!sources(&off).contains(&SOURCE_GH_PROXY.to_string()),
|
|
||||||
"关了就没候选"
|
|
||||||
);
|
|
||||||
|
|
||||||
let prefix = DownloadTuning::from_settings(None, None, Some("https://gh.example/"))
|
|
||||||
.apply_gh_proxy(mirror_first);
|
|
||||||
assert_eq!(prefix.gh_proxy.as_deref(), Some("https://gh.example/"));
|
|
||||||
assert!(prefix.gh_proxy_enabled(), "前缀生效");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 每个数据根的调优互不串味(一个根改成 2 不该改另一个根的引擎)。
|
|
||||||
/// 变异证明:把 `wanted`/`publish` 的键改回单一进程级槽位 ⇒ 第二个根读到 2,红。
|
|
||||||
#[test]
|
|
||||||
fn tuning_is_per_cache_root_and_no_change_is_reported_as_such() {
|
|
||||||
let a = PathBuf::from("/tmp/ull-tuning-a");
|
|
||||||
let b = PathBuf::from("/tmp/ull-tuning-b");
|
|
||||||
assert_eq!(wanted(&a), DownloadTuning::default());
|
|
||||||
|
|
||||||
let changed = DownloadTuning::from_settings(Some(2), None, None);
|
|
||||||
assert!(publish(&a, changed.clone()), "真变了要报变更");
|
|
||||||
assert_eq!(wanted(&a), changed);
|
|
||||||
assert!(!publish(&a, changed.clone()), "同值不该报变更");
|
|
||||||
assert_eq!(wanted(&b), DownloadTuning::default(), "别的根不受影响");
|
|
||||||
|
|
||||||
assert!(
|
|
||||||
publish(&a, DownloadTuning::default()),
|
|
||||||
"恢复默认也是一次变更"
|
|
||||||
);
|
|
||||||
assert_eq!(wanted(&a), DownloadTuning::default());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,175 @@
|
|||||||
|
//! `download::config` 的单测:**从 `config.rs` 拆出只为守 400 行硬线**(M289 加超时字段前先纯搬移,逐字节未改)。
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use crate::setting::keys::{launcher_schema, launcher_version};
|
||||||
|
|
||||||
|
/// **守门③**:schema 的默认值 / 区间 / 键名与 `EngineConfig::default()` / 调优默认值取同一组常量。
|
||||||
|
/// 变异证明(只改实现侧):`EngineConfig::default()` 的并发写回 64、schema 默认值写成 16、
|
||||||
|
/// `MAX_CONCURRENCY` 改了而 schema 仍写 64 ⇒ 各自红。
|
||||||
|
#[test]
|
||||||
|
fn the_schema_contract_is_single_sourced() {
|
||||||
|
let schema = launcher_schema();
|
||||||
|
assert_eq!(schema.version(), launcher_version());
|
||||||
|
let cfg = EngineConfig::default();
|
||||||
|
let tune = DownloadTuning::default();
|
||||||
|
|
||||||
|
// 并发 1~64(0 张许可没意义);尝试次数 **0**~10(P2-1:0 = 只试一次,旧配置里真有)。
|
||||||
|
let contract: [(&str, i64, i64, usize); 2] = [
|
||||||
|
(
|
||||||
|
KEY_CONCURRENCY,
|
||||||
|
i64::try_from(DEFAULT_MAX_CONCURRENCY).expect("装得下"),
|
||||||
|
1,
|
||||||
|
MAX_CONCURRENCY,
|
||||||
|
),
|
||||||
|
(
|
||||||
|
KEY_RETRY_LIMIT,
|
||||||
|
i64::from(DEFAULT_MAX_ATTEMPTS_PER_SOURCE),
|
||||||
|
0,
|
||||||
|
usize::try_from(MAX_ATTEMPTS_PER_SOURCE).expect("装得下"),
|
||||||
|
),
|
||||||
|
];
|
||||||
|
for (key, default, min, max) in contract {
|
||||||
|
let spec = schema.spec(key).expect("键已登记");
|
||||||
|
assert_eq!(spec.default, serde_json::json!(default), "{key}");
|
||||||
|
assert_eq!(
|
||||||
|
spec.kind,
|
||||||
|
crate::setting::spec::ValueKind::Int {
|
||||||
|
min,
|
||||||
|
max: i64::try_from(max).expect("装得下"),
|
||||||
|
},
|
||||||
|
"{key}"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
assert_eq!(cfg.max_concurrency, DEFAULT_MAX_CONCURRENCY);
|
||||||
|
assert_eq!(tune.max_concurrency, DEFAULT_MAX_CONCURRENCY);
|
||||||
|
assert_eq!(cfg.max_attempts_per_source, DEFAULT_MAX_ATTEMPTS_PER_SOURCE);
|
||||||
|
assert_eq!(
|
||||||
|
tune.max_attempts_per_source,
|
||||||
|
DEFAULT_MAX_ATTEMPTS_PER_SOURCE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `SettingSpec.doc` 是 `&'static str`(`concat!` 插不进常量),描述里的数字只能手写——这条钉住它,
|
||||||
|
/// 改常量不改文案就红(`catalog.rs` 会把这些 doc 当 JSON schema 的 description 发出去)。
|
||||||
|
#[test]
|
||||||
|
fn the_key_docs_quote_the_real_limits() {
|
||||||
|
let schema = launcher_schema();
|
||||||
|
let doc = |key: &str| schema.spec(key).expect("键已登记").doc;
|
||||||
|
assert!(doc(KEY_CONCURRENCY).contains(&format!("1~{MAX_CONCURRENCY}")));
|
||||||
|
assert!(doc(KEY_CONCURRENCY).contains(&format!("出厂 {DEFAULT_MAX_CONCURRENCY}")));
|
||||||
|
assert!(doc(KEY_RETRY_LIMIT).contains(&format!("出厂 {DEFAULT_MAX_ATTEMPTS_PER_SOURCE}")));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 未填 / 越界回落默认(不阻断下载);**`retry_limit: 0` 是合法值**,语义 = 只试一次。
|
||||||
|
///
|
||||||
|
/// 变异证明:把并发的区间过滤删掉 ⇒ `0` / `9999` 两条红;把尝试次数的 `.max(1)` 删掉 ⇒
|
||||||
|
/// `0 → 1` 那条红(引擎会拿到 0 次尝试);把 `0` 判成越界 ⇒ 同样红。
|
||||||
|
#[test]
|
||||||
|
fn missing_or_illegal_values_fall_back_to_the_defaults() {
|
||||||
|
assert_eq!(
|
||||||
|
DownloadTuning::from_settings(None, None, None),
|
||||||
|
DownloadTuning::default()
|
||||||
|
);
|
||||||
|
|
||||||
|
let just_over = i64::try_from(MAX_CONCURRENCY).expect("上限装得下") + 1;
|
||||||
|
for bad in [0_i64, -1, 9_999, just_over] {
|
||||||
|
let tune = DownloadTuning::from_settings(Some(bad), None, None);
|
||||||
|
assert_eq!(tune.max_concurrency, DEFAULT_MAX_CONCURRENCY, "{bad}");
|
||||||
|
}
|
||||||
|
// 0 与 1 都 = 只试一次:旧配置里的 0 不许回落成出厂 3(那正是「界面 0、引擎 3」)。
|
||||||
|
for zero_or_one in [0_i64, 1] {
|
||||||
|
let tune = DownloadTuning::from_settings(None, Some(zero_or_one), None);
|
||||||
|
assert_eq!(tune.max_attempts_per_source, 1, "{zero_or_one}");
|
||||||
|
}
|
||||||
|
for bad in [-1_i64, 9_999] {
|
||||||
|
let tune = DownloadTuning::from_settings(None, Some(bad), None);
|
||||||
|
assert_eq!(
|
||||||
|
tune.max_attempts_per_source,
|
||||||
|
DEFAULT_MAX_ATTEMPTS_PER_SOURCE
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let tune = DownloadTuning::from_settings(Some(2), Some(2), None);
|
||||||
|
assert_eq!(tune.max_concurrency, 2);
|
||||||
|
assert_eq!(tune.max_attempts_per_source, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 三态:**空串 ≠ 关**(这条是「设置项说假话」的高发点,M197 的键语义同源)。
|
||||||
|
#[test]
|
||||||
|
fn empty_gh_proxy_means_follow_builtin_not_off() {
|
||||||
|
assert_eq!(gh_proxy_override(""), GhProxyOverride::Builtin);
|
||||||
|
assert_eq!(gh_proxy_override(" "), GhProxyOverride::Builtin);
|
||||||
|
for off in [
|
||||||
|
"off", "OFF", " none ", "direct", "disable", "disabled", "no",
|
||||||
|
] {
|
||||||
|
assert_eq!(gh_proxy_override(off), GhProxyOverride::Off, "{off}");
|
||||||
|
}
|
||||||
|
assert_eq!(
|
||||||
|
gh_proxy_override(" https://gh.example/ "),
|
||||||
|
GhProxyOverride::Prefix("https://gh.example/".to_string())
|
||||||
|
);
|
||||||
|
// 未填(键不存在)也是 Builtin,不是 Off。
|
||||||
|
assert_eq!(
|
||||||
|
DownloadTuning::from_settings(None, None, None).gh_proxy,
|
||||||
|
GhProxyOverride::Builtin
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `apply_gh_proxy` 的三档真的改到档案上、并且**改到候选链上**(`expand()` 读的就是档案里那个
|
||||||
|
/// 前缀;自定义前缀那一档的链断言在 `shared.rs`)。变异证明:`Off` 分支改成原样返回 ⇒ `off` 红。
|
||||||
|
#[test]
|
||||||
|
fn gh_proxy_override_reaches_the_profile_and_the_chain() {
|
||||||
|
use crate::download::mirrors::{MirrorTable, SOURCE_GH_PROXY};
|
||||||
|
use crate::download::types::ResourceKind;
|
||||||
|
|
||||||
|
let url = "https://github.com/o/r/releases/download/v1/a.jar";
|
||||||
|
let table = MirrorTable::builtin();
|
||||||
|
let sources = |profile: &RegionProfile| -> Vec<String> {
|
||||||
|
table
|
||||||
|
.expand(url, ResourceKind::Other, profile)
|
||||||
|
.into_iter()
|
||||||
|
.map(|candidate| candidate.source)
|
||||||
|
.collect()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mirror_first = RegionProfile::mirror_first(0);
|
||||||
|
let kept = DownloadTuning::default().apply_gh_proxy(mirror_first.clone());
|
||||||
|
assert_eq!(kept.gh_proxy, mirror_first.gh_proxy, "Builtin 不该动档案");
|
||||||
|
assert!(
|
||||||
|
sources(&kept).contains(&SOURCE_GH_PROXY.to_string()),
|
||||||
|
"出厂套前缀"
|
||||||
|
);
|
||||||
|
|
||||||
|
let off = DownloadTuning::from_settings(None, None, Some("off"))
|
||||||
|
.apply_gh_proxy(mirror_first.clone());
|
||||||
|
assert!(
|
||||||
|
!sources(&off).contains(&SOURCE_GH_PROXY.to_string()),
|
||||||
|
"关了就没候选"
|
||||||
|
);
|
||||||
|
|
||||||
|
let prefix = DownloadTuning::from_settings(None, None, Some("https://gh.example/"))
|
||||||
|
.apply_gh_proxy(mirror_first);
|
||||||
|
assert_eq!(prefix.gh_proxy.as_deref(), Some("https://gh.example/"));
|
||||||
|
assert!(prefix.gh_proxy_enabled(), "前缀生效");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 每个数据根的调优互不串味(一个根改成 2 不该改另一个根的引擎)。
|
||||||
|
/// 变异证明:把 `wanted`/`publish` 的键改回单一进程级槽位 ⇒ 第二个根读到 2,红。
|
||||||
|
#[test]
|
||||||
|
fn tuning_is_per_cache_root_and_no_change_is_reported_as_such() {
|
||||||
|
let a = PathBuf::from("/tmp/ull-tuning-a");
|
||||||
|
let b = PathBuf::from("/tmp/ull-tuning-b");
|
||||||
|
assert_eq!(wanted(&a), DownloadTuning::default());
|
||||||
|
|
||||||
|
let changed = DownloadTuning::from_settings(Some(2), None, None);
|
||||||
|
assert!(publish(&a, changed.clone()), "真变了要报变更");
|
||||||
|
assert_eq!(wanted(&a), changed);
|
||||||
|
assert!(!publish(&a, changed.clone()), "同值不该报变更");
|
||||||
|
assert_eq!(wanted(&b), DownloadTuning::default(), "别的根不受影响");
|
||||||
|
|
||||||
|
assert!(
|
||||||
|
publish(&a, DownloadTuning::default()),
|
||||||
|
"恢复默认也是一次变更"
|
||||||
|
);
|
||||||
|
assert_eq!(wanted(&a), DownloadTuning::default());
|
||||||
|
}
|
||||||
@@ -35,6 +35,8 @@ use super::types::{
|
|||||||
SOURCE_OFFICIAL,
|
SOURCE_OFFICIAL,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
mod inspect;
|
||||||
|
|
||||||
/// 一次成功尝试的产物描述。
|
/// 一次成功尝试的产物描述。
|
||||||
pub(crate) struct AttemptOk {
|
pub(crate) struct AttemptOk {
|
||||||
/// 文件总字节数。
|
/// 文件总字节数。
|
||||||
@@ -94,50 +96,6 @@ impl DownloadEngine {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 配置。
|
|
||||||
#[must_use]
|
|
||||||
pub fn config(&self) -> &EngineConfig {
|
|
||||||
&self.cfg
|
|
||||||
}
|
|
||||||
|
|
||||||
/// **真实并发闸门**此刻的许可数(探针,M193):读 [`Self::acquire`] 会去抢的那张
|
|
||||||
/// `Semaphore`,**不是** `config().max_concurrency`。有下载在飞时偏小,空闲等于容量。
|
|
||||||
#[must_use]
|
|
||||||
pub fn concurrency_probe(&self) -> usize {
|
|
||||||
self.sem.available_permits()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// HTTP 客户端(同一条连接池与超时配置):给「一锤子查询」用(如 Adoptium 版本查询),
|
|
||||||
/// 没必要为了一个 GET 再造一个 client。
|
|
||||||
#[must_use]
|
|
||||||
pub fn client(&self) -> &reqwest::Client {
|
|
||||||
&self.http
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 当前地区档案(设置页展示)。
|
|
||||||
#[must_use]
|
|
||||||
pub fn region(&self) -> &RegionProfile {
|
|
||||||
&self.region
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 镜像表(`game::java` 的 Oracle / MS / Zulu 分发表在这里查)。
|
|
||||||
#[must_use]
|
|
||||||
pub fn mirrors(&self) -> &MirrorTable {
|
|
||||||
&self.mirrors
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 健康度注册表(诊断页)。
|
|
||||||
#[must_use]
|
|
||||||
pub fn health(&self) -> &HealthRegistry {
|
|
||||||
&self.health
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 内容寻址缓存。
|
|
||||||
#[must_use]
|
|
||||||
pub fn cache(&self) -> &ContentCache {
|
|
||||||
&self.cache
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 候选规划:镜像展开 → 官方位置保持不变 → 其余按健康度排序。
|
/// 候选规划:镜像展开 → 官方位置保持不变 → 其余按健康度排序。
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn plan(&self, req: &DownloadRequest, now_ms: u64) -> Vec<Candidate> {
|
pub fn plan(&self, req: &DownloadRequest, now_ms: u64) -> Vec<Candidate> {
|
||||||
|
|||||||
@@ -0,0 +1,58 @@
|
|||||||
|
//! 引擎的只读查询面:**从 `engine.rs` 拆出只为守 400 行硬线**(M289 加失速诊断前先纯搬移,逐字节未改)。
|
||||||
|
//!
|
||||||
|
//! 这里只有「读」——配置、并发闸门探针、HTTP 客户端、地区档案、镜像表、健康度、内容缓存。
|
||||||
|
//! 编排(候选循环、退避、落盘)仍在 [`super`]。
|
||||||
|
|
||||||
|
use super::super::cache::ContentCache;
|
||||||
|
use super::super::config::EngineConfig;
|
||||||
|
use super::super::health::HealthRegistry;
|
||||||
|
use super::super::mirrors::MirrorTable;
|
||||||
|
use super::super::region::RegionProfile;
|
||||||
|
use super::DownloadEngine;
|
||||||
|
|
||||||
|
impl DownloadEngine {
|
||||||
|
/// 配置。
|
||||||
|
#[must_use]
|
||||||
|
pub fn config(&self) -> &EngineConfig {
|
||||||
|
&self.cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
/// **真实并发闸门**此刻的许可数(探针,M193):读 [`Self::acquire`] 会去抢的那张
|
||||||
|
/// `Semaphore`,**不是** `config().max_concurrency`。有下载在飞时偏小,空闲等于容量。
|
||||||
|
#[must_use]
|
||||||
|
pub fn concurrency_probe(&self) -> usize {
|
||||||
|
self.sem.available_permits()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// HTTP 客户端(同一条连接池与超时配置):给「一锤子查询」用(如 Adoptium 版本查询),
|
||||||
|
/// 没必要为了一个 GET 再造一个 client。
|
||||||
|
#[must_use]
|
||||||
|
pub fn client(&self) -> &reqwest::Client {
|
||||||
|
&self.http
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 当前地区档案(设置页展示)。
|
||||||
|
#[must_use]
|
||||||
|
pub fn region(&self) -> &RegionProfile {
|
||||||
|
&self.region
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 镜像表(`game::java` 的 Oracle / MS / Zulu 分发表在这里查)。
|
||||||
|
#[must_use]
|
||||||
|
pub fn mirrors(&self) -> &MirrorTable {
|
||||||
|
&self.mirrors
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 健康度注册表(诊断页)。
|
||||||
|
#[must_use]
|
||||||
|
pub fn health(&self) -> &HealthRegistry {
|
||||||
|
&self.health
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 内容寻址缓存。
|
||||||
|
#[must_use]
|
||||||
|
pub fn cache(&self) -> &ContentCache {
|
||||||
|
&self.cache
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
Reference in new issue
Block a user