go fmt [ci skip]

This commit is contained in:
Jimmy Zelinskie 2013-11-24 00:49:20 -05:00
parent cf36519c5e
commit 6549f49e26
10 changed files with 1735 additions and 1735 deletions

View file

@ -6,83 +6,83 @@
package config
import (
"encoding/json"
"io"
"os"
"time"
"encoding/json"
"io"
"os"
"time"
)
type Duration struct {
time.Duration
time.Duration
}
func (d *Duration) MarshalJSON() ([]byte, error) {
return json.Marshal(d.String())
return json.Marshal(d.String())
}
func (d *Duration) UnmarshalJSON(b []byte) error {
var str string
err := json.Unmarshal(b, &str)
d.Duration, err = time.ParseDuration(str)
return err
var str string
err := json.Unmarshal(b, &str)
d.Duration, err = time.ParseDuration(str)
return err
}
// DataStore represents the configuration used to connect to a data store.
type DataStore struct {
Driver string `json:"driver"`
Network string `json:"network`
Host string `json:"host"`
Port string `json:"port"`
Username string `json:"user"`
Password string `json:"pass"`
Schema string `json:"schema,omitempty"`
Encoding string `json:"encoding,omitempty"`
Prefix string `json:"prefix,omitempty"`
Driver string `json:"driver"`
Network string `json:"network`
Host string `json:"host"`
Port string `json:"port"`
Username string `json:"user"`
Password string `json:"pass"`
Schema string `json:"schema,omitempty"`
Encoding string `json:"encoding,omitempty"`
Prefix string `json:"prefix,omitempty"`
MaxIdleConns int `json:"max_idle_conns,omitempty"`
IdleTimeout *Duration `json:"idle_timeout,omitempty"`
MaxIdleConns int `json:"max_idle_conns,omitempty"`
IdleTimeout *Duration `json:"idle_timeout,omitempty"`
}
// Config represents a configuration for a server.Server.
type Config struct {
Addr string `json:"addr"`
PubAddr string `json:"pub_addr"`
Cache DataStore `json:"cache"`
Storage DataStore `json:"storage"`
Addr string `json:"addr"`
PubAddr string `json:"pub_addr"`
Cache DataStore `json:"cache"`
Storage DataStore `json:"storage"`
Private bool `json:"private"`
Freeleech bool `json:"freeleech"`
Slots bool `json:"slots"`
Private bool `json:"private"`
Freeleech bool `json:"freeleech"`
Slots bool `json:"slots"`
Announce Duration `json:"announce"`
MinAnnounce Duration `json:"min_announce"`
ReadTimeout Duration `json:"read_timeout"`
DefaultNumWant int `json:"default_num_want"`
Announce Duration `json:"announce"`
MinAnnounce Duration `json:"min_announce"`
ReadTimeout Duration `json:"read_timeout"`
DefaultNumWant int `json:"default_num_want"`
}
// Open is a shortcut to open a file, read it, and generate a Config.
// It supports relative and absolute paths.
func Open(path string) (*Config, error) {
expandedPath := os.ExpandEnv(path)
f, err := os.Open(expandedPath)
if err != nil {
return nil, err
}
defer f.Close()
expandedPath := os.ExpandEnv(path)
f, err := os.Open(expandedPath)
if err != nil {
return nil, err
}
defer f.Close()
conf, err := newConfig(f)
if err != nil {
return nil, err
}
return conf, nil
conf, err := newConfig(f)
if err != nil {
return nil, err
}
return conf, nil
}
// New decodes JSON from a Reader into a Config.
func newConfig(raw io.Reader) (*Config, error) {
conf := &Config{}
err := json.NewDecoder(raw).Decode(conf)
if err != nil {
return nil, err
}
return conf, nil
conf := &Config{}
err := json.NewDecoder(raw).Decode(conf)
if err != nil {
return nil, err
}
return conf, nil
}

View file

