package tracker import ( "bytes" "crypto/sha1" "encoding/binary" "fmt" "io/ioutil" "log" "net" "net/http" "time" "dim13.org/btget/bencode" "dim13.org/btget/query" ) type Event string const ( NoEvent Event = "" Started Event = "started" Stopped Event = "stopped" Completed Event = "completed" ) type Request struct { InfoHash [sha1.Size]byte `query:"info_hash"` // info_hash PeerID []byte `query:"peer_id"` // peer_id Port int `query:"port"` Uploaded int `query:"uploaded"` Downloaded int `query:"downloaded"` Left int `query:"left"` Compact bool `query:"compact,optional"` // always true NoPeerID bool `query:"no_peer_id,optional"` Event Event `query:"event,optional"` IP net.IPAddr `query:"ip,optional"` NumWant int `query:"numwant,optional"` Key []byte `query:"key,optional"` TrackerID []byte `query:"tracker_id,optional"` } // we support only compact mode type Response struct { Complete int `bencode:"complete"` FalureReason string `bencode:"failure reason"` Incomplete int `bencode:"incomplete"` Interval time.Duration `bencode:"interval"` MinInterval time.Duration `bencode:"min interval"` Peers Peers `bencode:"peers"` // can be []byte or []Peer Peers6 []byte `bencode:"peers6"` TrackerID string `bencode:"tracker id"` WarningMessage string `bencode:"warning message"` } type Peer struct { IP string `bencode:"ip"` ID []byte `bencode:"peer id"` Port int `bencode:"port"` } func (p Peer) String() string { return fmt.Sprintf("%v %s %v", p.IP, p.ID, p.Port) } type Peers []Peer func (p *Peers) UnmarshalBencode(b []byte) error { log.Println(string(b)) return nil } func (r Request) Get(announce string) (Response, error) { fail := func(err error) (Response, error) { return Response{}, err } q, err := query.Marshal(r) if err != nil { return fail(err) } resp, err := http.Get(announce + q) if err != nil { return fail(err) } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { return fail(err) } var res Response err = bencode.Unmarshal(body, &res) if err != nil { return fail(err) } return res, nil } func (r Response) IntervalDuration() time.Duration { return time.Duration(r.Interval) * time.Second } /* func (r Response) PeerAddr() ([]*net.TCPAddr, error) { return peerAddr(r.Peers) } */ func peerAddr(b []byte) ([]*net.TCPAddr, error) { n := len(b) / 6 a := make([]*net.TCPAddr, n) var port uint16 for i := 0; i < n; i++ { off := i * 6 buf := bytes.NewReader(b[off+4 : off+6]) err := binary.Read(buf, binary.BigEndian, &port) if err != nil { return nil, err } a[i] = &net.TCPAddr{ IP: net.IP(b[off : off+4]), Port: int(port), } } return a, nil }