]> Sergey Matveev's repositories - btrtrc.git/blob - tracker_scraper.go
Rework torrent tracker scraping
[btrtrc.git] / tracker_scraper.go
1 package torrent
2
3 import (
4         "log"
5         "time"
6
7         "github.com/anacrolix/missinggo"
8
9         "github.com/anacrolix/torrent/tracker"
10 )
11
12 // Announces a torrent to a tracker at regular intervals, when peers are
13 // required.
14 type trackerScraper struct {
15         url string
16         // Causes the trackerScraper to stop running.
17         stop missinggo.Event
18         t    *Torrent
19 }
20
21 func trackerToTorrentPeers(ps []tracker.Peer) (ret []Peer) {
22         ret = make([]Peer, 0, len(ps))
23         for _, p := range ps {
24                 ret = append(ret, Peer{
25                         IP:     p.IP,
26                         Port:   p.Port,
27                         Source: peerSourceTracker,
28                 })
29         }
30         return
31 }
32
33 // Return how long to wait before trying again.
34 func (me *trackerScraper) announce() time.Duration {
35         blocked, urlToUse, host, err := me.t.cl.prepareTrackerAnnounceUnlocked(me.url)
36         if blocked {
37                 // Wait for DNS to potentially change. Very few people do it faster
38                 // than 5 minutes.
39                 return 5 * time.Minute
40         }
41         me.t.cl.mu.Lock()
42         req := me.t.announceRequest()
43         me.t.cl.mu.Unlock()
44         res, err := tracker.AnnounceHost(urlToUse, &req, host)
45         if err != nil {
46                 log.Printf("error announcing %s %q to %q: %s", me.t.InfoHash().HexString(), me.t.Name(), me.url, err)
47                 return 5 * time.Minute
48         }
49         me.t.AddPeers(trackerToTorrentPeers(res.Peers))
50         return time.Duration(res.Interval) * time.Second
51 }
52
53 func (me *trackerScraper) Run() {
54         for {
55                 select {
56                 case <-me.t.closed.LockedChan(&me.t.cl.mu):
57                         return
58                 case <-me.stop.LockedChan(&me.t.cl.mu):
59                         return
60                 case <-me.t.wantPeersEvent.LockedChan(&me.t.cl.mu):
61                 }
62
63                 intervalChan := time.After(me.announce())
64
65                 select {
66                 case <-me.t.closed.LockedChan(&me.t.cl.mu):
67                         return
68                 case <-me.stop.LockedChan(&me.t.cl.mu):
69                         return
70                 case <-intervalChan:
71                 }
72         }
73 }