From 6e671af6a5f8aa78d1df2506f87c2d4c96fc6d10 Mon Sep 17 00:00:00 2001 From: Matt Joiner Date: Wed, 9 Apr 2025 15:03:06 +1000 Subject: [PATCH] cmd/torrent: Switch to a status output more suited for lots of torrents --- cmd/torrent/download.go | 63 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 3 deletions(-) diff --git a/cmd/torrent/download.go b/cmd/torrent/download.go index 0a7f991f..bec6f489 100644 --- a/cmd/torrent/download.go +++ b/cmd/torrent/download.go @@ -25,6 +25,62 @@ import ( "github.com/anacrolix/torrent/storage" ) +func clientStatusWriter(ctx context.Context, cl *torrent.Client) { + start := time.Now() + lastStats := cl.Stats() + var lastLine string + var lastPrint time.Time + interval := 3 * time.Second + ticker := time.Tick(interval) + for { + select { + case <-ctx.Done(): + return + case <-ticker: + } + stats := cl.Stats() + ts := cl.Torrents() + var completeBytes int64 + var totalBytes int64 + var infos int + for _, t := range ts { + if t.Info() != nil { + infos++ + completeBytes += t.BytesCompleted() + totalBytes += t.Info().TotalLength() + } + } + getRate := func(a func(*torrent.ClientStats) *torrent.Count) int64 { + byteRate := int64(time.Second) + byteRate *= a(&stats).Int64() - a(&lastStats).Int64() + byteRate /= int64(interval) + return byteRate + } + uploadRate := getRate(func(s *torrent.ClientStats) *torrent.Count { + return &s.BytesWrittenData + }) + downloadRate := getRate(func(s *torrent.ClientStats) *torrent.Count { + return &s.BytesReadUsefulData + }) + line := fmt.Sprintf( + "%v torrents, %v infos, %s/%s ready, upload %s, download %s/s", + len(ts), + infos, + humanize.Bytes(uint64(completeBytes)), + humanize.Bytes(uint64(totalBytes)), + humanize.Bytes(uint64(uploadRate)), + humanize.Bytes(uint64(downloadRate)), + ) + if line != lastLine || time.Since(lastPrint) >= time.Minute { + lastLine = line + lastPrint = time.Now() + fmt.Fprintf(os.Stdout, "%s: %s\n", time.Since(start), line) + } + lastStats = stats + } +} + +// Keeping this for now for reference in case I do per-torrent deltas in client status updates. func torrentBar(t *torrent.Torrent, pieceStates bool) { go func() { start := time.Now() @@ -144,9 +200,6 @@ func addTorrents( err = fmt.Errorf("error writing chunk for %v: %w", t, err) fatalErr(err) }) - if flags.Progress { - torrentBar(t, flags.PieceStates) - } t.AddPeers(testPeers) wg.Add(1) go func() { @@ -354,6 +407,10 @@ func downloadErr(ctx context.Context, flags downloadFlags) error { } defer client.Close() + if flags.Progress { + go clientStatusWriter(ctx, client) + } + // Write status on the root path on the default HTTP muxer. This will be bound to localhost // somewhere if GOPPROF is set, thanks to the envpprof import. http.HandleFunc("/", func(w http.ResponseWriter, req *http.Request) { -- 2.50.0