mirror of
https://github.com/sunnypilot/sunnypilot.git
synced 2026-10-26 19:53:43 +08:00
ddd7b14ebc
* models: download whole-file artifacts with parallel byte ranges HuggingFace's Xet CAS throttles each connection to roughly 1-2 MB/s but does not limit connection count, so the single-stream _download_file left the link idle most of the time. Replace it with a downloader that probes the size with a one-byte Range request, creates the file at its final size and streams each 8 MB piece straight to its offset from one of 12 worker threads. The file is never copied or assembled and only ever occupies its own size on disk. A server that answers the probe with 200 gets one plain stream instead. Every request sends Accept-Encoding: identity, because byte ranges count encoded bytes while requests hands back decoded ones, so a compressed response would land at the wrong offsets and fail as a short read. Workers only write bytes; a reporter coroutine on the event loop publishes progress every 0.5 s (instead of every 128 KB), re-raises the first worker failure and polls the cancel ref. Transient errors (connection, timeout, truncated body, HTTP 408/429/500/502/503/504) give a piece up to three attempts; any other HTTP error fails the download at once. The whole-file path now also publishes "verifying" while hashing before and after the transfer, and the download is hashed against the manifest exactly as before. A cancel has to wait for in-flight pieces to unwind (a blocked socket read cannot be interrupted), so the row shows "canceling..." through a new DownloadProgress.canceling flag instead of a frozen bar, and the mici cancel button hides once the ref is gone, as it already does on the big UI. DownloadProgress gains speed, canceling and resuming, appended to the capnp so older readers are unaffected. All three are declared here so the wire format lands in one place; speed and resuming are filled in by the follow-up speed and resume changes. Builds on #2050, which drops chunking and publishes models as whole files; this makes that whole-file download parallel. Measured on a comma 3X on WiFi: ~2 MB/s single stream, 17-24 MB/s steady and 30-60 MB/s peak with 12 range connections, the count picked from an on-device sweep. Disk is not the bottleneck (eMMC writes at 56-67 MB/s with fdatasync). Tests drive the real downloader against a local threaded range server: piece tiling, actual parallelism (a stalled piece does not block the others), the no-range fallback, per-piece retry, 4xx, cancel via ModelManager_DownloadRef and mid-piece, verify/cached/downloaded state, a probe failure moving past verifying, and hash mismatch cleanup. Also drops two chunk-era leftovers in the tests: a stale "no chunks" note on manifest_bundle and a one-item URL loop in the live manifest check. Assisted-by: Claude Code (Claude Opus 4.8) Assisted-by: Claude Code (Claude Opus 5.5) * remove unneeded comments * models: trim the manager tests to the regressions they catch Each remaining test is there because a deliberate break in manager.py, helpers.py or fetcher.py fails it. Tests that only re-checked what another already catches are merged into a happy-path download or a table, and checks of constants rather than behaviour are dropped. The fake server now starts per test, keeps its state in one dataclass, and can cut a response short. Against 66 deliberate breaks, every one the old tests caught still fails, and a 404 being retried, a short read and its retry, and the display flags choosing the big model without a GPU are now caught too. Assisted-by: Claude Code (Claude Opus 5.5) * Update test_manager_download.py * Update manager.py --------- Co-authored-by: James Vecellio-Grant <159560811+Discountchubbs@users.noreply.github.com>