]> Sergey Matveev's repositories - btrtrc.git/blob - tracker_scraper.go
Merge branch 'master' of https://github.com/lovedboy/torrent
[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. For most errors, we return 5
34 // minutes, a relatively quick turn around for DNS changes.
35 func (me *trackerScraper) announce() time.Duration {
36         blocked, urlToUse, host, err := me.t.cl.prepareTrackerAnnounceUnlocked(me.url)
37         if err != nil {
38                 log.Printf("error preparing announce to %q: %s", me.url, err)
39                 return 5 * time.Minute
40         }
41         if blocked {
42                 log.Printf("announce to tracker %q blocked by IP", me.url)
43                 return 5 * time.Minute
44         }
45         me.t.cl.mu.Lock()
46         req := me.t.announceRequest()
47         me.t.cl.mu.Unlock()
48         res, err := tracker.AnnounceHost(urlToUse, &req, host)
49         if err != nil {
50                 log.Printf("error announcing %s %q to %q: %s", me.t.InfoHash().HexString(), me.t.Name(), me.url, err)
51                 return 5 * time.Minute
52         }
53         me.t.AddPeers(trackerToTorrentPeers(res.Peers))
54         return time.Duration(res.Interval) * time.Second
55 }
56
57 func (me *trackerScraper) Run() {
58         for {
59                 select {
60                 case <-me.t.closed.LockedChan(&me.t.cl.mu):
61                         return
62                 case <-me.stop.LockedChan(&me.t.cl.mu):
63                         return
64                 case <-me.t.wantPeersEvent.LockedChan(&me.t.cl.mu):
65                 }
66
67                 intervalChan := time.After(me.announce())
68
69                 select {
70                 case <-me.t.closed.LockedChan(&me.t.cl.mu):
71                         return
72                 case <-me.stop.LockedChan(&me.t.cl.mu):
73                         return
74                 case <-intervalChan:
75                 }
76         }
77 }