block() no longer special-cases one download with a [bracketed] one-liner;
it always draws the summary line, the column header, and one row per
download. The non-TTY path emits the same summary for one or many. This
drops lineOne and the dual rendering path it created, so a column or state
change is made in one place, not two that could drift.
This is a personal torrent client, not a web client or daemon, so the
rarely-used HTTP-client knobs and redundant tuning flags are gone — flag,
config field, implementation, and tests removed for each. The option
surface drops from 54 to 28.
Web-client cluster removed: --all-proxy (HTTP_PROXY env still works),
load/save-cookies, --referer, -U/--user-agent, --http-user/--http-passwd,
--conditional-get, --remote-time, --check-certificate, --ca-certificate,
--lowest-speed-limit. Pass --header for a one-off auth/cookie/UA header.
Redundant knobs removed: -x and -k (folded into -s), --connect-timeout,
--retry-wait, per-item --max-download-limit/-u, --bt-max-peers,
--bt-stop-timeout, --disable-ipv6, --auto-save-interval, --human-readable,
--stop, -T (a positional .torrent works). follow-torrent and human-readable
are now unconditional defaults.
validate() parsed every value to bounds-check it, then the typed getters
re-parsed the same string at read time (with a comment admitting the
failure was unreachable). A single parseValue() now validates and converts,
finalize() runs it once per option after layering, and the getters just
read the stored typed value.
dedupeTorrents and markInfoHash were the same map-of-infohash logic, one
batch and one incremental, with the same hazard explained in prose four
times. Both now go through a single seenInfoHash helper.
Drop the stacked progress bars for an aligned column table under a
header. Middle-elide names so downloads sharing a long prefix stay
distinct (a leading truncation rendered them identically), drop the
per-row DL:/UL: labels, and break the summary into downloading/seeding/
queued counts. Add SIZE (completed/total) and CN/SD (peer/seeder)
columns and show the seed share ratio in place of an idle upload rate.
Also fix the in-place redraw: the block could fill the pane's bottom row
and scroll it out from under the cursor, stranding a summary line each
tick. Reserve that row so the table falls back to the summary line
instead.
Completes the boolean fix: only literal "true"/"false" are accepted, with no
case folding, so "True"/"TRUE" are rejected. Drop strings.ToLower. Keep
TrimSpace so a config value with surrounding whitespace still parses; only the
case folding was invented leniency.
Dead, vestigial, and over-built code with no behavior change (except the
bool-vocabulary trim, a deliberate behavior tightening):
- httpdl: drop the vestigial sort+copy in validSegs (work-stealing was
removed in 270812d, so segments always tile [0,total) ascending now);
validate order in place, which also rejects a scrambled sidecar. Inline
the endOff() accessor to s.end.
- cli: shrink the boolean vocabulary to true/false, which is all that's
accepted. The invented yes/no/1/0/on/off spellings are gone, so e.g.
--enable-dht=yes (or yes in got.conf) is now a usage error.
- download: remove the dead, never-called Stat.Done() method.
- progress: drop speed(), a pure alias of humanSize; call humanSize directly.
- main: replace the jobsHolder mutex box with atomic.Pointer[[]job] for the
forced-exit session save; the capability stays, the lock and type go.
- bt: collapse isAddrInUse's X||X (missinggo.IsAddrInUse is that exact
string match); drop the now-unused missinggo import (tidy -> indirect).
- option: note that prealloc and falloc are identical here.
Surface area, not the machinery, was the problem: 16 flags crowded the
bare --help. Re-tag so basic shows only the 10 outcome-changing flags;
every other flag still works behind --help=<group>.
- cut --bt-metadata-timeout, an invented flag with no real counterpart. Keep
its 60s magnet-metadata stall as a fixed internal default (bt.go), not a
user knob.
- fix the parallelism footgun: a bare `got URL` used min(split,x)=1
connection. When -x is unset, let --split drive per-host connections
(capped at 16), so `got URL` gets 5 and `-s16` gets 16. An explicit -x
is honored verbatim, including -x1. Locked by TestHTTPConnDefault.
- -s is the per-download speed dial now, so it moves to basic; -x (a
per-server cap) moves to the http group. -j help says "files at once,
not connections within one file".
- appendList: one home for the List newline-join rule (was duplicated
across accumulate and set)
- fold the redundant Int64 getter into Int; drop the truthy helper for
the shared boolWord vocabulary
- add Opt.Metavar so help derives the value placeholder from data
instead of branching on the option name (seed-time)
No behavior change; --help output is byte-identical.
Two Pike cleanups.
--auto-split was a third connection-count policy (beside -x and -s) that added
an extra knob rather than keeping the model minimal. Removing it also retires the
now-dead autoConns/maxAutoConns and the per-host transport cap that existed only
to scale for it; min(split, M*-x) is the sole policy again.
main's exit-code mapping fell back to substring-matching third-party error text
(strings.Contains "connection refused"/"timeout"/...), which rots when a
dependency rewords a message. The typed checks (errors.Is on the syscall errno,
*net.DNSError, net.Error.Timeout, context.DeadlineExceeded) already cover the
real stdlib errors -- verified end to end: refused -> 6, bad host -> 19. The two
cases that genuinely needed the text match are our own errors, now typed
sentinels: httpdl.ErrTimeout (idle timeout) and the bt metadata timeout wrapping
context.DeadlineExceeded.
The pool let an idle worker steal the back half of a slower in-flight
segment, behind a mutex that also serialized every advance. At the default
-x 1 it never fired, and it carried the trickiest invariant in the tree
(minSplit >= readBuf keeps an owner's in-flight write out of the stolen tail).
makeSegments already caps the segment count at the connection count, so the
segments map one-to-one onto workers: give each its own goroutine, advance
written with a plain atomic add, and snapshot the fixed slice with no lock.
pool/newPool/acquire/steal/advance and the seg.owned field all go away.
Net -156 lines. Behaviour at the user's flags is unchanged, except a slow
mirror's tail segment is no longer rebalanced onto idle connections.
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.