@ -5,351 +5,351 @@
package server
import (
"errors"
"log"
"net/http"
"path"
"strconv"
"time"
"errors"
"log"
"net/http"
"path"
"strconv"
"time"
"github.com/pushrax/chihaya/storage"
"github.com/pushrax/chihaya/storage"
)
func (s Server) serveAnnounce(w http.ResponseWriter, r *http.Request) {
// Parse the required parameters off of a query
compact, numWant, infohash, peerID, event, ip, port, uploaded, downloaded, left, err := s.validateAnnounceQuery(r)
if err != nil {
fail(err, w, r)
return
}
// Parse the required parameters off of a query
compact, numWant, infohash, peerID, event, ip, port, uploaded, downloaded, left, err := s.validateAnnounceQuery(r)
if err != nil {
fail(err, w, r)
return
}
// Get a connection to the tracker db
conn, err := s.dbConnPool.Get()
if err != nil {
log.Panicf("server: %s", err)
}
// Get a connection to the tracker db
conn, err := s.dbConnPool.Get()
if err != nil {
log.Panicf("server: %s", err)
}
// Validate the user's passkey
passkey, _ := path.Split(r.URL.Path)
user, err := validateUser(conn, passkey)
if err != nil {
fail(err, w, r)
return
}
// Validate the user's passkey
passkey, _ := path.Split(r.URL.Path)
user, err := validateUser(conn, passkey)
if err != nil {
fail(err, w, r)
return
}
// Check if the user's client is whitelisted
whitelisted, err := conn.ClientWhitelisted(parsePeerID(peerID))
if err != nil {
log.Panicf("server: %s", err)
}
if !whitelisted {
fail(errors.New("Your client is not approved"), w, r)
return
}
// Check if the user's client is whitelisted
whitelisted, err := conn.ClientWhitelisted(parsePeerID(peerID))
if err != nil {
log.Panicf("server: %s", err)
}
if !whitelisted {
fail(errors.New("Your client is not approved"), w, r)
return
}
// Find the specified torrent
torrent, exists, err := conn.FindTorrent(infohash)
if err != nil {
log.Panicf("server: %s", err)
}
if !exists {
fail(errors.New("This torrent does not exist"), w, r)
return
}
// Find the specified torrent
torrent, exists, err := conn.FindTorrent(infohash)
if err != nil {
log.Panicf("server: %s", err)
}
if !exists {
fail(errors.New("This torrent does not exist"), w, r)
return
}
// If the torrent was pruned and the user is seeding, unprune it
if !torrent.Active && left == 0 {
err := conn.MarkActive(torrent)
if err != nil {
log.Panicf("server: %s", err)
}
}
// If the torrent was pruned and the user is seeding, unprune it
if !torrent.Active && left == 0 {
err := conn.MarkActive(torrent)
if err != nil {
log.Panicf("server: %s", err)
}
}
// Create a new peer object from the request
peer := &storage.Peer{
ID: peerID,
UserID: user.ID,
TorrentID: torrent.ID,
IP: ip,
Port: port,
Uploaded: uploaded,
Downloaded: downloaded,
Left: left,
LastAnnounce: time.Now().Unix(),
}
// Create a new peer object from the request
peer := &storage.Peer{
ID: peerID,
UserID: user.ID,
TorrentID: torrent.ID,
IP: ip,
Port: port,
Uploaded: uploaded,
Downloaded: downloaded,
Left: left,
LastAnnounce: time.Now().Unix(),
}
// Look for the user in in the pool of seeders and leechers
_, seeder := torrent.Seeders[storage.PeerMapKey(peer)]
_, leecher := torrent.Leechers[storage.PeerMapKey(peer)]
// Look for the user in in the pool of seeders and leechers
_, seeder := torrent.Seeders[storage.PeerMapKey(peer)]
_, leecher := torrent.Leechers[storage.PeerMapKey(peer)]
switch {
// Guarantee that no user is in both pools
case seeder && leecher:
if left == 0 {
err := conn.RemoveLeecher(torrent, peer)
if err != nil {
log.Panicf("server: %s", err)
}
leecher = false
} else {
err := conn.RemoveSeeder(torrent, peer)
if err != nil {
log.Panicf("server: %s", err)
}
seeder = false
}
switch {
// Guarantee that no user is in both pools
case seeder && leecher:
if left == 0 {
err := conn.RemoveLeecher(torrent, peer)
if err != nil {
log.Panicf("server: %s", err)
}
leecher = false
} else {
err := conn.RemoveSeeder(torrent, peer)
if err != nil {
log.Panicf("server: %s", err)
}
seeder = false
}
case seeder:
// Update the peer with the stats from the request
err := conn.SetSeeder(torrent, peer)
if err != nil {
log.Panicf("server: %s", err)
}
case seeder:
// Update the peer with the stats from the request
err := conn.SetSeeder(torrent, peer)
if err != nil {
log.Panicf("server: %s", err)
}
case leecher:
// Update the peer with the stats from the request
err := conn.SetLeecher(torrent, peer)
if err != nil {
log.Panicf("server: %s", err)
}
case leecher:
// Update the peer with the stats from the request
err := conn.SetLeecher(torrent, peer)
if err != nil {
log.Panicf("server: %s", err)
}
default:
// Check the user's slots to see if they're allowed to leech
if s.conf.Slots && user.Slots != -1 && left != 0 {
if user.SlotsUsed >= user.Slots {
fail(errors.New("You've run out of download slots."), w, r)
return
}
}
default:
// Check the user's slots to see if they're allowed to leech
if s.conf.Slots && user.Slots != -1 && left != 0 {
if user.SlotsUsed >= user.Slots {
fail(errors.New("You've run out of download slots."), w, r)
return
}
}
if left == 0 {
// Save the peer as a new seeder
err := conn.AddSeeder(torrent, peer)
if err != nil {
log.Panicf("server: %s", err)
}
} else {
// Save the peer as a new leecher and increment the user's slots
err := conn.IncrementSlots(user)
if err != nil {
log.Panicf("server: %s", err)
}
err = conn.AddLeecher(torrent, peer)
if err != nil {
log.Panicf("server: %s", err)
}
}
}
if left == 0 {
// Save the peer as a new seeder
err := conn.AddSeeder(torrent, peer)
if err != nil {
log.Panicf("server: %s", err)
}
} else {
// Save the peer as a new leecher and increment the user's slots
err := conn.IncrementSlots(user)
if err != nil {
log.Panicf("server: %s", err)
}
err = conn.AddLeecher(torrent, peer)
if err != nil {
log.Panicf("server: %s", err)
}
}
}
// Handle any events in the request
switch {
case event == "stopped" || event == "paused":
if seeder {
err := conn.RemoveSeeder(torrent, peer)
if err != nil {
log.Panicf("server: %s", err)
}
}
if leecher {
err := conn.RemoveLeecher(torrent, peer)
if err != nil {
log.Panicf("server: %s", err)
}
err = conn.DecrementSlots(user)
if err != nil {
log.Panicf("server: %s", err)
}
}
// Handle any events in the request
switch {
case event == "stopped" || event == "paused":
if seeder {
err := conn.RemoveSeeder(torrent, peer)
if err != nil {
log.Panicf("server: %s", err)
}
}
if leecher {
err := conn.RemoveLeecher(torrent, peer)
if err != nil {
log.Panicf("server: %s", err)
}
err = conn.DecrementSlots(user)
if err != nil {
log.Panicf("server: %s", err)
}
}
case event == "completed":
err := conn.RecordSnatch(user, torrent)
if err != nil {
log.Panicf("server: %s", err)
}
if leecher {
err := conn.LeecherFinished(torrent, peer)
if err != nil {
log.Panicf("server: %s", err)
}
}
case event == "completed":
err := conn.RecordSnatch(user, torrent)
if err != nil {
log.Panicf("server: %s", err)
}
if leecher {
err := conn.LeecherFinished(torrent, peer)
if err != nil {
log.Panicf("server: %s", err)
}
}
case leecher && left == 0:
// A leecher completed but the event was never received
err := conn.LeecherFinished(torrent, peer)
if err != nil {
log.Panicf("server: %s", err)
}
}
case leecher && left == 0:
// A leecher completed but the event was never received
err := conn.LeecherFinished(torrent, peer)
if err != nil {
log.Panicf("server: %s", err)
}
}
if ip != peer.IP || port != peer.Port {
peer.Port = port
peer.IP = ip
}
if ip != peer.IP || port != peer.Port {
peer.Port = port
peer.IP = ip
}
// Generate the response
seedCount := len(torrent.Seeders)
leechCount := len(torrent.Leechers)
// Generate the response
seedCount := len(torrent.Seeders)
leechCount := len(torrent.Leechers)
writeBencoded(w, "d")
writeBencoded(w, "complete")
writeBencoded(w, seedCount)
writeBencoded(w, "incomplete")
writeBencoded(w, leechCount)
writeBencoded(w, "interval")
writeBencoded(w, s.conf.Announce.Duration)
writeBencoded(w, "min interval")
writeBencoded(w, s.conf.MinAnnounce.Duration)
writeBencoded(w, "d")
writeBencoded(w, "complete")
writeBencoded(w, seedCount)
writeBencoded(w, "incomplete")
writeBencoded(w, leechCount)
writeBencoded(w, "interval")
writeBencoded(w, s.conf.Announce.Duration)
writeBencoded(w, "min interval")
writeBencoded(w, s.conf.MinAnnounce.Duration)
if numWant > 0 && event != "stopped" && event != "paused" {
writeBencoded(w, "peers")
var peerCount, count int
if numWant > 0 && event != "stopped" && event != "paused" {
writeBencoded(w, "peers")
var peerCount, count int
if compact {
if left > 0 {
peerCount = minInt(numWant, leechCount)
} else {
peerCount = minInt(numWant, leechCount+seedCount-1)
}
writeBencoded(w, strconv.Itoa(peerCount*6))
writeBencoded(w, ":")
} else {
writeBencoded(w, "l")
}
if compact {
if left > 0 {
peerCount = minInt(numWant, leechCount)
} else {
peerCount = minInt(numWant, leechCount+seedCount-1)
}
writeBencoded(w, strconv.Itoa(peerCount*6))
writeBencoded(w, ":")
} else {
writeBencoded(w, "l")
}
if left > 0 {
// If they're seeding, give them only leechers
writeLeechers(w, torrent, count, numWant, compact)
} else {
// If they're leeching, prioritize giving them seeders
writeSeeders(w, torrent, count, numWant, compact)
writeLeechers(w, torrent, count, numWant, compact)
}
if left > 0 {
// If they're seeding, give them only leechers
writeLeechers(w, torrent, count, numWant, compact)
} else {
// If they're leeching, prioritize giving them seeders
writeSeeders(w, torrent, count, numWant, compact)
writeLeechers(w, torrent, count, numWant, compact)
}
if compact && peerCount != count {
log.Panicf("Calculated peer count (%d) != real count (%d)", peerCount, count)
}
if compact && peerCount != count {
log.Panicf("Calculated peer count (%d) != real count (%d)", peerCount, count)
}
if !compact {
writeBencoded(w, "e")
}
}
writeBencoded(w, "e")
if !compact {
writeBencoded(w, "e")
}
}
writeBencoded(w, "e")
}
func (s Server) validateAnnounceQuery(r *http.Request) (compact bool, numWant int, infohash, peerID, event, ip string, port, uploaded, downloaded, left uint64, err error) {
pq, err := parseQuery(r.URL.RawQuery)
if err != nil {
return false, 0, "", "", "", "", 0, 0, 0, 0, err
}
pq, err := parseQuery(r.URL.RawQuery)
if err != nil {
return false, 0, "", "", "", "", 0, 0, 0, 0, err
}
compact = pq.Params["compact"] == "1"
numWant = requestedPeerCount(s.conf.DefaultNumWant, pq)
infohash, _ = pq.Params["info_hash"]
peerID, _ = pq.Params["peer_id"]
event, _ = pq.Params["event"]
ip, _ = requestedIP(r, pq)
port, portErr := pq.getUint64("port")
uploaded, uploadedErr := pq.getUint64("uploaded")
downloaded, downloadedErr := pq.getUint64("downloaded")
left, leftErr := pq.getUint64("left")
compact = pq.Params["compact"] == "1"
numWant = requestedPeerCount(s.conf.DefaultNumWant, pq)
infohash, _ = pq.Params["info_hash"]
peerID, _ = pq.Params["peer_id"]
event, _ = pq.Params["event"]
ip, _ = requestedIP(r, pq)
port, portErr := pq.getUint64("port")
uploaded, uploadedErr := pq.getUint64("uploaded")
downloaded, downloadedErr := pq.getUint64("downloaded")
left, leftErr := pq.getUint64("left")
if infohash == "" ||
peerID == "" ||
ip == "" ||
portErr != nil ||
uploadedErr != nil ||
downloadedErr != nil ||
leftErr != nil {
return false, 0, "", "", "", "", 0, 0, 0, 0, errors.New("Malformed request")
}
return
if infohash == "" ||
peerID == "" ||
ip == "" ||
portErr != nil ||
uploadedErr != nil ||
downloadedErr != nil ||
leftErr != nil {
return false, 0, "", "", "", "", 0, 0, 0, 0, errors.New("Malformed request")
}
return
}
func requestedPeerCount(fallback int, pq *parsedQuery) int {
if numWantStr, exists := pq.Params["numWant"]; exists {
numWant, err := strconv.Atoi(numWantStr)
if err != nil {
return fallback
}
return numWant
}
return fallback
if numWantStr, exists := pq.Params["numWant"]; exists {
numWant, err := strconv.Atoi(numWantStr)
if err != nil {
return fallback
}
return numWant
}
return fallback
}
func requestedIP(r *http.Request, pq *parsedQuery) (string, error) {
ip, ok := pq.Params["ip"]
ipv4, okv4 := pq.Params["ipv4"]
xRealIPs, xRealOk := pq.Params["X-Real-Ip"]
ip, ok := pq.Params["ip"]
ipv4, okv4 := pq.Params["ipv4"]
xRealIPs, xRealOk := pq.Params["X-Real-Ip"]
switch {
case ok:
return ip, nil
switch {
case ok:
return ip, nil
case okv4:
return ipv4, nil
case okv4:
return ipv4, nil
case xRealOk && len(xRealIPs) > 0:
return string(xRealIPs[0]), nil
case xRealOk && len(xRealIPs) > 0:
return string(xRealIPs[0]), nil
default:
portIndex := len(r.RemoteAddr) - 1
for ; portIndex >= 0; portIndex-- {
if r.RemoteAddr[portIndex] == ':' {
break
}
}
if portIndex != -1 {
return r.RemoteAddr[0:portIndex], nil
}
return "", errors.New("Failed to parse IP address")
}
default:
portIndex := len(r.RemoteAddr) - 1
for ; portIndex >= 0; portIndex-- {
if r.RemoteAddr[portIndex] == ':' {
break
}
}
if portIndex != -1 {
return r.RemoteAddr[0:portIndex], nil
}
return "", errors.New("Failed to parse IP address")
}
}
func minInt(a, b int) int {
if a < b {
return a
}
return b
if a < b {
return a
}
return b
}
func writeSeeders(w http.ResponseWriter, t *storage.Torrent, count, numWant int, compact bool) {
for _, seed := range t.Seeders {
if count >= numWant {
break
}
if compact {
// TODO writeBencoded(w, compactAddr)
} else {
writeBencoded(w, "d")
writeBencoded(w, "ip")
writeBencoded(w, seed.IP)
writeBencoded(w, "peer id")
writeBencoded(w, seed.ID)
writeBencoded(w, "port")
writeBencoded(w, seed.Port)
writeBencoded(w, "e")
}
count++
}
for _, seed := range t.Seeders {
if count >= numWant {
break
}
if compact {
// TODO writeBencoded(w, compactAddr)
} else {
writeBencoded(w, "d")
writeBencoded(w, "ip")
writeBencoded(w, seed.IP)
writeBencoded(w, "peer id")
writeBencoded(w, seed.ID)
writeBencoded(w, "port")
writeBencoded(w, seed.Port)
writeBencoded(w, "e")
}
count++
}
}
func writeLeechers(w http.ResponseWriter, t *storage.Torrent, count, numWant int, compact bool) {
for _, leech := range t.Leechers {
if count >= numWant {
break
}
if compact {
// TODO writeBencoded(w, compactAddr)
} else {
writeBencoded(w, "d")
writeBencoded(w, "ip")
writeBencoded(w, leech.IP)
writeBencoded(w, "peer id")
writeBencoded(w, leech.ID)
writeBencoded(w, "port")
writeBencoded(w, leech.Port)
writeBencoded(w, "e")
}
count++
}
for _, leech := range t.Leechers {
if count >= numWant {
break
}
if compact {
// TODO writeBencoded(w, compactAddr)
} else {
writeBencoded(w, "d")
writeBencoded(w, "ip")
writeBencoded(w, leech.IP)
writeBencoded(w, "peer id")
writeBencoded(w, leech.ID)
writeBencoded(w, "port")
writeBencoded(w, leech.Port)
writeBencoded(w, "e")
}
count++
}
}

