From 507daba528a512b511ce438679913709f429d3fe Mon Sep 17 00:00:00 2001 From: Matt Joiner Date: Tue, 12 Jul 2016 16:44:06 +1000 Subject: [PATCH] Rework tracker scraper code to allow tracker stats Inspired by @axet's work. --- torrent.go | 17 ++++++++---- tracker_scraper.go | 67 +++++++++++++++++++++++++++++++++++++--------- 2 files changed, 67 insertions(+), 17 deletions(-) diff --git a/torrent.go b/torrent.go index 216ebbc1..6c4e8c2a 100644 --- a/torrent.go +++ b/torrent.go @@ -11,6 +11,7 @@ import ( "net" "os" "sync" + "text/tabwriter" "time" "github.com/anacrolix/missinggo" @@ -436,11 +437,17 @@ func (t *Torrent) writeStatus(w io.Writer, cl *Client) { }) fmt.Fprintln(w) - fmt.Fprintf(w, "Trackers: ") - for _url := range t.trackerAnnouncers { - fmt.Fprintf(w, "%q ", _url) - } - fmt.Fprintf(w, "\n") + fmt.Fprintf(w, "Trackers:\n") + func() { + tw := tabwriter.NewWriter(w, 0, 0, 2, ' ', 0) + fmt.Fprintf(tw, " URL\tNext announce\tLast announce\n") + for _, ta := range slices.Sort(slices.FromElems(t.trackerAnnouncers), func(l, r *trackerScraper) bool { + return l.url < r.url + }).([]*trackerScraper) { + fmt.Fprintf(tw, " %s\n", ta.statusLine()) + } + tw.Flush() + }() fmt.Fprintf(w, "DHT Announces: %d\n", t.numDHTAnnounces) diff --git a/tracker_scraper.go b/tracker_scraper.go index 5c3956b0..23c3ebf6 100644 --- a/tracker_scraper.go +++ b/tracker_scraper.go @@ -1,7 +1,9 @@ package torrent import ( - "log" + "bytes" + "errors" + "fmt" "time" "github.com/anacrolix/missinggo" @@ -14,8 +16,38 @@ import ( type trackerScraper struct { url string // Causes the trackerScraper to stop running. - stop missinggo.Event - t *Torrent + stop missinggo.Event + t *Torrent + lastAnnounce trackerAnnounceResult +} + +func (ts *trackerScraper) statusLine() string { + var w bytes.Buffer + fmt.Fprintf(&w, "%q\t%s\t%s", + ts.url, + func() string { + // return ts.lastAnnounce.Completed.Add(ts.lastAnnounce.Interval).Format("2006-01-02 15:04:05 -0700 MST") + na := ts.lastAnnounce.Completed.Add(ts.lastAnnounce.Interval).Sub(time.Now()) + if na > 0 { + return na.String() + } else { + return "anytime" + } + }(), + func() string { + if ts.lastAnnounce.Err != nil { + return ts.lastAnnounce.Err.Error() + } + return fmt.Sprintf("%d peers", ts.lastAnnounce.NumPeers) + }()) + return w.String() +} + +type trackerAnnounceResult struct { + Err error + NumPeers int + Interval time.Duration + Completed time.Time } func trackerToTorrentPeers(ps []tracker.Peer) (ret []Peer) { @@ -32,26 +64,32 @@ func trackerToTorrentPeers(ps []tracker.Peer) (ret []Peer) { // Return how long to wait before trying again. For most errors, we return 5 // minutes, a relatively quick turn around for DNS changes. -func (me *trackerScraper) announce() time.Duration { +func (me *trackerScraper) announce() (ret trackerAnnounceResult) { + defer func() { + ret.Completed = time.Now() + }() + ret.Interval = 5 * time.Minute blocked, urlToUse, host, err := me.t.cl.prepareTrackerAnnounceUnlocked(me.url) if err != nil { - log.Printf("error preparing announce to %q: %s", me.url, err) - return 5 * time.Minute + ret.Err = err + return } if blocked { - log.Printf("announce to tracker %q blocked by IP", me.url) - return 5 * time.Minute + ret.Err = errors.New("blocked by IP") + return } me.t.cl.mu.Lock() req := me.t.announceRequest() me.t.cl.mu.Unlock() res, err := tracker.AnnounceHost(urlToUse, &req, host) if err != nil { - // log.Printf("error announcing %s %q to %q: %s", me.t.InfoHash().HexString(), me.t.Name(), me.url, err) - return 5 * time.Minute + ret.Err = err + return } me.t.AddPeers(trackerToTorrentPeers(res.Peers)) - return time.Duration(res.Interval) * time.Second + ret.NumPeers = len(res.Peers) + ret.Interval = time.Duration(res.Interval) * time.Second + return } func (me *trackerScraper) Run() { @@ -64,7 +102,12 @@ func (me *trackerScraper) Run() { case <-me.t.wantPeersEvent.LockedChan(&me.t.cl.mu): } - intervalChan := time.After(me.announce()) + ar := me.announce() + me.t.cl.mu.Lock() + me.lastAnnounce = ar + me.t.cl.mu.Unlock() + + intervalChan := time.After(ar.Completed.Add(ar.Interval).Sub(time.Now())) select { case <-me.t.closed.LockedChan(&me.t.cl.mu): -- 2.50.0