13 "github.com/anacrolix/torrent/bencode"
14 "github.com/anacrolix/torrent/util"
18 RegisterClientScheme("http", NewClient)
25 func NewClient(url *url.URL) Client {
31 type response struct {
32 FailureReason string `bencode:"failure reason"`
33 Interval int32 `bencode:"interval"`
34 TrackerId string `bencode:"tracker id"`
35 Complete int32 `bencode:"complete"`
36 Incomplete int32 `bencode:"incomplete"`
37 Peers interface{} `bencode:"peers"`
40 func (r *response) UnmarshalPeers() (ret []Peer, err error) {
41 s, ok := r.Peers.(string)
43 err = fmt.Errorf("unsupported peers value type: %T", r.Peers)
46 cp := make(util.CompactPeers, 0, len(s)/6)
47 err = cp.UnmarshalBinary([]byte(s))
51 ret = make([]Peer, 0, len(cp))
52 for _, p := range cp {
53 ret = append(ret, Peer{net.IP(p.IP[:]), int(p.Port)})
58 func (me *client) Announce(ar *AnnounceRequest) (ret AnnounceResponse, err error) {
60 q.Set("info_hash", string(ar.InfoHash[:]))
61 q.Set("peer_id", string(ar.PeerId[:]))
62 q.Set("port", fmt.Sprintf("%d", ar.Port))
63 q.Set("uploaded", strconv.FormatInt(ar.Uploaded, 10))
64 q.Set("downloaded", strconv.FormatInt(ar.Downloaded, 10))
65 q.Set("left", strconv.FormatUint(ar.Left, 10))
67 q.Set("event", ar.Event.String())
69 // http://stackoverflow.com/questions/17418004/why-does-tracker-server-not-understand-my-request-bittorrent-protocol
71 // According to https://wiki.vuze.com/w/Message_Stream_Encryption.
72 q.Set("supportcrypto", "1")
73 var reqURL url.URL = me.url
74 reqURL.RawQuery = q.Encode()
75 resp, err := http.Get(reqURL.String())
79 defer resp.Body.Close()
81 io.Copy(&buf, resp.Body)
82 if resp.StatusCode != 200 {
83 err = fmt.Errorf("response from tracker: %s: %s", resp.Status, buf.String())
86 var trackerResponse response
87 err = bencode.Unmarshal(buf.Bytes(), &trackerResponse)
89 err = fmt.Errorf("error decoding %q: %s", buf.Bytes(), err)
92 if trackerResponse.FailureReason != "" {
93 err = errors.New(trackerResponse.FailureReason)
96 ret.Interval = trackerResponse.Interval
97 ret.Leechers = trackerResponse.Incomplete
98 ret.Seeders = trackerResponse.Complete
99 ret.Peers, err = trackerResponse.UnmarshalPeers()
103 func (me *client) Connect() error {
104 // HTTP trackers do not require a connecting handshake.
108 func (me *client) String() string {
112 func (me *client) URL() string {
113 return me.url.String()