View file

@ -5,72 +5,72 @@
package server
import (
"errors"
"io"
"log"
"net/http"
"path"
"errors"
"io"
"log"
"net/http"
"path"
"github.com/pushrax/chihaya/storage"
"github.com/pushrax/chihaya/storage"
)
func (s *Server) serveScrape(w http.ResponseWriter, r *http.Request) {
// Parse the query
pq, err := parseQuery(r.URL.RawQuery)
if err != nil {
fail(errors.New("Error parsing query"), w, r)
return
}
// Parse the query
pq, err := parseQuery(r.URL.RawQuery)
if err != nil {
fail(errors.New("Error parsing query"), w, r)
return
}
// Get a connection to the tracker db
conn, err := s.dbConnPool.Get()
if err != nil {
log.Fatal(err)
}
// Get a connection to the tracker db
conn, err := s.dbConnPool.Get()
if err != nil {
log.Fatal(err)
}
// Find and validate the user
passkey, _ := path.Split(r.URL.Path)
_, err = validateUser(conn, passkey)
if err != nil {
fail(err, w, r)
return
}
// Find and validate the user
passkey, _ := path.Split(r.URL.Path)
_, err = validateUser(conn, passkey)
if err != nil {
fail(err, w, r)
return
}
io.WriteString(w, "d")
writeBencoded(w, "files")
if pq.Infohashes != nil {
for _, infohash := range pq.Infohashes {
torrent, exists, err := conn.FindTorrent(infohash)
if err != nil {
log.Panicf("server: %s", err)
}
if exists {
writeBencoded(w, infohash)
writeScrapeInfo(w, torrent)
}
}
} else if infohash, exists := pq.Params["info_hash"]; exists {
torrent, exists, err := conn.FindTorrent(infohash)
if err != nil {
log.Panicf("server: %s", err)
}
if exists {
writeBencoded(w, infohash)
writeScrapeInfo(w, torrent)
}
}
io.WriteString(w, "e")
io.WriteString(w, "d")
writeBencoded(w, "files")
if pq.Infohashes != nil {
for _, infohash := range pq.Infohashes {
torrent, exists, err := conn.FindTorrent(infohash)
if err != nil {
log.Panicf("server: %s", err)
}
if exists {
writeBencoded(w, infohash)
writeScrapeInfo(w, torrent)
}
}
} else if infohash, exists := pq.Params["info_hash"]; exists {
torrent, exists, err := conn.FindTorrent(infohash)
if err != nil {
log.Panicf("server: %s", err)
}
if exists {
writeBencoded(w, infohash)
writeScrapeInfo(w, torrent)
}
}
io.WriteString(w, "e")
w.(http.Flusher).Flush()
w.(http.Flusher).Flush()
}
func writeScrapeInfo(w io.Writer, torrent *storage.Torrent) {
io.WriteString(w, "d")
writeBencoded(w, "complete")
writeBencoded(w, len(torrent.Seeders))
writeBencoded(w, "downloaded")
writeBencoded(w, torrent.Snatches)
writeBencoded(w, "incomplete")
writeBencoded(w, len(torrent.Leechers))
io.WriteString(w, "e")
io.WriteString(w, "d")
writeBencoded(w, "complete")
writeBencoded(w, len(torrent.Seeders))
writeBencoded(w, "downloaded")
writeBencoded(w, torrent.Snatches)
writeBencoded(w, "incomplete")
writeBencoded(w, len(torrent.Leechers))
io.WriteString(w, "e")
}

View file

@ -6,140 +6,140 @@
package server
import (
"errors"
"io"
"log"
"net"
"net/http"
"path"
"strconv"
"sync/atomic"
"time"
"errors"
"io"
"log"
"net"
"net/http"
"path"
"strconv"
"sync/atomic"
"time"
"github.com/etix/stoppableListener"
"github.com/etix/stoppableListener"
"github.com/pushrax/chihaya/config"
"github.com/pushrax/chihaya/storage"
"github.com/pushrax/chihaya/storage/tracker"
"github.com/pushrax/chihaya/config"
"github.com/pushrax/chihaya/storage"
"github.com/pushrax/chihaya/storage/tracker"
)
type Server struct {
conf *config.Config
listener *stoppableListener.StoppableListener
dbConnPool tracker.Pool
conf *config.Config
listener *stoppableListener.StoppableListener
dbConnPool tracker.Pool
startTime time.Time
startTime time.Time
deltaRequests int64
rpm int64
deltaRequests int64
rpm int64
http.Server
http.Server
}
func New(conf *config.Config) (*Server, error) {
pool, err := tracker.Open(&conf.Cache)
if err != nil {
return nil, err
}
pool, err := tracker.Open(&conf.Cache)
if err != nil {
return nil, err
}
s := &Server{
conf: conf,
dbConnPool: pool,
Server: http.Server{
Addr: conf.Addr,
ReadTimeout: conf.ReadTimeout.Duration,
},
}
s.Server.Handler = s
s := &Server{
conf: conf,
dbConnPool: pool,
Server: http.Server{
Addr: conf.Addr,
ReadTimeout: conf.ReadTimeout.Duration,
},
}
s.Server.Handler = s
return s, nil
return s, nil
}
func (s *Server) ListenAndServe() error {
l, err := net.Listen("tcp", s.Addr)
if err != nil {
return err
}
sl := stoppableListener.Handle(l)
s.listener = sl
s.startTime = time.Now()
l, err := net.Listen("tcp", s.Addr)
if err != nil {
return err
}
sl := stoppableListener.Handle(l)
s.listener = sl
s.startTime = time.Now()
go s.updateStats()
s.Serve(s.listener)
go s.updateStats()
s.Serve(s.listener)
return nil
return nil
}
func (s *Server) Stop() error {
s.listener.Stop <- true
err := s.dbConnPool.Close()
if err != nil {
return err
}
return s.listener.Close()
s.listener.Stop <- true
err := s.dbConnPool.Close()
if err != nil {
return err
}
return s.listener.Close()
}
func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
defer atomic.AddInt64(&s.deltaRequests, 1)
r.Close = true
defer atomic.AddInt64(&s.deltaRequests, 1)
r.Close = true
switch r.URL.Path {
case "/stats":
s.serveStats(w, r)
return
case "/add":
s.serveAdd(w, r)
return
case "/remove":
s.serveRemove(w, r)
return
}
switch r.URL.Path {
case "/stats":
s.serveStats(w, r)
return
case "/add":
s.serveAdd(w, r)
return
case "/remove":
s.serveRemove(w, r)
return
}
_, action := path.Split(r.URL.Path)
switch action {
case "announce":
s.serveAnnounce(w, r)
return
case "scrape":
s.serveScrape(w, r)
return
default:
fail(errors.New("Unknown action"), w, r)
return
}
_, action := path.Split(r.URL.Path)
switch action {
case "announce":
s.serveAnnounce(w, r)
return
case "scrape":
s.serveScrape(w, r)
return
default:
fail(errors.New("Unknown action"), w, r)
return
}
}
func fail(err error, w http.ResponseWriter, r *http.Request) {
errmsg := err.Error()
message := "d14:failure reason" + strconv.Itoa(len(errmsg)) + ":" + errmsg + "e"
length, _ := io.WriteString(w, message)
w.Header().Add("Content-Length", string(length))
w.(http.Flusher).Flush()
errmsg := err.Error()
message := "d14:failure reason" + strconv.Itoa(len(errmsg)) + ":" + errmsg + "e"
length, _ := io.WriteString(w, message)
w.Header().Add("Content-Length", string(length))
w.(http.Flusher).Flush()
}
func validateUser(conn tracker.Conn, dir string) (*storage.User, error) {
if len(dir) != 34 {
return nil, errors.New("Passkey is invalid")
}
passkey := dir[1:33]
if len(dir) != 34 {
return nil, errors.New("Passkey is invalid")
}
passkey := dir[1:33]
user, exists, err := conn.FindUser(passkey)
if err != nil {
log.Panicf("server: %s", err)
}
if !exists {
return nil, errors.New("User not found")
}
user, exists, err := conn.FindUser(passkey)
if err != nil {
log.Panicf("server: %s", err)
}
if !exists {
return nil, errors.New("User not found")
}
return user, nil
return user, nil
}
// Takes a peer_id and returns a ClientID
func parsePeerID(peerID string) (clientID string) {
if peerID[0] == '-' {
clientID = peerID[1:7]
} else {
clientID = peerID[0:6]
}
return
if peerID[0] == '-' {
clientID = peerID[1:7]
} else {
clientID = peerID[0:6]
}
return
}

View file

@ -5,35 +5,35 @@
package server
import (
"encoding/json"
"net/http"
"sync/atomic"
"time"
"encoding/json"
"net/http"
"sync/atomic"
"time"
"github.com/pushrax/chihaya/config"
"github.com/pushrax/chihaya/config"
)
type stats struct {
Uptime config.Duration `json:"uptime"`
RPM int64 `json:"req_per_min"`
Uptime config.Duration `json:"uptime"`
RPM int64 `json:"req_per_min"`
}
func (s *Server) serveStats(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.Header().Set("Content-Type", "application/json")
stats, _ := json.Marshal(&stats{
config.Duration{time.Now().Sub(s.startTime)},
s.rpm,
})
stats, _ := json.Marshal(&stats{
config.Duration{time.Now().Sub(s.startTime)},
s.rpm,
})
length, _ := w.Write(stats)
w.Header().Set("Content-Length", string(length))
w.(http.Flusher).Flush()
length, _ := w.Write(stats)
w.Header().Set("Content-Length", string(length))
w.(http.Flusher).Flush()
}
func (s *Server) updateStats() {
for _ = range time.NewTicker(time.Minute).C {
s.rpm = s.deltaRequests
atomic.StoreInt64(&s.deltaRequests, 0)
}
for _ = range time.NewTicker(time.Minute).C {
s.rpm = s.deltaRequests
atomic.StoreInt64(&s.deltaRequests, 0)
}
}

View file

