Skip to content

fix(download): 上报当前下载速度而不是整段平均速度 - #88

Merged
std-microblock merged 1 commit into
std-microblock:masterfrom
std-external:fix/download-speed-window
Oct 13, 2026
Merged

std-microblock merged 1 commit into
std-microblock:masterfrom
std-external:fix/download-speed-window

Conversation

@std-external

Copy link
Copy Markdown
Contributor

问题

群里的报告(Celeste Coders):下载 Mod 时「偶发下载速度越来越慢」。查下来有两半:

  • 镜像侧:weg.fan 的下载 CDN(302 → celeste-mirror-cdn-2.wegfan.com)速度可以差几十倍、部分对象不支持 Range、缺文件还返回 200 + JSON。这些不是本仓库能修的。
  • 客户端侧(本 PR):界面上那个「速度」根本不是当前速度,而是从下载开始到现在的平均速度,所以只要镜像中途变慢,数字就会一路平滑下滑 —— 看到的就是「越下越慢」而不是「卡住了」;单线程路径还只在进度前进 0.1% 时才上报,卡住时数字干脆不动。

根因(客户端那半)

// src-tauri/src/ureq.rs(改动前)
fn report_progress(cb, downloaded, total, started: Instant) {
    let elapsed = started.elapsed().as_secs_f64().max(0.001);
    cb(DownloadCallbackInfo {
        ...
        speed_bytes_per_sec: downloaded as f64 / elapsed,   // ← 整段平均
    });
}

前端原样显示这个数字(DownloadList.tsx:22 formatSpeed、:168/:273),并没有「平均」字样。

实测:同一台 CDN、同一个 URL(本机直连,不走代理)

https://celeste.weg.fan/api/v2/download/gamebanana-files/831746(Mt Everest,17,488,764 字节)连续下 3 次:

#1: t=1.1s 0.26MB | t=2.6s 0.46MB | t=3.6s 0.59MB | t=4.8s 0.79MB | t=5.9s 1.25MB | t=6.9s 1.97MB | t=7.9s 3.15MB
    → 8.0s 只下了 3.34MB,平均 0.42MB/s
#2: 17.49MB / 0.6s = 27.0MB/s
#3: 17.49MB / 0.8s = 23.1MB/s

把上面这一条真实的慢速轨迹喂给两种算法:

t 已下载 旧(整段平均) 新(3s 窗口)
1.1s 0.26 MB 0.24 MB/s 0.24 MB/s
2.6s 0.46 MB 0.18 MB/s 0.13 MB/s
3.6s 0.59 MB 0.16 MB/s 0.13 MB/s
4.8s 0.79 MB 0.17 MB/s 0.17 MB/s
5.9s 1.25 MB 0.21 MB/s 0.42 MB/s
6.9s 1.97 MB 0.29 MB/s 0.72 MB/s
7.9s 3.15 MB 0.40 MB/s 1.18 MB/s

旧算法一路从 0.24 掉到 0.16 再慢慢爬,看着就是「越来越慢」;新算法从一开始就如实报 0.13 MB/s、镜像恢复后立刻升到 1.18 MB/s。

改动

  • 新增 SpeedMeter(ureq.rs):按最近 3 秒的采样窗口算速度,下载刚开始窗口没铺满时退回整段平均;窗口外只保留一个采样点,避免采样间隔过短导致数字乱跳。
  • report_progress 不再自己算速度,改为接收调用方算好的数值。
  • 单线程路径也按 PROGRESS_INTERVAL(200ms,与多线程路径一致)上报,不再只在进度 +0.1% 时才报 —— 卡住时速度会掉到 0,而不是停在上一次的数字。
  • 重试导致归零重下时会重建 SpeedMeter。

没有改网络行为:8 线程分段、暂停、重试、Range 探测都没动(和 #84 / #85 / #87 不重叠)。

验证

  • cd src-tauri && cargo test --lib → 109 passed; 0 failed(新增 2 个:窗口不丢旧采样点、卡顿后不再被历史高速率拉高)。
  • cargo fmt --all -- --check 通过。

顺带查到的镜像侧事实(不在本 PR 范围,供参考)

现象 实测
同一 URL 速度差 60 倍 0.42 MB/s vs 27.0 MB/s(上面)
部分对象忽略 Range gamebanana-files/1845372:Range: bytes=0-0 返回 200 + 整个 9,109,998 字节(重复 2 次一致)→ CeleMod 的 probe_range 判定不支持分段,回退单连接(ureq.rs:346、:354)
不存在的文件返回 200 + JSON gamebanana-files/invalid → HTTP 200、content-type: application/json、54 字节 {"data":null,"code":10002,"message":"文件未找到"};客户端会把它当成一次成功的 HTTP 下载,直到 zip 校验才失败
celeste-mirror-cdn.wegfan.com 证书过期 CN=wegfan.cn, notAfter=Sep 10 23:59:59 2026 GMT(所以 20fc093 撤掉了强制改写节点那套)

报告来源:Celeste Coders 群友(非开发者);暂停那条是已知问题,对应 PR #85。

下载速度一直按「已下载 / 从开始到现在的秒数」上报,也就是整段下载的平均值:
镜像中途变慢或卡住时,界面上的速度只会一路平滑下滑(用户看到「越下越慢」而不是
「卡住了」),重试等待期间数字也完全不动。单线程路径还只在进度前进 0.1% 时才上报,
卡住时干脆一直显示上一次的速度。

- 新增 SpeedMeter:按最近 3 秒的窗口算当前速度,刚开始窗口没铺满时退回整段平均。
- 单线程路径也按 200ms 的节奏上报(与多线程路径一致),卡住时速度会掉到 0。
- 新增 2 个单测覆盖窗口与「不再被历史高速率拉高」。
@std-microblock
std-microblock merged commit 28e3c91 into std-microblock:master Oct 13, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants