]> Sergey Matveev's repositories - btrtrc.git/commitdiff
Rework tracker scraper code to allow tracker stats
authorMatt Joiner <anacrolix@gmail.com>
Tue, 12 Jul 2016 06:44:06 +0000 (16:44 +1000)
committerMatt Joiner <anacrolix@gmail.com>
Tue, 12 Jul 2016 06:44:06 +0000 (16:44 +1000)
Inspired by @axet's work.

torrent.go
tracker_scraper.go

index 216ebbc1cbb6f1b9dc47df19e1ad2b3a0abd8d30..6c4e8c2a8d3cdc36b92b376fb104e8540298afc7 100644 (file)
@@ -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)
 
index 5c3956b0c8fca8acdea30dbcab403500dcf5e66a..23c3ebf6f8c7025e884432dfc94233cb5f199b6c 100644 (file)
@@ -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):