@ -5,51 +5,51 @@
package server
import (
"errors"
"net/http"
"net/http/httptest"
"os"
"testing"
"errors"
"net/http"
"net/http/httptest"
"os"
"testing"
"github.com/pushrax/chihaya/config"
"github.com/pushrax/chihaya/config"
_ "github.com/pushrax/chihaya/storage/backend/batter"
_ "github.com/pushrax/chihaya/storage/tracker/redis"
_ "github.com/pushrax/chihaya/storage/backend/batter"
_ "github.com/pushrax/chihaya/storage/tracker/redis"
)
func newTestServer() (*Server, error) {
testConfig, err := config.Open(os.Getenv("TESTCONFIGPATH"))
if err != nil {
return nil, err
}
testConfig, err := config.Open(os.Getenv("TESTCONFIGPATH"))
if err != nil {
return nil, err
}
s, err := New(testConfig)
if err != nil {
return nil, err
}
s, err := New(testConfig)
if err != nil {
return nil, err
}
return s, nil
return s, nil
}
func TestStats(t *testing.T) {
s, err := newTestServer()
if err != nil {
t.Error(err)
}
s, err := newTestServer()
if err != nil {
t.Error(err)
}
r, err := http.NewRequest("GET", "127.0.0.1:80/stats", nil)
if err != nil {
t.Error(err)
}
r, err := http.NewRequest("GET", "127.0.0.1:80/stats", nil)
if err != nil {
t.Error(err)
}
w := httptest.NewRecorder()
s.serveStats(w, r)
w := httptest.NewRecorder()
s.serveStats(w, r)
if w.Code != 200 {
t.Error(errors.New("/stats did not return HTTP 200"))
}
if w.Code != 200 {
t.Error(errors.New("/stats did not return HTTP 200"))
}
if w.Header()["Content-Type"][0] != "application/json" {
t.Error(errors.New("/stats did not return the proper Content-Type header"))
}
if w.Header()["Content-Type"][0] != "application/json" {
t.Error(errors.New("/stats did not return the proper Content-Type header"))
}
}

View file

