package tracker import ( "bytes" "encoding/binary" "errors" "fmt" "io/ioutil" "log" "net" "net/http" "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 []byte `query:"info_hash"` // info_hash PeerID []byte `query:"peer_id"` // peer_id Port int `query:"port,optional"` Uploaded int `query:"uploaded,optional"` Downloaded int `query:"downloaded,optional"` Left int `query:"left,optional"` 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 int `bencode:"interval"` MinInterval int `bencode:"min interval"` Peers []byte `bencode:"peers"` Peers6 []byte `bencode:"peers6"` TrackerId string `bencode:"tracker id"` WarningMessage string `bencode:"warning message"` } 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) } log.Println(announce + q) 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) } log.Println(string(body)) var res Response err = bencode.Unmarshal(body, &res) if err != nil { return fail(err) } return res, nil } func ParseAddr(b []byte) (string, error) { if len(b) != 6 { return "", errors.New("wrong length") } buf := bytes.NewReader(b[4:6]) var port int16 err := binary.Read(buf, binary.BigEndian, &port) if err != nil { return "", err } return fmt.Sprintf("%s:%d", net.IP(b[0:4]), port), nil }