Findings from a Rob-Pike-lens review (bugs/races/network), each verified
against the code before fixing:
- httpdl: name/out are now atomic.Pointer[string] -- the engine publishes a
download to the reporter before Run resolves the name, so Stat raced the
write (bt already did this)
- httpdl: a malformed --proxy fails loudly instead of silently bypassing it
- httpdl: a 206 must carry a matching Content-Range; a 200 in segmented mode is
fatal so it fails over instead of burning the retry budget
- httpdl: single-stream mirror failover validates the range before appending;
ErrTooSlow only when the error is a real ctx cancellation
- httpdl: idle guard tracks progress by timestamp (no Reset/Stop race, no
sticky fired flag)
- httpdl/control: reject a resume file whose segments don't tile [0,total)
- bt: clamp the listen-port range; verify on-disk data before choosing pieces
under --check-integrity
- cli: reject size overflow; show --seed-time=MIN; clamp --select-file range
- progress/engine/main: clamp ETA against int64 overflow; show queued
downloads as waiting; join the reporter on exit instead of a 20ms sleep
running got in the repo root drops downloaded files next to the source;
torrents/control files were already ignored, add common media (mkv/mp4/
avi/mov/webm/iso/mp3/flac) so anime/ISO downloads don't show up as
untracked and can't be committed by accident.
max-connection-per-server, split and min-split-size were tagged HTTP, so
they only appeared under --help=all. Tag them Basic so they show in the
default --help, where users expect the core connection knobs.
From a Rob Pike pass over the tree:
- singleOnce adds deltas to d.completed like pump does, instead of
storing absolute offsets, so the counter has one write discipline.
- one overMirrors helper replaces the three copy-pasted mirror-fallover
loops in probeRetry, fetchSeg and single.
- failedDownload becomes a pointer, the only value-type Download impl, so
Engine.untrack's == is always pointer identity and can't compare the
fields of a value (keying on Stat().ID is out — a torrent's ID changes
from source to infohash once metadata loads).
webseed/peer/tracker warnings (the 403/429 chatter) go through slog, the
rest through the legacy analog logger; both default to Warning, which
interleaves with and corrupts the live progress block. Filter both to
Error and above so only genuine errors reach stderr. quietSlogger is a
small testable helper; anacrolix/log becomes a direct dependency.
lineMany crammed every download onto one line as name+percent, dropping
the speed column that answers "which one is stalled" and producing ugly
double brackets for names like "[Gecko]". render N>1 as a redrawn block:
one row each (name, bar, percent, DL speed, ETA/stalled), a header with
the active count and totals, falling back to a single summary line when
the table would overflow the window. one download keeps its dashboard.
a .torrent fetched over http is added to the shared client in a second
pass (followUps); two that name the same torrent would share one torrent
on the refcount-less client, and the first to finish would Drop it out
from under the other, stranding it at 0%. dedupe the followed files by
infohash, the guard build() already applies to pass-1 sources.
an idle worker now steals the back half of the busiest in-flight segment
instead of exiting, so one slow segment no longer drains alone over a single
connection. control file persists stolen tails; resume re-tiles.
add --auto-split (opt-in): derive the connection count from file size (one
per min-split-size, up to 16), overriding -x/-s. default stays at 1
connection for a single server.