tracker/http/writer.go

127 lines
2.9 KiB
Go
Raw Normal View History

// 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"
)
2014-07-19 01:09:06 +02:00
// Writer implements the tracker.Writer interface for the HTTP protocol.
type Writer struct {
http.ResponseWriter
}
2014-07-19 01:09:06 +02:00
// 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(),
})
}
2014-07-19 01:09:06 +02:00
// 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,
}
2014-07-22 07:59:05 +02:00
if res.Compact {
if res.IPv4Peers != nil {
2014-07-17 06:41:59 +02:00
dict["peers"] = compactPeers(false, res.IPv4Peers)
2014-07-22 07:59:05 +02:00
}
if res.IPv6Peers != nil {
2014-07-23 06:56:11 +02:00
compact := compactPeers(true, res.IPv6Peers)
// Don't bother writing the IPv6 field if there is no value.
if len(compact) > 0 {
dict["peers6"] = compact
}
2014-07-17 06:41:59 +02:00
}
2014-07-22 07:59:05 +02:00
} else if res.IPv4Peers != nil || res.IPv6Peers != nil {
2014-07-23 19:08:52 +02:00
dict["peers"] = peersList(res.IPv4Peers, res.IPv6Peers)
}
bencoder := bencode.NewEncoder(w)
return bencoder.Encode(dict)
}
2014-07-19 01:09:06 +02:00
// 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 {
2014-07-23 19:15:04 +02:00
compactPeers.Write(peer.IPv6)
compactPeers.Write([]byte{byte(peer.Port >> 8), byte(peer.Port & 0xff)})
}
} else {
for _, peer := range peers {
2014-07-23 19:15:04 +02:00
compactPeers.Write(peer.IPv4)
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 {
2014-07-23 19:15:04 +02:00
peers = append(peers, peerDict(&peer, false))
}
for _, peer := range ipv6s {
2014-07-23 19:15:04 +02:00
peers = append(peers, peerDict(&peer, true))
}
return peers
}
2014-07-23 19:15:04 +02:00
func peerDict(peer *models.Peer, ipv6 bool) bencode.Dict {
var ip string
if ipv6 {
ip = peer.IPv6.String()
} else {
ip = peer.IPv4.String()
}
return bencode.Dict{
2014-07-23 19:15:04 +02:00
"ip": ip,
"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,
}
}