@ -5,559 +5,559 @@
package redis
import (
"math/rand"
"os"
"reflect"
"testing"
"time"
"math/rand"
"os"
"reflect"
"testing"
"time"
"github.com/pushrax/chihaya/config"
"github.com/pushrax/chihaya/storage"
"github.com/pushrax/chihaya/storage/tracker"
"github.com/pushrax/chihaya/config"
"github.com/pushrax/chihaya/storage"
"github.com/pushrax/chihaya/storage/tracker"
)
func createTestConn() tracker.Conn {
testConfig, err := config.Open(os.Getenv("TESTCONFIGPATH"))
panicOnErr(err)
conf := &testConfig.Cache
testConfig, err := config.Open(os.Getenv("TESTCONFIGPATH"))
panicOnErr(err)
conf := &testConfig.Cache
testPool, err := tracker.Open(conf)
panicOnErr(err)
testPool, err := tracker.Open(conf)
panicOnErr(err)
newConn, err := testPool.Get()
panicOnErr(err)
newConn, err := testPool.Get()
panicOnErr(err)
return newConn
return newConn
}
func TestFindUserSuccess(t *testing.T) {
conn := createTestConn()
testUser := createTestUser()
conn := createTestConn()
testUser := createTestUser()
panicOnErr(conn.AddUser(testUser))
foundUser, found, err := conn.FindUser(testUser.Passkey)
panicOnErr(err)
if !found {
t.Error("user not found", testUser)
}
if *foundUser != *testUser {
t.Error("found user mismatch", *foundUser, testUser)
}
// Cleanup
panicOnErr(conn.RemoveUser(testUser))
panicOnErr(conn.AddUser(testUser))
foundUser, found, err := conn.FindUser(testUser.Passkey)
panicOnErr(err)
if !found {
t.Error("user not found", testUser)
}
if *foundUser != *testUser {
t.Error("found user mismatch", *foundUser, testUser)
}
// Cleanup
panicOnErr(conn.RemoveUser(testUser))
}
func TestFindUserFail(t *testing.T) {
conn := createTestConn()
testUser := createTestUser()
conn := createTestConn()
testUser := createTestUser()
foundUser, found, err := conn.FindUser(testUser.Passkey)
panicOnErr(err)
if found {
t.Error("user found", foundUser)
}
foundUser, found, err := conn.FindUser(testUser.Passkey)
panicOnErr(err)
if found {
t.Error("user found", foundUser)
}
}
func TestRemoveUser(t *testing.T) {
conn := createTestConn()
testUser := createTestUser()
conn := createTestConn()
testUser := createTestUser()
panicOnErr(conn.AddUser(testUser))
err := conn.RemoveUser(testUser)
panicOnErr(err)
foundUser, found, err := conn.FindUser(testUser.Passkey)
panicOnErr(err)
if found {
t.Error("removed user found", foundUser)
}
panicOnErr(conn.AddUser(testUser))
err := conn.RemoveUser(testUser)
panicOnErr(err)
foundUser, found, err := conn.FindUser(testUser.Passkey)
panicOnErr(err)
if found {
t.Error("removed user found", foundUser)
}
}
func TestFindTorrentSuccess(t *testing.T) {
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
foundTorrent, found, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
if !found {
t.Error("torrent not found", testTorrent)
}
if !reflect.DeepEqual(foundTorrent, testTorrent) {
t.Error("found torrent mismatch", foundTorrent, testTorrent)
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
foundTorrent, found, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
if !found {
t.Error("torrent not found", testTorrent)
}
if !reflect.DeepEqual(foundTorrent, testTorrent) {
t.Error("found torrent mismatch", foundTorrent, testTorrent)
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
}
func TestFindTorrentFail(t *testing.T) {
conn := createTestConn()
testTorrent := createTestTorrent()
conn := createTestConn()
testTorrent := createTestTorrent()
foundTorrent, found, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
if found {
t.Error("torrent found", foundTorrent)
}
foundTorrent, found, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
if found {
t.Error("torrent found", foundTorrent)
}
}
func TestRemoveTorrent(t *testing.T) {
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
panicOnErr(conn.RemoveTorrent(testTorrent))
foundTorrent, found, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
if found {
t.Error("removed torrent found", foundTorrent)
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
panicOnErr(conn.RemoveTorrent(testTorrent))
foundTorrent, found, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
if found {
t.Error("removed torrent found", foundTorrent)
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
}
func TestClientWhitelistSuccess(t *testing.T) {
conn := createTestConn()
testPeerID := "-lt0D30-"
conn := createTestConn()
testPeerID := "-lt0D30-"
panicOnErr(conn.WhitelistClient(testPeerID))
found, err := conn.ClientWhitelisted(testPeerID)
panicOnErr(err)
if !found {
t.Error("peerID not found", testPeerID)
}
// Cleanup
panicOnErr(conn.UnWhitelistClient(testPeerID))
panicOnErr(conn.WhitelistClient(testPeerID))
found, err := conn.ClientWhitelisted(testPeerID)
panicOnErr(err)
if !found {
t.Error("peerID not found", testPeerID)
}
// Cleanup
panicOnErr(conn.UnWhitelistClient(testPeerID))
}
func TestClientWhitelistFail(t *testing.T) {
conn := createTestConn()
testPeerID2 := "TIX0192"
conn := createTestConn()
testPeerID2 := "TIX0192"
found, err := conn.ClientWhitelisted(testPeerID2)
panicOnErr(err)
if found {
t.Error("peerID found", testPeerID2)
}
found, err := conn.ClientWhitelisted(testPeerID2)
panicOnErr(err)
if found {
t.Error("peerID found", testPeerID2)
}
}
func TestRecordSnatch(t *testing.T) {
conn := createTestConn()
testTorrent := createTestTorrent()
testUser := createTestUser()
panicOnErr(conn.AddTorrent(testTorrent))
panicOnErr(conn.AddUser(testUser))
conn := createTestConn()
testTorrent := createTestTorrent()
testUser := createTestUser()
panicOnErr(conn.AddTorrent(testTorrent))
panicOnErr(conn.AddUser(testUser))
userSnatches := testUser.Snatches
torrentSnatches := testTorrent.Snatches
userSnatches := testUser.Snatches
torrentSnatches := testTorrent.Snatches
panicOnErr(conn.RecordSnatch(testUser, testTorrent))
panicOnErr(conn.RecordSnatch(testUser, testTorrent))
foundTorrent, _, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundUser, _, err := conn.FindUser(testUser.Passkey)
panicOnErr(err)
foundTorrent, _, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundUser, _, err := conn.FindUser(testUser.Passkey)
panicOnErr(err)
if testUser.Snatches != userSnatches+1 {
t.Error("snatch not recorded to local user", testUser.Snatches, userSnatches+1)
}
if testTorrent.Snatches != torrentSnatches+1 {
t.Error("snatch not recorded to local torrent")
}
if foundUser.Snatches != userSnatches+1 {
t.Error("snatch not recorded to cached user", foundUser.Snatches, userSnatches+1)
}
if foundTorrent.Snatches != torrentSnatches+1 {
t.Error("snatch not recorded to cached torrent")
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
panicOnErr(conn.RemoveUser(testUser))
if testUser.Snatches != userSnatches+1 {
t.Error("snatch not recorded to local user", testUser.Snatches, userSnatches+1)
}
if testTorrent.Snatches != torrentSnatches+1 {
t.Error("snatch not recorded to local torrent")
}
if foundUser.Snatches != userSnatches+1 {
t.Error("snatch not recorded to cached user", foundUser.Snatches, userSnatches+1)
}
if foundTorrent.Snatches != torrentSnatches+1 {
t.Error("snatch not recorded to cached torrent")
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
panicOnErr(conn.RemoveUser(testUser))
}
func TestMarkActive(t *testing.T) {
conn := createTestConn()
testTorrent := createTestTorrent()
testTorrent.Active = false
panicOnErr(conn.AddTorrent(testTorrent))
conn := createTestConn()
testTorrent := createTestTorrent()
testTorrent.Active = false
panicOnErr(conn.AddTorrent(testTorrent))
panicOnErr(conn.MarkActive(testTorrent))
foundTorrent, _, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
panicOnErr(conn.MarkActive(testTorrent))
foundTorrent, _, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
if foundTorrent.Active != true {
t.Error("cached torrent not activated")
}
if testTorrent.Active != true {
t.Error("cached torrent not activated")
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
if foundTorrent.Active != true {
t.Error("cached torrent not activated")
}
if testTorrent.Active != true {
t.Error("cached torrent not activated")
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
}
func TestClientWhitelistRemove(t *testing.T) {
conn := createTestConn()
testPeerID := "-lt0D30-"
panicOnErr(conn.WhitelistClient(testPeerID))
panicOnErr(conn.UnWhitelistClient(testPeerID))
conn := createTestConn()
testPeerID := "-lt0D30-"
panicOnErr(conn.WhitelistClient(testPeerID))
panicOnErr(conn.UnWhitelistClient(testPeerID))
found, err := conn.ClientWhitelisted(testPeerID)
panicOnErr(err)
if found {
t.Error("removed peerID found", testPeerID)
}
found, err := conn.ClientWhitelisted(testPeerID)
panicOnErr(err)
if found {
t.Error("removed peerID found", testPeerID)
}
}
func TestAddSeeder(t *testing.T) {
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
testSeeder := createTestPeer(createTestUserID(), testTorrent.ID)
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
testSeeder := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddSeeder(testTorrent, testSeeder))
foundTorrent, found, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundSeeder, found := foundTorrent.Seeders[storage.PeerMapKey(testSeeder)]
if found && foundSeeder != *testSeeder {
t.Error("seeder not added to cache", testSeeder)
}
foundSeeder, found = testTorrent.Seeders[storage.PeerMapKey(testSeeder)]
if found && foundSeeder != *testSeeder {
t.Error("seeder not added to local", testSeeder)
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
panicOnErr(conn.AddSeeder(testTorrent, testSeeder))
foundTorrent, found, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundSeeder, found := foundTorrent.Seeders[storage.PeerMapKey(testSeeder)]
if found && foundSeeder != *testSeeder {
t.Error("seeder not added to cache", testSeeder)
}
foundSeeder, found = testTorrent.Seeders[storage.PeerMapKey(testSeeder)]
if found && foundSeeder != *testSeeder {
t.Error("seeder not added to local", testSeeder)
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
}
func TestAddLeecher(t *testing.T) {
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
testLeecher := createTestPeer(createTestUserID(), testTorrent.ID)
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
testLeecher := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddLeecher(testTorrent, testLeecher))
foundTorrent, found, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundLeecher, found := foundTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if found && foundLeecher != *testLeecher {
t.Error("leecher not added to cache", testLeecher)
}
foundLeecher, found = testTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if found && foundLeecher != *testLeecher {
t.Error("leecher not added to local", testLeecher)
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
panicOnErr(conn.AddLeecher(testTorrent, testLeecher))
foundTorrent, found, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundLeecher, found := foundTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if found && foundLeecher != *testLeecher {
t.Error("leecher not added to cache", testLeecher)
}
foundLeecher, found = testTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if found && foundLeecher != *testLeecher {
t.Error("leecher not added to local", testLeecher)
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
}
func TestRemoveSeeder(t *testing.T) {
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
testSeeder := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddSeeder(testTorrent, testSeeder))
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
testSeeder := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddSeeder(testTorrent, testSeeder))
panicOnErr(conn.RemoveSeeder(testTorrent, testSeeder))
foundSeeder, found := testTorrent.Seeders[storage.PeerMapKey(testSeeder)]
if found || foundSeeder == *testSeeder {
t.Error("seeder not removed from local", foundSeeder)
}
panicOnErr(conn.RemoveSeeder(testTorrent, testSeeder))
foundSeeder, found := testTorrent.Seeders[storage.PeerMapKey(testSeeder)]
if found || foundSeeder == *testSeeder {
t.Error("seeder not removed from local", foundSeeder)
}
foundTorrent, found, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundSeeder, found = foundTorrent.Seeders[storage.PeerMapKey(testSeeder)]
if found || foundSeeder == *testSeeder {
t.Error("seeder not removed from cache", foundSeeder, *testSeeder)
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
foundTorrent, found, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundSeeder, found = foundTorrent.Seeders[storage.PeerMapKey(testSeeder)]
if found || foundSeeder == *testSeeder {
t.Error("seeder not removed from cache", foundSeeder, *testSeeder)
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
}
func TestRemoveLeecher(t *testing.T) {
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
testLeecher := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddLeecher(testTorrent, testLeecher))
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
testLeecher := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddLeecher(testTorrent, testLeecher))
panicOnErr(conn.RemoveLeecher(testTorrent, testLeecher))
foundTorrent, found, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundLeecher, found := foundTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if found || foundLeecher == *testLeecher {
t.Error("leecher not removed from cache", foundLeecher, *testLeecher)
}
foundLeecher, found = testTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if found || foundLeecher == *testLeecher {
t.Error("leecher not removed from local", foundLeecher, *testLeecher)
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
panicOnErr(conn.RemoveLeecher(testTorrent, testLeecher))
foundTorrent, found, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundLeecher, found := foundTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if found || foundLeecher == *testLeecher {
t.Error("leecher not removed from cache", foundLeecher, *testLeecher)
}
foundLeecher, found = testTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if found || foundLeecher == *testLeecher {
t.Error("leecher not removed from local", foundLeecher, *testLeecher)
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
}
func TestSetSeeder(t *testing.T) {
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
testSeeder := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddSeeder(testTorrent, testSeeder))
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
testSeeder := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddSeeder(testTorrent, testSeeder))
r := rand.New(rand.NewSource(time.Now().UnixNano()))
testSeeder.Uploaded += uint64(r.Int63())
r := rand.New(rand.NewSource(time.Now().UnixNano()))
testSeeder.Uploaded += uint64(r.Int63())
panicOnErr(conn.SetSeeder(testTorrent, testSeeder))
panicOnErr(conn.SetSeeder(testTorrent, testSeeder))
foundTorrent, _, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundSeeder, _ := foundTorrent.Seeders[storage.PeerMapKey(testSeeder)]
if foundSeeder != *testSeeder {
t.Error("seeder not updated in cache", foundSeeder, *testSeeder)
}
foundSeeder, _ = testTorrent.Seeders[storage.PeerMapKey(testSeeder)]
if foundSeeder != *testSeeder {
t.Error("seeder not updated in local", foundSeeder, *testSeeder)
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
foundTorrent, _, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundSeeder, _ := foundTorrent.Seeders[storage.PeerMapKey(testSeeder)]
if foundSeeder != *testSeeder {
t.Error("seeder not updated in cache", foundSeeder, *testSeeder)
}
foundSeeder, _ = testTorrent.Seeders[storage.PeerMapKey(testSeeder)]
if foundSeeder != *testSeeder {
t.Error("seeder not updated in local", foundSeeder, *testSeeder)
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
}
func TestSetLeecher(t *testing.T) {
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
testLeecher := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddLeecher(testTorrent, testLeecher))
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
testLeecher := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddLeecher(testTorrent, testLeecher))
r := rand.New(rand.NewSource(time.Now().UnixNano()))
testLeecher.Uploaded += uint64(r.Int63())
r := rand.New(rand.NewSource(time.Now().UnixNano()))
testLeecher.Uploaded += uint64(r.Int63())
panicOnErr(conn.SetLeecher(testTorrent, testLeecher))
foundTorrent, _, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundLeecher, _ := foundTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if foundLeecher != *testLeecher {
t.Error("leecher not updated in cache", testLeecher)
}
foundLeecher, _ = testTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if foundLeecher != *testLeecher {
t.Error("leecher not updated in local", testLeecher)
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
panicOnErr(conn.SetLeecher(testTorrent, testLeecher))
foundTorrent, _, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundLeecher, _ := foundTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if foundLeecher != *testLeecher {
t.Error("leecher not updated in cache", testLeecher)
}
foundLeecher, _ = testTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if foundLeecher != *testLeecher {
t.Error("leecher not updated in local", testLeecher)
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
}
func TestIncrementSlots(t *testing.T) {
conn := createTestConn()
testUser := createTestUser()
panicOnErr(conn.AddUser(testUser))
numSlots := testUser.Slots
conn := createTestConn()
testUser := createTestUser()
panicOnErr(conn.AddUser(testUser))
numSlots := testUser.Slots
panicOnErr(conn.IncrementSlots(testUser))
foundUser, _, err := conn.FindUser(testUser.Passkey)
panicOnErr(err)
panicOnErr(conn.IncrementSlots(testUser))
foundUser, _, err := conn.FindUser(testUser.Passkey)
panicOnErr(err)
if foundUser.Slots != numSlots+1 {
t.Error("cached slots not incremented")
}
if testUser.Slots != numSlots+1 {
t.Error("local slots not incremented")
}
// Cleanup
panicOnErr(conn.RemoveUser(testUser))
if foundUser.Slots != numSlots+1 {
t.Error("cached slots not incremented")
}
if testUser.Slots != numSlots+1 {
t.Error("local slots not incremented")
}
// Cleanup
panicOnErr(conn.RemoveUser(testUser))
}
func TestDecrementSlots(t *testing.T) {
conn := createTestConn()
testUser := createTestUser()
panicOnErr(conn.AddUser(testUser))
numSlots := testUser.Slots
conn := createTestConn()
testUser := createTestUser()
panicOnErr(conn.AddUser(testUser))
numSlots := testUser.Slots
panicOnErr(conn.DecrementSlots(testUser))
foundUser, _, err := conn.FindUser(testUser.Passkey)
panicOnErr(err)
panicOnErr(conn.DecrementSlots(testUser))
foundUser, _, err := conn.FindUser(testUser.Passkey)
panicOnErr(err)
if foundUser.Slots != numSlots-1 {
t.Error("cached slots not incremented")
}
if testUser.Slots != numSlots-1 {
t.Error("local slots not incremented")
}
// Cleanup
panicOnErr(conn.RemoveUser(testUser))
if foundUser.Slots != numSlots-1 {
t.Error("cached slots not incremented")
}
if testUser.Slots != numSlots-1 {
t.Error("local slots not incremented")
}
// Cleanup
panicOnErr(conn.RemoveUser(testUser))
}
func TestLeecherFinished(t *testing.T) {
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
testLeecher := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddLeecher(testTorrent, testLeecher))
testLeecher.Left = 0
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
testLeecher := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddLeecher(testTorrent, testLeecher))
testLeecher.Left = 0
panicOnErr(conn.LeecherFinished(testTorrent, testLeecher))
panicOnErr(conn.LeecherFinished(testTorrent, testLeecher))
foundTorrent, _, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundSeeder, _ := foundTorrent.Seeders[storage.PeerMapKey(testLeecher)]
if foundSeeder != *testLeecher {
t.Error("seeder not added to cache", foundSeeder, *testLeecher)
}
foundSeeder, _ = foundTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if foundSeeder == *testLeecher {
t.Error("leecher not removed from cache", testLeecher)
}
foundSeeder, _ = testTorrent.Seeders[storage.PeerMapKey(testLeecher)]
if foundSeeder != *testLeecher {
t.Error("seeder not added to local", testLeecher)
}
foundSeeder, _ = testTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if foundSeeder == *testLeecher {
t.Error("leecher not removed from local", testLeecher)
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
foundTorrent, _, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundSeeder, _ := foundTorrent.Seeders[storage.PeerMapKey(testLeecher)]
if foundSeeder != *testLeecher {
t.Error("seeder not added to cache", foundSeeder, *testLeecher)
}
foundSeeder, _ = foundTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if foundSeeder == *testLeecher {
t.Error("leecher not removed from cache", testLeecher)
}
foundSeeder, _ = testTorrent.Seeders[storage.PeerMapKey(testLeecher)]
if foundSeeder != *testLeecher {
t.Error("seeder not added to local", testLeecher)
}
foundSeeder, _ = testTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if foundSeeder == *testLeecher {
t.Error("leecher not removed from local", testLeecher)
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
}
// Add, update, verify remove
func TestUpdatePeer(t *testing.T) {
conn := createTestConn()
testTorrent := createTestTorrent()
testSeeder := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddTorrent(testTorrent))
panicOnErr(conn.AddSeeder(testTorrent, testSeeder))
// Update a seeder, set it, then check to make sure it updated
r := rand.New(rand.NewSource(time.Now().UnixNano()))
testSeeder.Uploaded += uint64(r.Int63())
conn := createTestConn()
testTorrent := createTestTorrent()
testSeeder := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddTorrent(testTorrent))
panicOnErr(conn.AddSeeder(testTorrent, testSeeder))
// Update a seeder, set it, then check to make sure it updated
r := rand.New(rand.NewSource(time.Now().UnixNano()))
testSeeder.Uploaded += uint64(r.Int63())
panicOnErr(conn.SetSeeder(testTorrent, testSeeder))
panicOnErr(conn.SetSeeder(testTorrent, testSeeder))
panicOnErr(conn.RemoveSeeder(testTorrent, testSeeder))
foundTorrent, _, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
if seeder, exists := foundTorrent.Seeders[storage.PeerMapKey(testSeeder)]; exists {
t.Error("seeder not removed from cache", seeder)
}
if seeder, exists := testTorrent.Seeders[storage.PeerMapKey(testSeeder)]; exists {
t.Error("seeder not removed from local", seeder)
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
panicOnErr(conn.RemoveSeeder(testTorrent, testSeeder))
foundTorrent, _, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
if seeder, exists := foundTorrent.Seeders[storage.PeerMapKey(testSeeder)]; exists {
t.Error("seeder not removed from cache", seeder)
}
if seeder, exists := testTorrent.Seeders[storage.PeerMapKey(testSeeder)]; exists {
t.Error("seeder not removed from local", seeder)
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
}
func TestParallelFindUser(t *testing.T) {
t.Parallel()
if testing.Short() {
t.Skip()
}
conn := createTestConn()
testUserSuccess := createTestUser()
testUserFail := createTestUser()
panicOnErr(conn.AddUser(testUserSuccess))
t.Parallel()
if testing.Short() {
t.Skip()
}
conn := createTestConn()
testUserSuccess := createTestUser()
testUserFail := createTestUser()
panicOnErr(conn.AddUser(testUserSuccess))
for i := 0; i < 10; i++ {
foundUser, found, err := conn.FindUser(testUserFail.Passkey)
panicOnErr(err)
if found {
t.Error("user found", foundUser)
}
foundUser, found, err = conn.FindUser(testUserSuccess.Passkey)
panicOnErr(err)
if !found {
t.Error("user not found", testUserSuccess)
}
if *foundUser != *testUserSuccess {
t.Error("found user mismatch", *foundUser, testUserSuccess)
}
}
// Cleanup
panicOnErr(conn.RemoveUser(testUserSuccess))
for i := 0; i < 10; i++ {
foundUser, found, err := conn.FindUser(testUserFail.Passkey)
panicOnErr(err)
if found {
t.Error("user found", foundUser)
}
foundUser, found, err = conn.FindUser(testUserSuccess.Passkey)
panicOnErr(err)
if !found {
t.Error("user not found", testUserSuccess)
}
if *foundUser != *testUserSuccess {
t.Error("found user mismatch", *foundUser, testUserSuccess)
}
}
// Cleanup
panicOnErr(conn.RemoveUser(testUserSuccess))
}
func TestParallelFindTorrent(t *testing.T) {
t.Parallel()
if testing.Short() {
t.Skip()
}
conn := createTestConn()
testTorrentSuccess := createTestTorrent()
testTorrentFail := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrentSuccess))
t.Parallel()
if testing.Short() {
t.Skip()
}
conn := createTestConn()
testTorrentSuccess := createTestTorrent()
testTorrentFail := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrentSuccess))
for i := 0; i < 10; i++ {
foundTorrent, found, err := conn.FindTorrent(testTorrentSuccess.Infohash)
panicOnErr(err)
if !found {
t.Error("torrent not found", testTorrentSuccess)
}
if !reflect.DeepEqual(foundTorrent, testTorrentSuccess) {
t.Error("found torrent mismatch", foundTorrent, testTorrentSuccess)
}
foundTorrent, found, err = conn.FindTorrent(testTorrentFail.Infohash)
panicOnErr(err)
if found {
t.Error("torrent found", foundTorrent)
}
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrentSuccess))
for i := 0; i < 10; i++ {
foundTorrent, found, err := conn.FindTorrent(testTorrentSuccess.Infohash)
panicOnErr(err)
if !found {
t.Error("torrent not found", testTorrentSuccess)
}
if !reflect.DeepEqual(foundTorrent, testTorrentSuccess) {
t.Error("found torrent mismatch", foundTorrent, testTorrentSuccess)
}
foundTorrent, found, err = conn.FindTorrent(testTorrentFail.Infohash)
panicOnErr(err)
if found {
t.Error("torrent found", foundTorrent)
}
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrentSuccess))
}
func TestParallelSetSeeder(t *testing.T) {
t.Parallel()
if testing.Short() {
t.Skip()
}
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
testSeeder := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddSeeder(testTorrent, testSeeder))
r := rand.New(rand.NewSource(time.Now().UnixNano()))
t.Parallel()
if testing.Short() {
t.Skip()
}
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
testSeeder := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddSeeder(testTorrent, testSeeder))
r := rand.New(rand.NewSource(time.Now().UnixNano()))
for i := 0; i < 10; i++ {
testSeeder.Uploaded += uint64(r.Int63())
for i := 0; i < 10; i++ {
testSeeder.Uploaded += uint64(r.Int63())
panicOnErr(conn.SetSeeder(testTorrent, testSeeder))
panicOnErr(conn.SetSeeder(testTorrent, testSeeder))
foundTorrent, _, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundSeeder, _ := foundTorrent.Seeders[storage.PeerMapKey(testSeeder)]
if foundSeeder != *testSeeder {
t.Error("seeder not updated in cache", foundSeeder, *testSeeder)
}
foundSeeder, _ = testTorrent.Seeders[storage.PeerMapKey(testSeeder)]
if foundSeeder != *testSeeder {
t.Error("seeder not updated in local", foundSeeder, *testSeeder)
}
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
foundTorrent, _, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundSeeder, _ := foundTorrent.Seeders[storage.PeerMapKey(testSeeder)]
if foundSeeder != *testSeeder {
t.Error("seeder not updated in cache", foundSeeder, *testSeeder)
}
foundSeeder, _ = testTorrent.Seeders[storage.PeerMapKey(testSeeder)]
if foundSeeder != *testSeeder {
t.Error("seeder not updated in local", foundSeeder, *testSeeder)
}
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
}
func TestParallelAddLeecher(t *testing.T) {
t.Parallel()
if testing.Short() {
t.Skip()
}
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
t.Parallel()
if testing.Short() {
t.Skip()
}
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
for i := 0; i < 10; i++ {
testLeecher := createTestPeer(createTestUserID(), testTorrent.ID)
for i := 0; i < 10; i++ {
testLeecher := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddLeecher(testTorrent, testLeecher))
panicOnErr(conn.AddLeecher(testTorrent, testLeecher))
foundTorrent, found, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundLeecher, found := foundTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if found && foundLeecher != *testLeecher {
t.Error("leecher not added to cache", testLeecher)
}
foundLeecher, found = testTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if found && foundLeecher != *testLeecher {
t.Error("leecher not added to local", testLeecher)
}
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
foundTorrent, found, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
foundLeecher, found := foundTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if found && foundLeecher != *testLeecher {
t.Error("leecher not added to cache", testLeecher)
}
foundLeecher, found = testTorrent.Leechers[storage.PeerMapKey(testLeecher)]
if found && foundLeecher != *testLeecher {
t.Error("leecher not added to local", testLeecher)
}
}
// Cleanup
panicOnErr(conn.RemoveTorrent(testTorrent))
}

File diff suppressed because it is too large Load diff

View file

@ -5,284 +5,284 @@
package redis
import (
"math/rand"
"testing"
"time"
"math/rand"
"testing"
"time"
)
func BenchmarkSuccessfulFindUser(b *testing.B) {
b.StopTimer()
conn := createTestConn()
testUser := createTestUser()
panicOnErr(conn.AddUser(testUser))
b.StartTimer()
b.StopTimer()
conn := createTestConn()
testUser := createTestUser()
panicOnErr(conn.AddUser(testUser))
b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ {
for bCount := 0; bCount < b.N; bCount++ {
foundUser, found, err := conn.FindUser(testUser.Passkey)
panicOnErr(err)
if !found {
b.Error("user not found", testUser)
}
if *foundUser != *testUser {
b.Error("found user mismatch", *foundUser, testUser)
}
}
// Cleanup
b.StopTimer()
panicOnErr(conn.RemoveUser(testUser))
b.StartTimer()
foundUser, found, err := conn.FindUser(testUser.Passkey)
panicOnErr(err)
if !found {
b.Error("user not found", testUser)
}
if *foundUser != *testUser {
b.Error("found user mismatch", *foundUser, testUser)
}
}
// Cleanup
b.StopTimer()
panicOnErr(conn.RemoveUser(testUser))
b.StartTimer()
}
func BenchmarkFailedFindUser(b *testing.B) {
b.StopTimer()
conn := createTestConn()
testUser := createTestUser()
b.StartTimer()
b.StopTimer()
conn := createTestConn()
testUser := createTestUser()
b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ {
for bCount := 0; bCount < b.N; bCount++ {
_, found, err := conn.FindUser(testUser.Passkey)
panicOnErr(err)
if found {
b.Error("user not found", testUser)
}
}
_, found, err := conn.FindUser(testUser.Passkey)
panicOnErr(err)
if found {
b.Error("user not found", testUser)
}
}
}
func BenchmarkSuccessfulFindTorrent(b *testing.B) {
b.StopTimer()
conn := createTestConn()
testTorrent := createTestTorrent()
b.StopTimer()
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
b.StartTimer()
panicOnErr(conn.AddTorrent(testTorrent))
b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ {
foundTorrent, found, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
if !found {
b.Error("torrent not found", testTorrent)
}
// Incomplete comparison as maps make struct not nativly comparable
if foundTorrent.Infohash != testTorrent.Infohash {
b.Error("found torrent mismatch", foundTorrent, testTorrent)
}
}
// Cleanup
b.StopTimer()
panicOnErr(conn.RemoveTorrent(testTorrent))
b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ {
foundTorrent, found, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
if !found {
b.Error("torrent not found", testTorrent)
}
// Incomplete comparison as maps make struct not nativly comparable
if foundTorrent.Infohash != testTorrent.Infohash {
b.Error("found torrent mismatch", foundTorrent, testTorrent)
}
}
// Cleanup
b.StopTimer()
panicOnErr(conn.RemoveTorrent(testTorrent))
b.StartTimer()
}
func BenchmarkFailFindTorrent(b *testing.B) {
b.StopTimer()
conn := createTestConn()
testTorrent := createTestTorrent()
b.StartTimer()
b.StopTimer()
conn := createTestConn()
testTorrent := createTestTorrent()
b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ {
foundTorrent, found, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
if found {
b.Error("torrent found", foundTorrent)
}
}
for bCount := 0; bCount < b.N; bCount++ {
foundTorrent, found, err := conn.FindTorrent(testTorrent.Infohash)
panicOnErr(err)
if found {
b.Error("torrent found", foundTorrent)
}
}
}
func BenchmarkSuccessfulClientWhitelisted(b *testing.B) {
b.StopTimer()
conn := createTestConn()
testPeerID := "-lt0D30-"
panicOnErr(conn.WhitelistClient(testPeerID))
b.StartTimer()
b.StopTimer()
conn := createTestConn()
testPeerID := "-lt0D30-"
panicOnErr(conn.WhitelistClient(testPeerID))
b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ {
found, err := conn.ClientWhitelisted(testPeerID)
panicOnErr(err)
if !found {
b.Error("peerID not found", testPeerID)
}
}
// Cleanup
b.StopTimer()
panicOnErr(conn.UnWhitelistClient(testPeerID))
b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ {
found, err := conn.ClientWhitelisted(testPeerID)
panicOnErr(err)
if !found {
b.Error("peerID not found", testPeerID)
}
}
// Cleanup
b.StopTimer()
panicOnErr(conn.UnWhitelistClient(testPeerID))
b.StartTimer()
}
func BenchmarkFailClientWhitelisted(b *testing.B) {
b.StopTimer()
conn := createTestConn()
testPeerID2 := "TIX0192"
b.StartTimer()
b.StopTimer()
conn := createTestConn()
testPeerID2 := "TIX0192"
b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ {
found, err := conn.ClientWhitelisted(testPeerID2)
panicOnErr(err)
if found {
b.Error("peerID found", testPeerID2)
}
}
for bCount := 0; bCount < b.N; bCount++ {
found, err := conn.ClientWhitelisted(testPeerID2)
panicOnErr(err)
if found {
b.Error("peerID found", testPeerID2)
}
}
}
func BenchmarkRecordSnatch(b *testing.B) {
b.StopTimer()
conn := createTestConn()
testTorrent := createTestTorrent()
testUser := createTestUser()
panicOnErr(conn.AddTorrent(testTorrent))
panicOnErr(conn.AddUser(testUser))
b.StartTimer()
b.StopTimer()
conn := createTestConn()
testTorrent := createTestTorrent()
testUser := createTestUser()
panicOnErr(conn.AddTorrent(testTorrent))
panicOnErr(conn.AddUser(testUser))
b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ {
panicOnErr(conn.RecordSnatch(testUser, testTorrent))
}
// Cleanup
b.StopTimer()
panicOnErr(conn.RemoveTorrent(testTorrent))
panicOnErr(conn.RemoveUser(testUser))
b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ {
panicOnErr(conn.RecordSnatch(testUser, testTorrent))
}
// Cleanup
b.StopTimer()
panicOnErr(conn.RemoveTorrent(testTorrent))
panicOnErr(conn.RemoveUser(testUser))
b.StartTimer()
}
func BenchmarkMarkActive(b *testing.B) {
b.StopTimer()
conn := createTestConn()
testTorrent := createTestTorrent()
testTorrent.Active = false
panicOnErr(conn.AddTorrent(testTorrent))
b.StartTimer()
b.StopTimer()
conn := createTestConn()
testTorrent := createTestTorrent()
testTorrent.Active = false
panicOnErr(conn.AddTorrent(testTorrent))
b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ {
panicOnErr(conn.MarkActive(testTorrent))
}
// Cleanup
b.StopTimer()
panicOnErr(conn.RemoveTorrent(testTorrent))
b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ {
panicOnErr(conn.MarkActive(testTorrent))
}
// Cleanup
b.StopTimer()
panicOnErr(conn.RemoveTorrent(testTorrent))
b.StartTimer()
}
func BenchmarkAddSeeder(b *testing.B) {
b.StopTimer()
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
b.StartTimer()
b.StopTimer()
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ {
b.StopTimer()
testSeeder := createTestPeer(createTestUserID(), testTorrent.ID)
b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ {
b.StopTimer()
testSeeder := createTestPeer(createTestUserID(), testTorrent.ID)
b.StartTimer()
panicOnErr(conn.AddSeeder(testTorrent, testSeeder))
}
// Cleanup
b.StopTimer()
panicOnErr(conn.RemoveTorrent(testTorrent))
b.StartTimer()
panicOnErr(conn.AddSeeder(testTorrent, testSeeder))
}
// Cleanup
b.StopTimer()
panicOnErr(conn.RemoveTorrent(testTorrent))
b.StartTimer()
}
func BenchmarkRemoveSeeder(b *testing.B) {
b.StopTimer()
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
testSeeder := createTestPeer(createTestUserID(), testTorrent.ID)
b.StartTimer()
b.StopTimer()
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
testSeeder := createTestPeer(createTestUserID(), testTorrent.ID)
b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ {
b.StopTimer()
conn.AddSeeder(testTorrent, testSeeder)
b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ {
b.StopTimer()
conn.AddSeeder(testTorrent, testSeeder)
b.StartTimer()
panicOnErr(conn.RemoveSeeder(testTorrent, testSeeder))
}
// Cleanup
b.StopTimer()
panicOnErr(conn.RemoveTorrent(testTorrent))
b.StartTimer()
panicOnErr(conn.RemoveSeeder(testTorrent, testSeeder))
}
// Cleanup
b.StopTimer()
panicOnErr(conn.RemoveTorrent(testTorrent))
b.StartTimer()
}
func BenchmarkSetSeeder(b *testing.B) {
b.StopTimer()
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
testSeeder := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddSeeder(testTorrent, testSeeder))
r := rand.New(rand.NewSource(time.Now().UnixNano()))
b.StartTimer()
b.StopTimer()
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
testSeeder := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddSeeder(testTorrent, testSeeder))
r := rand.New(rand.NewSource(time.Now().UnixNano()))
b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ {
b.StopTimer()
testSeeder.Uploaded += uint64(r.Int63())
b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ {
b.StopTimer()
testSeeder.Uploaded += uint64(r.Int63())
b.StartTimer()
conn.SetSeeder(testTorrent, testSeeder)
}
// Cleanup
b.StopTimer()
panicOnErr(conn.RemoveTorrent(testTorrent))
b.StartTimer()
conn.SetSeeder(testTorrent, testSeeder)
}
// Cleanup
b.StopTimer()
panicOnErr(conn.RemoveTorrent(testTorrent))
b.StartTimer()
}
func BenchmarkIncrementSlots(b *testing.B) {
b.StopTimer()
conn := createTestConn()
testUser := createTestUser()
panicOnErr(conn.AddUser(testUser))
b.StartTimer()
b.StopTimer()
conn := createTestConn()
testUser := createTestUser()
panicOnErr(conn.AddUser(testUser))
b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ {
panicOnErr(conn.IncrementSlots(testUser))
}
// Cleanup
b.StopTimer()
panicOnErr(conn.RemoveUser(testUser))
b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ {
panicOnErr(conn.IncrementSlots(testUser))
}
// Cleanup
b.StopTimer()
panicOnErr(conn.RemoveUser(testUser))
b.StartTimer()
}
func BenchmarkLeecherFinished(b *testing.B) {
b.StopTimer()
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
b.StartTimer()
b.StopTimer()
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ {
b.StopTimer()
testLeecher := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddLeecher(testTorrent, testLeecher))
testLeecher.Left = 0
b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ {
b.StopTimer()
testLeecher := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddLeecher(testTorrent, testLeecher))
testLeecher.Left = 0
b.StartTimer()
panicOnErr(conn.LeecherFinished(testTorrent, testLeecher))
}
// Cleanup
b.StopTimer()
panicOnErr(conn.RemoveTorrent(testTorrent))
b.StartTimer()
panicOnErr(conn.LeecherFinished(testTorrent, testLeecher))
}
// Cleanup
b.StopTimer()
panicOnErr(conn.RemoveTorrent(testTorrent))
b.StartTimer()
}
// This is a comparision to the Leecher finished function
func BenchmarkRemoveLeecherAddSeeder(b *testing.B) {
b.StopTimer()
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
b.StartTimer()
b.StopTimer()
conn := createTestConn()
testTorrent := createTestTorrent()
panicOnErr(conn.AddTorrent(testTorrent))
b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ {
b.StopTimer()
testLeecher := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddLeecher(testTorrent, testLeecher))
testLeecher.Left = 0
b.StartTimer()
for bCount := 0; bCount < b.N; bCount++ {
b.StopTimer()
testLeecher := createTestPeer(createTestUserID(), testTorrent.ID)
panicOnErr(conn.AddLeecher(testTorrent, testLeecher))
testLeecher.Left = 0
b.StartTimer()
panicOnErr(conn.RemoveLeecher(testTorrent, testLeecher))
panicOnErr(conn.AddSeeder(testTorrent, testLeecher))
}
// Cleanup
b.StopTimer()
conn.RemoveTorrent(testTorrent)
b.StartTimer()
panicOnErr(conn.RemoveLeecher(testTorrent, testLeecher))
panicOnErr(conn.AddSeeder(testTorrent, testLeecher))
}
// Cleanup
b.StopTimer()
conn.RemoveTorrent(testTorrent)
b.StartTimer()
}

