122 lines
2.9 KiB
Go
122 lines
2.9 KiB
Go
// Copyright 2014 The Chihaya Authors. All rights reserved.
|
|
// Use of this source code is governed by the BSD 2-Clause license,
|
|
// which can be found in the LICENSE file.
|
|
|
|
package http
|
|
|
|
import (
|
|
"bytes"
|
|
"net/http"
|
|
|
|
"github.com/chihaya/bencode"
|
|
"github.com/chihaya/chihaya/tracker/models"
|
|
)
|
|
|
|
// Writer implements the tracker.Writer interface for the HTTP protocol.
|
|
type Writer struct {
|
|
http.ResponseWriter
|
|
}
|
|
|
|
// WriteError writes a bencode dict with a failure reason.
|
|
func (w *Writer) WriteError(err error) error {
|
|
bencoder := bencode.NewEncoder(w)
|
|
|
|
return bencoder.Encode(bencode.Dict{
|
|
"failure reason": err.Error(),
|
|
})
|
|
}
|
|
|
|
// WriteAnnounce writes a bencode dict representation of an AnnounceResponse.
|
|
func (w *Writer) WriteAnnounce(res *models.AnnounceResponse) error {
|
|
dict := bencode.Dict{
|
|
"complete": res.Complete,
|
|
"incomplete": res.Incomplete,
|
|
"interval": res.Interval,
|
|
"min interval": res.MinInterval,
|
|
}
|
|
|
|
if res.Compact {
|
|
if res.IPv4Peers != nil {
|
|
dict["peers"] = compactPeers(false, res.IPv4Peers)
|
|
}
|
|
if res.IPv6Peers != nil {
|
|
compact := compactPeers(true, res.IPv6Peers)
|
|
|
|
// Don't bother writing the IPv6 field if there is no value.
|
|
if len(compact) > 0 {
|
|
dict["peers6"] = compact
|
|
}
|
|
}
|
|
} else if res.IPv4Peers != nil || res.IPv6Peers != nil {
|
|
dict["peers"] = peersList(res.IPv6Peers, res.IPv4Peers)
|
|
}
|
|
|
|
bencoder := bencode.NewEncoder(w)
|
|
return bencoder.Encode(dict)
|
|
}
|
|
|
|
// WriteScrape writes a bencode dict representation of a ScrapeResponse.
|
|
func (w *Writer) WriteScrape(res *models.ScrapeResponse) error {
|
|
dict := bencode.Dict{
|
|
"files": filesDict(res.Files),
|
|
}
|
|
|
|
bencoder := bencode.NewEncoder(w)
|
|
return bencoder.Encode(dict)
|
|
}
|
|
|
|
func compactPeers(ipv6 bool, peers models.PeerList) []byte {
|
|
var compactPeers bytes.Buffer
|
|
|
|
if ipv6 {
|
|
for _, peer := range peers {
|
|
if ip := peer.IP.To16(); ip != nil {
|
|
compactPeers.Write(ip)
|
|
compactPeers.Write([]byte{byte(peer.Port >> 8), byte(peer.Port & 0xff)})
|
|
}
|
|
}
|
|
} else {
|
|
for _, peer := range peers {
|
|
if ip := peer.IP.To4(); ip != nil {
|
|
compactPeers.Write(ip)
|
|
compactPeers.Write([]byte{byte(peer.Port >> 8), byte(peer.Port & 0xff)})
|
|
}
|
|
}
|
|
}
|
|
|
|
return compactPeers.Bytes()
|
|
}
|
|
|
|
func peersList(ipv4s, ipv6s models.PeerList) (peers []bencode.Dict) {
|
|
for _, peer := range ipv4s {
|
|
peers = append(peers, peerDict(&peer))
|
|
}
|
|
for _, peer := range ipv6s {
|
|
peers = append(peers, peerDict(&peer))
|
|
}
|
|
return peers
|
|
}
|
|
|
|
func peerDict(peer *models.Peer) bencode.Dict {
|
|
return bencode.Dict{
|
|
"ip": peer.IP.String(),
|
|
"peer id": peer.ID,
|
|
"port": peer.Port,
|
|
}
|
|
}
|
|
|
|
func filesDict(torrents []*models.Torrent) bencode.Dict {
|
|
d := bencode.NewDict()
|
|
for _, torrent := range torrents {
|
|
d[torrent.Infohash] = torrentDict(torrent)
|
|
}
|
|
return d
|
|
}
|
|
|
|
func torrentDict(torrent *models.Torrent) bencode.Dict {
|
|
return bencode.Dict{
|
|
"complete": len(torrent.Seeders),
|
|
"incomplete": len(torrent.Leechers),
|
|
"downloaded": torrent.Snatches,
|
|
}
|
|
}
|