]> Sergey Matveev's repositories - btrtrc.git/commitdiff
Almost completed http tracker support
authorMatt Joiner <anacrolix@gmail.com>
Thu, 26 Mar 2015 06:20:31 +0000 (17:20 +1100)
committerMatt Joiner <anacrolix@gmail.com>
Thu, 26 Mar 2015 06:20:31 +0000 (17:20 +1100)
tracker/http/httptracker.go [new file with mode: 0644]
tracker/tracker.go

diff --git a/tracker/http/httptracker.go b/tracker/http/httptracker.go
new file mode 100644 (file)
index 0000000..432d00c
--- /dev/null
@@ -0,0 +1,112 @@
+package http
+
+import (
+       "bytes"
+       "errors"
+       "fmt"
+       "io"
+       "log"
+       "net"
+       "net/http"
+       "net/url"
+       "strconv"
+
+       "github.com/anacrolix/torrent/util"
+
+       "github.com/anacrolix/libtorgo/bencode"
+
+       "github.com/anacrolix/torrent/tracker"
+)
+
+func init() {
+       tracker.RegisterClientScheme("http", NewClient)
+}
+
+type client struct {
+       url url.URL
+}
+
+func NewClient(url *url.URL) tracker.Client {
+       return &client{
+               url: *url,
+       }
+}
+
+type response struct {
+       FailureReason string      `bencode:"failure reason"`
+       Interval      int32       `bencode:"interval"`
+       TrackerId     string      `bencode:"tracker id"`
+       Complete      int32       `bencode:"complete"`
+       Incomplete    int32       `bencode:"incomplete"`
+       Peers         interface{} `bencode:"peers"`
+}
+
+func (r *response) UnmarshalPeers() (ret []tracker.Peer, err error) {
+       s, ok := r.Peers.(string)
+       if !ok {
+               err = fmt.Errorf("unsupported peers value type: %T", r.Peers)
+               return
+       }
+       cp := make(util.CompactPeers, 0, len(s)/6)
+       err = cp.UnmarshalBinary([]byte(s))
+       if err != nil {
+               return
+       }
+       ret = make([]tracker.Peer, 0, len(cp))
+       for _, p := range cp {
+               ret = append(ret, tracker.Peer{net.IP(p.IP[:]), int(p.Port)})
+       }
+       return
+}
+
+func (me *client) Announce(ar *tracker.AnnounceRequest) (ret tracker.AnnounceResponse, err error) {
+       q := make(url.Values)
+       q.Set("info_hash", string(ar.InfoHash[:]))
+       q.Set("peer_id", string(ar.PeerId[:]))
+       q.Set("port", fmt.Sprintf("%d", ar.Port))
+       q.Set("uploaded", strconv.FormatInt(ar.Uploaded, 10))
+       q.Set("downloaded", strconv.FormatInt(ar.Downloaded, 10))
+       q.Set("left", strconv.FormatInt(ar.Left, 10))
+       if ar.Event != tracker.None {
+               q.Set("event", ar.Event.String())
+       }
+       // http://stackoverflow.com/questions/17418004/why-does-tracker-server-not-understand-my-request-bittorrent-protocol
+       q.Set("compact", "1")
+       var reqURL url.URL = me.url
+       reqURL.RawQuery = q.Encode()
+       resp, err := http.Get(reqURL.String())
+       if err != nil {
+               return
+       }
+       defer resp.Body.Close()
+       buf := bytes.Buffer{}
+       io.Copy(&buf, resp.Body)
+       log.Printf("%q", buf.Bytes())
+       var trackerResponse response
+       err = bencode.NewDecoder(&buf).Decode(&trackerResponse)
+       if err != nil {
+               return
+       }
+       if trackerResponse.FailureReason != "" {
+               err = errors.New(trackerResponse.FailureReason)
+               return
+       }
+       ret.Interval = trackerResponse.Interval
+       ret.Leechers = trackerResponse.Incomplete
+       ret.Seeders = trackerResponse.Complete
+       ret.Peers, err = trackerResponse.UnmarshalPeers()
+       return
+}
+
+func (me *client) Connect() error {
+       // HTTP trackers do not require a connecting handshake.
+       return nil
+}
+
+func (me *client) String() string {
+       return me.URL()
+}
+
+func (me *client) URL() string {
+       return me.url.String()
+}
index 888228ec04bfc25054a9df58ec55d3331720143e..98a77a182c247e54ed2ae4b9e6b6c36a93a9c59f 100644 (file)
@@ -28,6 +28,11 @@ type AnnounceResponse struct {
 
 type AnnounceEvent int32
 
+func (me AnnounceEvent) String() string {
+       // See BEP 3, "event".
+       return []string{"empty", "completed", "started", "stopped"}[me]
+}
+
 type Peer struct {
        IP   net.IP
        Port int