View file

@ -5,180 +5,180 @@
package redis
import (
"crypto/rand"
"fmt"
"io"
"os"
"strconv"
"testing"
"crypto/rand"
"fmt"
"io"
"os"
"strconv"
"testing"
"github.com/garyburd/redigo/redis"
"github.com/garyburd/redigo/redis"
"github.com/pushrax/chihaya/config"
"github.com/pushrax/chihaya/storage"
"github.com/pushrax/chihaya/config"
"github.com/pushrax/chihaya/storage"
)
var (
testTorrentIDChannel chan uint64
testUserIDChannel chan uint64
testPeerIDChannel chan int
testTorrentIDChannel chan uint64
testUserIDChannel chan uint64
testPeerIDChannel chan int
)
func init() {
testTorrentIDChannel = make(chan uint64, 100)
testUserIDChannel = make(chan uint64, 100)
testPeerIDChannel = make(chan int, 100)
// Sync access to ID counter with buffered global channels
go func() {
for i := 0; ; i++ {
testTorrentIDChannel <- uint64(i)
}
}()
go func() {
for i := 0; ; i++ {
testUserIDChannel <- uint64(i)
}
}()
go func() {
for i := 0; ; i++ {
testPeerIDChannel <- i
}
}()
testTorrentIDChannel = make(chan uint64, 100)
testUserIDChannel = make(chan uint64, 100)
testPeerIDChannel = make(chan int, 100)
// Sync access to ID counter with buffered global channels
go func() {
for i := 0; ; i++ {
testTorrentIDChannel <- uint64(i)
}
}()
go func() {
for i := 0; ; i++ {
testUserIDChannel <- uint64(i)
}
}()
go func() {
for i := 0; ; i++ {
testPeerIDChannel <- i
}
}()
}
func createTestTorrentID() uint64 {
return <-testTorrentIDChannel
return <-testTorrentIDChannel
}
func createTestUserID() uint64 {
return <-testUserIDChannel
return <-testUserIDChannel
}
func createTestPeerID() string {
return "-testPeerID-" + strconv.Itoa(<-testPeerIDChannel)
return "-testPeerID-" + strconv.Itoa(<-testPeerIDChannel)
}
func createTestInfohash() string {
uuid := make([]byte, 40)
n, err := io.ReadFull(rand.Reader, uuid)
if n != len(uuid) || err != nil {
panic(err)
}
return string(uuid)
uuid := make([]byte, 40)
n, err := io.ReadFull(rand.Reader, uuid)
if n != len(uuid) || err != nil {
panic(err)
}
return string(uuid)
}
func createTestPasskey() string {
uuid := make([]byte, 40)
n, err := io.ReadFull(rand.Reader, uuid)
if n != len(uuid) || err != nil {
panic(err)
}
return string(uuid)
uuid := make([]byte, 40)
n, err := io.ReadFull(rand.Reader, uuid)
if n != len(uuid) || err != nil {
panic(err)
}
return string(uuid)
}
func panicOnErr(err error) {
if err != nil {
fmt.Println(err)
panic(err)
}
if err != nil {
fmt.Println(err)
panic(err)
}
}
func createTestRedisConn() *Conn {
testConfig, err := config.Open(os.Getenv("TESTCONFIGPATH"))
conf := &testConfig.Cache
panicOnErr(err)
testConfig, err := config.Open(os.Getenv("TESTCONFIGPATH"))
conf := &testConfig.Cache
panicOnErr(err)
testPool := &Pool{
conf: conf,
pool: redis.Pool{
MaxIdle: conf.MaxIdleConns,
IdleTimeout: conf.IdleTimeout.Duration,
Dial: makeDialFunc(conf),
TestOnBorrow: testOnBorrow,
},
}
testPool := &Pool{
conf: conf,
pool: redis.Pool{
MaxIdle: conf.MaxIdleConns,
IdleTimeout: conf.IdleTimeout.Duration,
Dial: makeDialFunc(conf),
TestOnBorrow: testOnBorrow,
},
}
newConn := &Conn{
conf: testPool.conf,
done: false,
Conn: testPool.pool.Get(),
}
panicOnErr(err)
newConn := &Conn{
conf: testPool.conf,
done: false,
Conn: testPool.pool.Get(),
}
panicOnErr(err)
// Test connection before returning
_, err = newConn.Do("PING")
panicOnErr(err)
return newConn
// Test connection before returning
_, err = newConn.Do("PING")
panicOnErr(err)
return newConn
}
func createTestUser() *storage.User {
return &storage.User{ID: createTestUserID(), Passkey: createTestPasskey(),
UpMultiplier: 1.01, DownMultiplier: 1.0, Slots: 4, SlotsUsed: 2, Snatches: 7}
return &storage.User{ID: createTestUserID(), Passkey: createTestPasskey(),
UpMultiplier: 1.01, DownMultiplier: 1.0, Slots: 4, SlotsUsed: 2, Snatches: 7}
}
func createTestPeer(userID uint64, torrentID uint64) *storage.Peer {
return &storage.Peer{ID: createTestPeerID(), UserID: userID, TorrentID: torrentID,
IP: "127.0.0.1", Port: 6889, Uploaded: 1024, Downloaded: 3000, Left: 4200, LastAnnounce: 11}
return &storage.Peer{ID: createTestPeerID(), UserID: userID, TorrentID: torrentID,
IP: "127.0.0.1", Port: 6889, Uploaded: 1024, Downloaded: 3000, Left: 4200, LastAnnounce: 11}
}
func createTestPeers(torrentID uint64, num int) map[string]storage.Peer {
testPeers := make(map[string]storage.Peer)
for i := 0; i < num; i++ {
tempPeer := createTestPeer(createTestUserID(), torrentID)
testPeers[storage.PeerMapKey(tempPeer)] = *tempPeer
}
return testPeers
testPeers := make(map[string]storage.Peer)
for i := 0; i < num; i++ {
tempPeer := createTestPeer(createTestUserID(), torrentID)
testPeers[storage.PeerMapKey(tempPeer)] = *tempPeer
}
return testPeers
}
func createTestTorrent() *storage.Torrent {
torrentInfohash := createTestInfohash()
torrentID := createTestTorrentID()
torrentInfohash := createTestInfohash()
torrentID := createTestTorrentID()
testSeeders := createTestPeers(torrentID, 4)
testLeechers := createTestPeers(torrentID, 2)
testSeeders := createTestPeers(torrentID, 4)
testLeechers := createTestPeers(torrentID, 2)
testTorrent := storage.Torrent{ID: torrentID, Infohash: torrentInfohash, Active: true,
Seeders: testSeeders, Leechers: testLeechers, Snatches: 11, UpMultiplier: 1.0, DownMultiplier: 1.0, LastAction: 0}
return &testTorrent
testTorrent := storage.Torrent{ID: torrentID, Infohash: torrentInfohash, Active: true,
Seeders: testSeeders, Leechers: testLeechers, Snatches: 11, UpMultiplier: 1.0, DownMultiplier: 1.0, LastAction: 0}
return &testTorrent
}
func TestValidPeers(t *testing.T) {
testConn := createTestRedisConn()
testTorrentID := createTestTorrentID()
testPeers := createTestPeers(testTorrentID, 3)
testConn := createTestRedisConn()
testTorrentID := createTestTorrentID()
testPeers := createTestPeers(testTorrentID, 3)
panicOnErr(testConn.addPeers(testPeers, "test:"))
peerMap, err := testConn.getPeers(testTorrentID, "test:")
panicOnErr(err)
if len(peerMap) != len(testPeers) {
t.Error("Num Peers not equal ", len(peerMap), len(testPeers))
}
panicOnErr(testConn.removePeers(testTorrentID, testPeers, "test:"))
panicOnErr(testConn.addPeers(testPeers, "test:"))
peerMap, err := testConn.getPeers(testTorrentID, "test:")
panicOnErr(err)
if len(peerMap) != len(testPeers) {
t.Error("Num Peers not equal ", len(peerMap), len(testPeers))
}
panicOnErr(testConn.removePeers(testTorrentID, testPeers, "test:"))
}
func TestInvalidPeers(t *testing.T) {
testConn := createTestRedisConn()
testTorrentID := createTestTorrentID()
testPeers := createTestPeers(testTorrentID, 3)
tempPeer := createTestPeer(createTestUserID(), testTorrentID)
testPeers[storage.PeerMapKey(tempPeer)] = *tempPeer
testConn := createTestRedisConn()
testTorrentID := createTestTorrentID()
testPeers := createTestPeers(testTorrentID, 3)
tempPeer := createTestPeer(createTestUserID(), testTorrentID)
testPeers[storage.PeerMapKey(tempPeer)] = *tempPeer
panicOnErr(testConn.addPeers(testPeers, "test:"))
// Imitate a peer being removed during get
hashKey := testConn.conf.Prefix + getPeerHashKey(tempPeer)
_, err := testConn.Do("DEL", hashKey)
panicOnErr(err)
panicOnErr(testConn.addPeers(testPeers, "test:"))
// Imitate a peer being removed during get
hashKey := testConn.conf.Prefix + getPeerHashKey(tempPeer)
_, err := testConn.Do("DEL", hashKey)
panicOnErr(err)
peerMap, err := testConn.getPeers(testTorrentID, "test:")
panicOnErr(err)
// Expect 1 less peer due to delete
if len(peerMap) != len(testPeers)-1 {
t.Error("Num Peers not equal ", len(peerMap), len(testPeers)-1)
}
panicOnErr(testConn.removePeers(testTorrentID, testPeers, "test:"))
if len(testPeers) != 0 {
t.Errorf("All peers not removed, %d peers remain!", len(testPeers))
}
peerMap, err := testConn.getPeers(testTorrentID, "test:")
panicOnErr(err)
// Expect 1 less peer due to delete
if len(peerMap) != len(testPeers)-1 {
t.Error("Num Peers not equal ", len(peerMap), len(testPeers)-1)
}
panicOnErr(testConn.removePeers(testTorrentID, testPeers, "test:"))
if len(testPeers) != 0 {
t.Errorf("All peers not removed, %d peers remain!", len(testPeers))
}
}