]> Sergey Matveev's repositories - btrtrc.git/blob - tracker/tracker.go
Add UDP tracker announce and connect expvars
[btrtrc.git] / tracker / tracker.go
1 package tracker
2
3 import (
4         "context"
5         "errors"
6         "net/http"
7         "net/url"
8         "time"
9
10         "github.com/anacrolix/dht/v2/krpc"
11 )
12
13 // Marshalled as binary by the UDP client, so be careful making changes.
14 type AnnounceRequest struct {
15         InfoHash   [20]byte
16         PeerId     [20]byte
17         Downloaded int64
18         Left       int64 // If less than 0, math.MaxInt64 will be used for HTTP trackers instead.
19         Uploaded   int64
20         // Apparently this is optional. None can be used for announces done at
21         // regular intervals.
22         Event     AnnounceEvent
23         IPAddress uint32
24         Key       int32
25         NumWant   int32 // How many peer addresses are desired. -1 for default.
26         Port      uint16
27 } // 82 bytes
28
29 type AnnounceResponse struct {
30         Interval int32 // Minimum seconds the local peer should wait before next announce.
31         Leechers int32
32         Seeders  int32
33         Peers    []Peer
34 }
35
36 type AnnounceEvent int32
37
38 func (e AnnounceEvent) String() string {
39         // See BEP 3, "event", and https://github.com/anacrolix/torrent/issues/416#issuecomment-751427001.
40         return []string{"", "completed", "started", "stopped"}[e]
41 }
42
43 const (
44         None      AnnounceEvent = iota
45         Completed               // The local peer just completed the torrent.
46         Started                 // The local peer has just resumed this torrent.
47         Stopped                 // The local peer is leaving the swarm.
48 )
49
50 var (
51         ErrBadScheme = errors.New("unknown scheme")
52 )
53
54 type Announce struct {
55         TrackerUrl string
56         Request    AnnounceRequest
57         HostHeader string
58         HTTPProxy  func(*http.Request) (*url.URL, error)
59         ServerName string
60         UserAgent  string
61         UdpNetwork string
62         // If the port is zero, it's assumed to be the same as the Request.Port.
63         ClientIp4 krpc.NodeAddr
64         // If the port is zero, it's assumed to be the same as the Request.Port.
65         ClientIp6 krpc.NodeAddr
66         Context   context.Context
67 }
68
69 // The code *is* the documentation.
70 const DefaultTrackerAnnounceTimeout = 15 * time.Second
71
72 func (me Announce) Do() (res AnnounceResponse, err error) {
73         _url, err := url.Parse(me.TrackerUrl)
74         if err != nil {
75                 return
76         }
77         if me.Context == nil {
78                 // This is just to maintain the old behaviour that should be a timeout of 15s. Users can
79                 // override it by providing their own Context. See comments elsewhere about longer timeouts
80                 // acting as rate limiting overloaded trackers.
81                 ctx, cancel := context.WithTimeout(context.Background(), DefaultTrackerAnnounceTimeout)
82                 defer cancel()
83                 me.Context = ctx
84         }
85         switch _url.Scheme {
86         case "http", "https":
87                 return announceHTTP(me, _url)
88         case "udp", "udp4", "udp6":
89                 return announceUDP(me, _url)
90         default:
91                 err = ErrBadScheme
92                 return
93         }
94 }