12 "github.com/anacrolix/missinggo/httptoo"
14 "github.com/anacrolix/torrent/bencode"
15 "github.com/anacrolix/torrent/util"
18 type httpResponse struct {
19 FailureReason string `bencode:"failure reason"`
20 Interval int32 `bencode:"interval"`
21 TrackerId string `bencode:"tracker id"`
22 Complete int32 `bencode:"complete"`
23 Incomplete int32 `bencode:"incomplete"`
24 Peers interface{} `bencode:"peers"`
27 func (r *httpResponse) UnmarshalPeers() (ret []Peer, err error) {
28 switch v := r.Peers.(type) {
30 var cps []util.CompactPeer
31 cps, err = util.UnmarshalIPv4CompactPeers([]byte(v))
35 ret = make([]Peer, 0, len(cps))
36 for _, cp := range cps {
37 ret = append(ret, Peer{
46 p.fromDictInterface(i.(map[string]interface{}))
51 err = fmt.Errorf("unsupported peers value type: %T", r.Peers)
56 func setAnnounceParams(_url *url.URL, ar *AnnounceRequest) {
59 q.Set("info_hash", string(ar.InfoHash[:]))
60 q.Set("peer_id", string(ar.PeerId[:]))
61 q.Set("port", fmt.Sprintf("%d", ar.Port))
62 q.Set("uploaded", strconv.FormatInt(ar.Uploaded, 10))
63 q.Set("downloaded", strconv.FormatInt(ar.Downloaded, 10))
64 q.Set("left", strconv.FormatUint(ar.Left, 10))
66 q.Set("event", ar.Event.String())
68 // http://stackoverflow.com/questions/17418004/why-does-tracker-server-not-understand-my-request-bittorrent-protocol
70 // According to https://wiki.vuze.com/w/Message_Stream_Encryption.
71 q.Set("supportcrypto", "1")
73 _url.RawQuery = q.Encode()
76 func announceHTTP(cl *http.Client, ar *AnnounceRequest, _url *url.URL, host string) (ret AnnounceResponse, err error) {
77 _url = httptoo.CopyURL(_url)
78 setAnnounceParams(_url, ar)
79 req, err := http.NewRequest("GET", _url.String(), nil)
81 resp, err := cl.Do(req)
85 defer resp.Body.Close()
87 io.Copy(&buf, resp.Body)
88 if resp.StatusCode != 200 {
89 err = fmt.Errorf("response from tracker: %s: %s", resp.Status, buf.String())
92 var trackerResponse httpResponse
93 err = bencode.Unmarshal(buf.Bytes(), &trackerResponse)
95 err = fmt.Errorf("error decoding %q: %s", buf.Bytes(), err)
98 if trackerResponse.FailureReason != "" {
99 err = errors.New(trackerResponse.FailureReason)
102 ret.Interval = trackerResponse.Interval
103 ret.Leechers = trackerResponse.Incomplete
104 ret.Seeders = trackerResponse.Complete
105 ret.Peers, err = trackerResponse.UnmarshalPeers()