From 6549f49e26873cb658e829bfd3d18b82b7bca7df Mon Sep 17 00:00:00 2001 From: Jimmy Zelinskie Date: Sun, 24 Nov 2013 00:49:20 -0500 Subject: [PATCH] go fmt [ci skip] --- config/config.go | 98 +-- server/announce.go | 592 +++++++-------- server/scrape.go | 114 +-- server/server.go | 196 ++--- server/stats.go | 38 +- server/stats_test.go | 66 +- storage/tracker/redis/conn_test.go | 862 +++++++++++----------- storage/tracker/redis/redis.go | 836 ++++++++++----------- storage/tracker/redis/redis_bench_test.go | 430 +++++------ storage/tracker/redis/redis_test.go | 238 +++--- 10 files changed, 1735 insertions(+), 1735 deletions(-) diff --git a/config/config.go b/config/config.go index dde644b..537d6f8 100644 --- a/config/config.go +++ b/config/config.go @@ -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 } diff --git a/server/announce.go b/server/announce.go index 42970b4..31927d9 100644 --- a/server/announce.go +++ b/server/announce.go @@ -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++ + } } diff --git a/server/scrape.go b/server/scrape.go index abdb376..3e34efb 100644 --- a/server/scrape.go +++ b/server/scrape.go @@ -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") } diff --git a/server/server.go b/server/server.go index b41cba2..9d00d81 100644 --- a/server/server.go +++ b/server/server.go @@ -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 } diff --git a/server/stats.go b/server/stats.go index df94099..6e0a074 100644 --- a/server/stats.go +++ b/server/stats.go @@ -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) + } } diff --git a/server/stats_test.go b/server/stats_test.go index d0fb0eb..0c1816f 100644 --- a/server/stats_test.go +++ b/server/stats_test.go @@ -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")) + } } diff --git a/storage/tracker/redis/conn_test.go b/storage/tracker/redis/conn_test.go index 2893c6f..11f4439 100644 --- a/storage/tracker/redis/conn_test.go +++ b/storage/tracker/redis/conn_test.go @@ -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)) } diff --git a/storage/tracker/redis/redis.go b/storage/tracker/redis/redis.go index d96500f..a445247 100644 --- a/storage/tracker/redis/redis.go +++ b/storage/tracker/redis/redis.go @@ -24,92 +24,92 @@ package redis import ( - "errors" - "strconv" - "time" + "errors" + "strconv" + "time" - "github.com/garyburd/redigo/redis" + "github.com/garyburd/redigo/redis" - "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" ) var ( - ErrCreateUser = errors.New("redis: Incorrect reply length for user") - ErrCreateTorrent = errors.New("redis: Incorrect reply length for torrent") - ErrCreatePeer = errors.New("redis: Incorrect reply length for peer") - ErrMarkActive = errors.New("redis: Torrent doesn't exist") + ErrCreateUser = errors.New("redis: Incorrect reply length for user") + ErrCreateTorrent = errors.New("redis: Incorrect reply length for torrent") + ErrCreatePeer = errors.New("redis: Incorrect reply length for peer") + ErrMarkActive = errors.New("redis: Torrent doesn't exist") - SeedersPrefix = "seeders:" - LeechersPrefix = "leechers:" - TorrentPrefix = "torrent:" - UserPrefix = "user:" - PeerPrefix = "peer:" + SeedersPrefix = "seeders:" + LeechersPrefix = "leechers:" + TorrentPrefix = "torrent:" + UserPrefix = "user:" + PeerPrefix = "peer:" ) type driver struct{} // New creates and returns a tracker.Pool. func (d *driver) New(conf *config.DataStore) tracker.Pool { - return &Pool{ - conf: conf, - pool: redis.Pool{ - MaxIdle: conf.MaxIdleConns, - IdleTimeout: conf.IdleTimeout.Duration, - Dial: makeDialFunc(conf), - TestOnBorrow: testOnBorrow, - }, - } + return &Pool{ + conf: conf, + pool: redis.Pool{ + MaxIdle: conf.MaxIdleConns, + IdleTimeout: conf.IdleTimeout.Duration, + Dial: makeDialFunc(conf), + TestOnBorrow: testOnBorrow, + }, + } } // makeDialFunc configures and returns a new redis.Dial struct using the specified configuration. func makeDialFunc(conf *config.DataStore) func() (redis.Conn, error) { - return func() (conn redis.Conn, err error) { - conn, err = redis.Dial(conf.Network, conf.Host+":"+conf.Port) - if err != nil { - return nil, err - } - return conn, nil - } + return func() (conn redis.Conn, err error) { + conn, err = redis.Dial(conf.Network, conf.Host+":"+conf.Port) + if err != nil { + return nil, err + } + return conn, nil + } } // testOnBorrow pings the Redis instance func testOnBorrow(c redis.Conn, t time.Time) error { - _, err := c.Do("PING") - return err + _, err := c.Do("PING") + return err } type Pool struct { - conf *config.DataStore - pool redis.Pool + conf *config.DataStore + pool redis.Pool } func (p *Pool) Close() error { - return p.pool.Close() + return p.pool.Close() } func (p *Pool) Get() (tracker.Conn, error) { - newConn := &Conn{ - conf: p.conf, - done: false, - Conn: p.pool.Get(), - } - return newConn, nil + newConn := &Conn{ + conf: p.conf, + done: false, + Conn: p.pool.Get(), + } + return newConn, nil } type Conn struct { - conf *config.DataStore - done bool - redis.Conn + conf *config.DataStore + done bool + redis.Conn } func (conn *Conn) close() { - if conn.done { - panic("redis: connection closed twice") - } - conn.done = true - conn.Conn.Close() + if conn.done { + panic("redis: connection closed twice") + } + conn.done = true + conn.Conn.Close() } // createUser takes a string slice of length 14 and returns a pointer to a new @@ -120,33 +120,33 @@ func (conn *Conn) close() { // If the field value string cannot be converted to the correct type, // createUser will return a nil user and the conversion error. func createUser(userVals []string) (*storage.User, error) { - if len(userVals) != 14 { - return nil, ErrCreateUser - } - var user storage.User - var err error - for index, userString := range userVals { - switch userString { - case "id": - user.ID, err = strconv.ParseUint(userVals[index+1], 10, 64) - case "passkey": - user.Passkey = userVals[index+1] - case "up_multiplier": - user.UpMultiplier, err = strconv.ParseFloat(userVals[index+1], 64) - case "down_multiplier": - user.DownMultiplier, err = strconv.ParseFloat(userVals[index+1], 64) - case "slots": - user.Slots, err = strconv.ParseInt(userVals[index+1], 10, 64) - case "slots_used": - user.SlotsUsed, err = strconv.ParseInt(userVals[index+1], 10, 64) - case "snatches": - user.Snatches, err = strconv.ParseUint(userVals[index+1], 10, 64) - } - if err != nil { - return nil, err - } - } - return &user, nil + if len(userVals) != 14 { + return nil, ErrCreateUser + } + var user storage.User + var err error + for index, userString := range userVals { + switch userString { + case "id": + user.ID, err = strconv.ParseUint(userVals[index+1], 10, 64) + case "passkey": + user.Passkey = userVals[index+1] + case "up_multiplier": + user.UpMultiplier, err = strconv.ParseFloat(userVals[index+1], 64) + case "down_multiplier": + user.DownMultiplier, err = strconv.ParseFloat(userVals[index+1], 64) + case "slots": + user.Slots, err = strconv.ParseInt(userVals[index+1], 10, 64) + case "slots_used": + user.SlotsUsed, err = strconv.ParseInt(userVals[index+1], 10, 64) + case "snatches": + user.Snatches, err = strconv.ParseUint(userVals[index+1], 10, 64) + } + if err != nil { + return nil, err + } + } + return &user, nil } // createTorrent takes a string slice of length 14 and returns a pointer to a new storage.Torrent @@ -159,59 +159,59 @@ func createUser(userVals []string) (*storage.User, error) { // createTorrent will return a nil user and the conversion error. // After converting the torrent fields, the seeders and leechers are populated by redis.getPeers func (conn *Conn) createTorrent(torrentVals []string) (*storage.Torrent, error) { - if len(torrentVals) != 14 { - return nil, ErrCreateTorrent - } - var torrent storage.Torrent - var err error - for index, torrentString := range torrentVals { - switch torrentString { - case "id": - torrent.ID, err = strconv.ParseUint(torrentVals[index+1], 10, 64) - case "infohash": - torrent.Infohash = torrentVals[index+1] - case "active": - torrent.Active, err = strconv.ParseBool(torrentVals[index+1]) - case "snatches": - torrent.Snatches, err = strconv.ParseUint(torrentVals[index+1], 10, 32) - case "up_multiplier": - torrent.UpMultiplier, err = strconv.ParseFloat(torrentVals[index+1], 64) - case "down_multiplier": - torrent.DownMultiplier, err = strconv.ParseFloat(torrentVals[index+1], 64) - case "last_action": - torrent.LastAction, err = strconv.ParseInt(torrentVals[index+1], 10, 64) - } - if err != nil { - return nil, err - } - } - torrent.Seeders, err = conn.getPeers(torrent.ID, SeedersPrefix) - if err != nil { - return nil, err - } - torrent.Leechers, err = conn.getPeers(torrent.ID, LeechersPrefix) - if err != nil { - return nil, err - } - return &torrent, nil + if len(torrentVals) != 14 { + return nil, ErrCreateTorrent + } + var torrent storage.Torrent + var err error + for index, torrentString := range torrentVals { + switch torrentString { + case "id": + torrent.ID, err = strconv.ParseUint(torrentVals[index+1], 10, 64) + case "infohash": + torrent.Infohash = torrentVals[index+1] + case "active": + torrent.Active, err = strconv.ParseBool(torrentVals[index+1]) + case "snatches": + torrent.Snatches, err = strconv.ParseUint(torrentVals[index+1], 10, 32) + case "up_multiplier": + torrent.UpMultiplier, err = strconv.ParseFloat(torrentVals[index+1], 64) + case "down_multiplier": + torrent.DownMultiplier, err = strconv.ParseFloat(torrentVals[index+1], 64) + case "last_action": + torrent.LastAction, err = strconv.ParseInt(torrentVals[index+1], 10, 64) + } + if err != nil { + return nil, err + } + } + torrent.Seeders, err = conn.getPeers(torrent.ID, SeedersPrefix) + if err != nil { + return nil, err + } + torrent.Leechers, err = conn.getPeers(torrent.ID, LeechersPrefix) + if err != nil { + return nil, err + } + return &torrent, nil } // setPeer writes or overwrites peer information, stored as a Redis hash. // The hash fields names are the same as the JSON tags on the storage.Peer struct. func (conn *Conn) setPeer(peer *storage.Peer) error { - hashKey := conn.conf.Prefix + getPeerHashKey(peer) - _, err := conn.Do("HMSET", hashKey, - "id", peer.ID, - "user_id", peer.UserID, - "torrent_id", peer.TorrentID, - "ip", peer.IP, - "port", peer.Port, - "uploaded", peer.Uploaded, - "downloaded", peer.Downloaded, - "left", peer.Left, - "last_announce", peer.LastAnnounce) + hashKey := conn.conf.Prefix + getPeerHashKey(peer) + _, err := conn.Do("HMSET", hashKey, + "id", peer.ID, + "user_id", peer.UserID, + "torrent_id", peer.TorrentID, + "ip", peer.IP, + "port", peer.Port, + "uploaded", peer.Uploaded, + "downloaded", peer.Downloaded, + "left", peer.Left, + "last_announce", peer.LastAnnounce) - return err + return err } // removePeer removes the given peer from the specified peer set (seeder or leecher), @@ -219,14 +219,14 @@ func (conn *Conn) setPeer(peer *storage.Peer) error { // This function calls multiple redis commands, it's not internally atomic. // This function will not return an error if the peer to remove doesn't exist. func (conn *Conn) removePeer(peer *storage.Peer, peerTypePrefix string) error { - setKey := conn.conf.Prefix + getPeerSetKey(peerTypePrefix, peer) - _, err := conn.Do("SREM", setKey, getPeerHashKey(peer)) - if err != nil { - return err - } - hashKey := conn.conf.Prefix + getPeerHashKey(peer) - _, err = conn.Do("DEL", hashKey) - return nil + setKey := conn.conf.Prefix + getPeerSetKey(peerTypePrefix, peer) + _, err := conn.Do("SREM", setKey, getPeerHashKey(peer)) + if err != nil { + return err + } + hashKey := conn.conf.Prefix + getPeerHashKey(peer) + _, err = conn.Do("DEL", hashKey) + return nil } // removePeers removes all peers from specified peer set (seeders or leechers), @@ -235,20 +235,20 @@ func (conn *Conn) removePeer(peer *storage.Peer, peerTypePrefix string) error { // This function will only delete the peer set if all the individual peer deletions were successful // This function calls multiple redis commands, it's not internally atomic. func (conn *Conn) removePeers(torrentID uint64, peers map[string]storage.Peer, peerTypePrefix string) error { - for _, peer := range peers { - hashKey := conn.conf.Prefix + getPeerHashKey(&peer) - _, err := conn.Do("DEL", hashKey) - if err != nil { - return err - } - delete(peers, storage.PeerMapKey(&peer)) - } - setKey := conn.conf.Prefix + peerTypePrefix + strconv.FormatUint(torrentID, 36) - _, err := conn.Do("DEL", setKey) - if err != nil { - return err - } - return nil + for _, peer := range peers { + hashKey := conn.conf.Prefix + getPeerHashKey(&peer) + _, err := conn.Do("DEL", hashKey) + if err != nil { + return err + } + delete(peers, storage.PeerMapKey(&peer)) + } + setKey := conn.conf.Prefix + peerTypePrefix + strconv.FormatUint(torrentID, 36) + _, err := conn.Do("DEL", setKey) + if err != nil { + return err + } + return nil } // getPeerHashKey returns a string with the peer.ID, encoded peer.UserID, and encoded peer.TorrentID, @@ -256,28 +256,28 @@ func (conn *Conn) removePeers(torrentID uint64, peers map[string]storage.Peer, p // This key corresponds to a Redis hash type with fields containing a peer's data. // The peer hashkey relies on the combination of peerID, userID, and torrentID being unique. func getPeerHashKey(peer *storage.Peer) string { - return peer.ID + ":" + strconv.FormatUint(peer.UserID, 36) + ":" + strconv.FormatUint(peer.TorrentID, 36) + return peer.ID + ":" + strconv.FormatUint(peer.UserID, 36) + ":" + strconv.FormatUint(peer.TorrentID, 36) } // getPeerSetKey returns a string that is the peer's encoded torrentID appended to the typePrefix // This key corresponds to a torrent's pool of leechers or seeders func getPeerSetKey(typePrefix string, peer *storage.Peer) string { - return typePrefix + strconv.FormatUint(peer.TorrentID, 36) + return typePrefix + strconv.FormatUint(peer.TorrentID, 36) } // addPeers adds each peer's key to the specified peer set and saves the peer's information. // This function will not return an error if the peer already exists in the set. // This function calls multiple redis commands, it's not internally atomic. func (conn *Conn) addPeers(peers map[string]storage.Peer, peerTypePrefix string) error { - for _, peer := range peers { - setKey := conn.conf.Prefix + getPeerSetKey(peerTypePrefix, &peer) - _, err := conn.Do("SADD", setKey, getPeerHashKey(&peer)) - if err != nil { - return err - } - conn.setPeer(&peer) - } - return nil + for _, peer := range peers { + setKey := conn.conf.Prefix + getPeerSetKey(peerTypePrefix, &peer) + _, err := conn.Do("SADD", setKey, getPeerHashKey(&peer)) + if err != nil { + return err + } + conn.setPeer(&peer) + } + return nil } // createPeer takes a slice of length 9 and returns a pointer to a new storage.Peer or an error. @@ -287,205 +287,205 @@ func (conn *Conn) addPeers(peers map[string]storage.Peer, peerTypePrefix string) // If the field value string cannot be converted to the correct type, // the function will return a nil peer and the conversion error. func createPeer(peerVals []string) (*storage.Peer, error) { - if len(peerVals) != 18 { - return nil, ErrCreatePeer - } - var peer storage.Peer - var err error - for index, peerString := range peerVals { - switch peerString { - case "id": - peer.ID = peerVals[index+1] - case "user_id": - peer.UserID, err = strconv.ParseUint(peerVals[index+1], 10, 64) - case "torrent_id": - peer.TorrentID, err = strconv.ParseUint(peerVals[index+1], 10, 64) - case "ip": - peer.IP = peerVals[index+1] - case "port": - peer.Port, err = strconv.ParseUint(peerVals[index+1], 10, 64) - case "uploaded": - peer.Uploaded, err = strconv.ParseUint(peerVals[index+1], 10, 64) - case "downloaded": - peer.Downloaded, err = strconv.ParseUint(peerVals[index+1], 10, 64) - case "left": - peer.Left, err = strconv.ParseUint(peerVals[index+1], 10, 64) - case "last_announce": - peer.LastAnnounce, err = strconv.ParseInt(peerVals[index+1], 10, 64) - } - if err != nil { - return nil, err - } - } - return &peer, nil + if len(peerVals) != 18 { + return nil, ErrCreatePeer + } + var peer storage.Peer + var err error + for index, peerString := range peerVals { + switch peerString { + case "id": + peer.ID = peerVals[index+1] + case "user_id": + peer.UserID, err = strconv.ParseUint(peerVals[index+1], 10, 64) + case "torrent_id": + peer.TorrentID, err = strconv.ParseUint(peerVals[index+1], 10, 64) + case "ip": + peer.IP = peerVals[index+1] + case "port": + peer.Port, err = strconv.ParseUint(peerVals[index+1], 10, 64) + case "uploaded": + peer.Uploaded, err = strconv.ParseUint(peerVals[index+1], 10, 64) + case "downloaded": + peer.Downloaded, err = strconv.ParseUint(peerVals[index+1], 10, 64) + case "left": + peer.Left, err = strconv.ParseUint(peerVals[index+1], 10, 64) + case "last_announce": + peer.LastAnnounce, err = strconv.ParseInt(peerVals[index+1], 10, 64) + } + if err != nil { + return nil, err + } + } + return &peer, nil } // getPeers returns a map of peers from a specified torrent's peer set(seeders or leechers). // This is a multiple action command, it's not internally atomic. func (conn *Conn) getPeers(torrentID uint64, peerTypePrefix string) (peers map[string]storage.Peer, err error) { - peers = make(map[string]storage.Peer) - setKey := conn.conf.Prefix + peerTypePrefix + strconv.FormatUint(torrentID, 36) - peerStrings, err := redis.Strings(conn.Do("SMEMBERS", setKey)) - if err != nil { - return nil, err - } - // Keys map to peer objects stored in hashes - for _, peerHashKey := range peerStrings { - hashKey := conn.conf.Prefix + peerHashKey - peerVals, err := redis.Strings(conn.Do("HGETALL", hashKey)) - if err != nil { - return nil, err - } - if len(peerVals) == 0 { - continue - } - peer, err := createPeer(peerVals) - if err != nil { - return nil, err - } - peers[storage.PeerMapKey(peer)] = *peer - } - return + peers = make(map[string]storage.Peer) + setKey := conn.conf.Prefix + peerTypePrefix + strconv.FormatUint(torrentID, 36) + peerStrings, err := redis.Strings(conn.Do("SMEMBERS", setKey)) + if err != nil { + return nil, err + } + // Keys map to peer objects stored in hashes + for _, peerHashKey := range peerStrings { + hashKey := conn.conf.Prefix + peerHashKey + peerVals, err := redis.Strings(conn.Do("HGETALL", hashKey)) + if err != nil { + return nil, err + } + if len(peerVals) == 0 { + continue + } + peer, err := createPeer(peerVals) + if err != nil { + return nil, err + } + peers[storage.PeerMapKey(peer)] = *peer + } + return } // AddTorrent writes/overwrites torrent information and saves peers from both peer sets. // The hash fields names are the same as the JSON tags on the storage.Torrent struct. // This is a multiple action command, it's not internally atomic. func (conn *Conn) AddTorrent(t *storage.Torrent) error { - hashkey := conn.conf.Prefix + TorrentPrefix + t.Infohash - _, err := conn.Do("HMSET", hashkey, - "id", t.ID, - "infohash", t.Infohash, - "active", t.Active, - "snatches", t.Snatches, - "up_multiplier", t.UpMultiplier, - "down_multiplier", t.DownMultiplier, - "last_action", t.LastAction) - if err != nil { - return err - } + hashkey := conn.conf.Prefix + TorrentPrefix + t.Infohash + _, err := conn.Do("HMSET", hashkey, + "id", t.ID, + "infohash", t.Infohash, + "active", t.Active, + "snatches", t.Snatches, + "up_multiplier", t.UpMultiplier, + "down_multiplier", t.DownMultiplier, + "last_action", t.LastAction) + if err != nil { + return err + } - err = conn.addPeers(t.Seeders, SeedersPrefix) - if err != nil { - return err - } - err = conn.addPeers(t.Leechers, LeechersPrefix) - if err != nil { - return err - } - return nil + err = conn.addPeers(t.Seeders, SeedersPrefix) + if err != nil { + return err + } + err = conn.addPeers(t.Leechers, LeechersPrefix) + if err != nil { + return err + } + return nil } // RemoveTorrent deletes the torrent's Redis hash and then deletes all peers. // This function will not return an error if the torrent has already been removed. // This is a multiple action command, it's not internally atomic. func (conn *Conn) RemoveTorrent(t *storage.Torrent) error { - hashkey := conn.conf.Prefix + TorrentPrefix + t.Infohash - _, err := conn.Do("DEL", hashkey) - if err != nil { - return err - } - // Remove seeders and leechers as well - err = conn.removePeers(t.ID, t.Seeders, SeedersPrefix) - if err != nil { - return err - } - err = conn.removePeers(t.ID, t.Leechers, LeechersPrefix) - if err != nil { - return err - } - return nil + hashkey := conn.conf.Prefix + TorrentPrefix + t.Infohash + _, err := conn.Do("DEL", hashkey) + if err != nil { + return err + } + // Remove seeders and leechers as well + err = conn.removePeers(t.ID, t.Seeders, SeedersPrefix) + if err != nil { + return err + } + err = conn.removePeers(t.ID, t.Leechers, LeechersPrefix) + if err != nil { + return err + } + return nil } // AddUser writes/overwrites user information to a Redis hash. // The hash fields names are the same as the JSON tags on the storage.user struct. func (conn *Conn) AddUser(u *storage.User) error { - hashkey := conn.conf.Prefix + UserPrefix + u.Passkey - _, err := conn.Do("HMSET", hashkey, - "id", u.ID, - "passkey", u.Passkey, - "up_multiplier", u.UpMultiplier, - "down_multiplier", u.DownMultiplier, - "slots", u.Slots, - "slots_used", u.SlotsUsed, - "snatches", u.Snatches) - if err != nil { - return err - } - return nil + hashkey := conn.conf.Prefix + UserPrefix + u.Passkey + _, err := conn.Do("HMSET", hashkey, + "id", u.ID, + "passkey", u.Passkey, + "up_multiplier", u.UpMultiplier, + "down_multiplier", u.DownMultiplier, + "slots", u.Slots, + "slots_used", u.SlotsUsed, + "snatches", u.Snatches) + if err != nil { + return err + } + return nil } // RemoveUser removes the user's hash from Redis. // This function does not return an error if the user doesn't exist. func (conn *Conn) RemoveUser(u *storage.User) error { - hashkey := conn.conf.Prefix + UserPrefix + u.Passkey - _, err := conn.Do("DEL", hashkey) - if err != nil { - return err - } - return nil + hashkey := conn.conf.Prefix + UserPrefix + u.Passkey + _, err := conn.Do("DEL", hashkey) + if err != nil { + return err + } + return nil } // FindUser returns a pointer to a new user struct and true if the user exists, // or nil and false if the user doesn't exist. // This function does not return an error if the torrent doesn't exist. func (conn *Conn) FindUser(passkey string) (*storage.User, bool, error) { - hashkey := conn.conf.Prefix + UserPrefix + passkey - // Consider using HGETALL instead of HVALS here for robustness - userStrings, err := redis.Strings(conn.Do("HGETALL", hashkey)) - if err != nil { - return nil, false, err - } else if len(userStrings) == 0 { - return nil, false, nil - } - foundUser, err := createUser(userStrings) - if err != nil { - return nil, false, err - } - return foundUser, true, nil + hashkey := conn.conf.Prefix + UserPrefix + passkey + // Consider using HGETALL instead of HVALS here for robustness + userStrings, err := redis.Strings(conn.Do("HGETALL", hashkey)) + if err != nil { + return nil, false, err + } else if len(userStrings) == 0 { + return nil, false, nil + } + foundUser, err := createUser(userStrings) + if err != nil { + return nil, false, err + } + return foundUser, true, nil } // FindTorrent returns a pointer to a new torrent struct and true if the torrent exists, // or nil and false if the torrent doesn't exist. // This is a multiple action command, it's not internally atomic. func (conn *Conn) FindTorrent(infohash string) (*storage.Torrent, bool, error) { - hashkey := conn.conf.Prefix + TorrentPrefix + infohash - torrentStrings, err := redis.Strings(conn.Do("HGETALL", hashkey)) - if err != nil { - return nil, false, err - } else if len(torrentStrings) == 0 { - return nil, false, nil - } + hashkey := conn.conf.Prefix + TorrentPrefix + infohash + torrentStrings, err := redis.Strings(conn.Do("HGETALL", hashkey)) + if err != nil { + return nil, false, err + } else if len(torrentStrings) == 0 { + return nil, false, nil + } - foundTorrent, err := conn.createTorrent(torrentStrings) - if err != nil { - return nil, false, err - } - return foundTorrent, true, nil + foundTorrent, err := conn.createTorrent(torrentStrings) + if err != nil { + return nil, false, err + } + return foundTorrent, true, nil } // ClientWhitelisted returns true if the ClientID exists in the Client set. // This function does not parse the client ID from the peer ID. // The clientID must match exactly to a member of the set. func (conn *Conn) ClientWhitelisted(peerID string) (exists bool, err error) { - key := conn.conf.Prefix + "whitelist" - return redis.Bool(conn.Do("SISMEMBER", key, peerID)) + key := conn.conf.Prefix + "whitelist" + return redis.Bool(conn.Do("SISMEMBER", key, peerID)) } // WhitelistClient adds a client ID to the client whitelist set. // This function does not return an error if the client ID is already in the set. func (conn *Conn) WhitelistClient(peerID string) error { - key := conn.conf.Prefix + "whitelist" - _, err := conn.Do("SADD", key, peerID) - return err + key := conn.conf.Prefix + "whitelist" + _, err := conn.Do("SADD", key, peerID) + return err } // UnWhitelistClient removes a client ID from the client whitelist set // This function does not return an error if the client ID is not in the set. func (conn *Conn) UnWhitelistClient(peerID string) error { - key := conn.conf.Prefix + "whitelist" - _, err := conn.Do("SREM", key, peerID) - return err + key := conn.conf.Prefix + "whitelist" + _, err := conn.Do("SREM", key, peerID) + return err } // RecordSnatch increments the snatch counter on the torrent and user by one. @@ -493,59 +493,59 @@ func (conn *Conn) UnWhitelistClient(peerID string) error { // This is a multiple action command, it's not internally atomic. func (conn *Conn) RecordSnatch(user *storage.User, torrent *storage.Torrent) error { - torrentKey := conn.conf.Prefix + TorrentPrefix + torrent.Infohash - snatchCount, err := redis.Int(conn.Do("HINCRBY", torrentKey, "snatches", 1)) - if err != nil { - return err - } - torrent.Snatches = uint64(snatchCount) + torrentKey := conn.conf.Prefix + TorrentPrefix + torrent.Infohash + snatchCount, err := redis.Int(conn.Do("HINCRBY", torrentKey, "snatches", 1)) + if err != nil { + return err + } + torrent.Snatches = uint64(snatchCount) - userKey := conn.conf.Prefix + UserPrefix + user.Passkey - snatchCount, err = redis.Int(conn.Do("HINCRBY", userKey, "snatches", 1)) - if err != nil { - return err - } - user.Snatches = uint64(snatchCount) - return nil + userKey := conn.conf.Prefix + UserPrefix + user.Passkey + snatchCount, err = redis.Int(conn.Do("HINCRBY", userKey, "snatches", 1)) + if err != nil { + return err + } + user.Snatches = uint64(snatchCount) + return nil } // MarkActive sets the active field of the torrent to true. // This modifies the argument as well as the hash field in Redis. // This function will return ErrMarkActive if the torrent does not exist. func (conn *Conn) MarkActive(torrent *storage.Torrent) error { - hashkey := conn.conf.Prefix + TorrentPrefix + torrent.Infohash - activeExists, err := redis.Int(conn.Do("HSET", hashkey, "active", true)) - if err != nil { - return err - } - torrent.Active = true - // HSET returns 1 if hash didn't exist before - if activeExists == 1 { - return ErrMarkActive - } - return nil + hashkey := conn.conf.Prefix + TorrentPrefix + torrent.Infohash + activeExists, err := redis.Int(conn.Do("HSET", hashkey, "active", true)) + if err != nil { + return err + } + torrent.Active = true + // HSET returns 1 if hash didn't exist before + if activeExists == 1 { + return ErrMarkActive + } + return nil } // MarkInactive sets the active field of the torrent to false. // This modifies the argument as well as the hash field in Redis. // This function will return ErrMarkActive if the torrent does not exist. func (conn *Conn) MarkInactive(torrent *storage.Torrent) error { - hashkey := conn.conf.Prefix + TorrentPrefix + torrent.Infohash - activeExists, err := redis.Int(conn.Do("HSET", hashkey, "active", false)) - if err != nil { - return err - } - torrent.Active = false - // HSET returns 1 if hash didn't exist before - if activeExists == 1 { - // Clean-up incomplete torrent - _, err = conn.Do("DEL", hashkey) - if err != nil { - return err - } - return ErrMarkActive - } - return nil + hashkey := conn.conf.Prefix + TorrentPrefix + torrent.Infohash + activeExists, err := redis.Int(conn.Do("HSET", hashkey, "active", false)) + if err != nil { + return err + } + torrent.Active = false + // HSET returns 1 if hash didn't exist before + if activeExists == 1 { + // Clean-up incomplete torrent + _, err = conn.Do("DEL", hashkey) + if err != nil { + return err + } + return ErrMarkActive + } + return nil } // AddLeecher adds a new peer to a torrent's leecher set. @@ -553,20 +553,20 @@ func (conn *Conn) MarkInactive(torrent *storage.Torrent) error { // This function does not return an error if the leecher already exists. // This is a multiple action command, it's not internally atomic. func (conn *Conn) AddLeecher(torrent *storage.Torrent, peer *storage.Peer) error { - setKey := conn.conf.Prefix + LeechersPrefix + strconv.FormatUint(torrent.ID, 36) - _, err := conn.Do("SADD", setKey, getPeerHashKey(peer)) - if err != nil { - return err - } - err = conn.setPeer(peer) - if err != nil { - return err - } - if torrent.Leechers == nil { - torrent.Leechers = make(map[string]storage.Peer) - } - torrent.Leechers[storage.PeerMapKey(peer)] = *peer - return nil + setKey := conn.conf.Prefix + LeechersPrefix + strconv.FormatUint(torrent.ID, 36) + _, err := conn.Do("SADD", setKey, getPeerHashKey(peer)) + if err != nil { + return err + } + err = conn.setPeer(peer) + if err != nil { + return err + } + if torrent.Leechers == nil { + torrent.Leechers = make(map[string]storage.Peer) + } + torrent.Leechers[storage.PeerMapKey(peer)] = *peer + return nil } // SetLeecher updates a torrent's leecher. @@ -574,43 +574,43 @@ func (conn *Conn) AddLeecher(torrent *storage.Torrent, peer *storage.Peer) error // Setting assumes that the peer is already a leecher, and only needs to be updated. // This function does not return an error if the leecher does not exist or is not in the torrent's leecher set. func (conn *Conn) SetLeecher(t *storage.Torrent, p *storage.Peer) error { - err := conn.setPeer(p) - if err != nil { - return err - } - t.Leechers[storage.PeerMapKey(p)] = *p - return nil + err := conn.setPeer(p) + if err != nil { + return err + } + t.Leechers[storage.PeerMapKey(p)] = *p + return nil } // RemoveLeecher removes the given peer from a torrent's leecher set. // This modifies the torrent argument, as well as the torrent's set and peer's hash in Redis. // This function does not return an error if the peer doesn't exist, or is not in the set. func (conn *Conn) RemoveLeecher(t *storage.Torrent, p *storage.Peer) error { - err := conn.removePeer(p, LeechersPrefix) - if err != nil { - return err - } - delete(t.Leechers, storage.PeerMapKey(p)) - return nil + err := conn.removePeer(p, LeechersPrefix) + if err != nil { + return err + } + delete(t.Leechers, storage.PeerMapKey(p)) + return nil } // LeecherFinished moves a peer's hashkey from a torrent's leecher set to the seeder set and updates the peer. // This modifies the torrent argument, as well as the torrent's set and peer's hash in Redis. // This function does not return an error if the peer doesn't exist or is not in the torrent's leecher set. func (conn *Conn) LeecherFinished(torrent *storage.Torrent, peer *storage.Peer) error { - torrentIdKey := strconv.FormatUint(torrent.ID, 36) - seederSetKey := conn.conf.Prefix + SeedersPrefix + torrentIdKey - leecherSetKey := conn.conf.Prefix + LeechersPrefix + torrentIdKey + torrentIdKey := strconv.FormatUint(torrent.ID, 36) + seederSetKey := conn.conf.Prefix + SeedersPrefix + torrentIdKey + leecherSetKey := conn.conf.Prefix + LeechersPrefix + torrentIdKey - _, err := conn.Do("SMOVE", leecherSetKey, seederSetKey, getPeerHashKey(peer)) - if err != nil { - return err - } - torrent.Seeders[storage.PeerMapKey(peer)] = *peer - delete(torrent.Leechers, storage.PeerMapKey(peer)) + _, err := conn.Do("SMOVE", leecherSetKey, seederSetKey, getPeerHashKey(peer)) + if err != nil { + return err + } + torrent.Seeders[storage.PeerMapKey(peer)] = *peer + delete(torrent.Leechers, storage.PeerMapKey(peer)) - err = conn.setPeer(peer) - return err + err = conn.setPeer(peer) + return err } // AddSeeder adds a new peer to a torrent's seeder set. @@ -618,20 +618,20 @@ func (conn *Conn) LeecherFinished(torrent *storage.Torrent, peer *storage.Peer) // This function does not return an error if the seeder already exists. // This is a multiple action command, it's not internally atomic. func (conn *Conn) AddSeeder(torrent *storage.Torrent, peer *storage.Peer) error { - setKey := conn.conf.Prefix + SeedersPrefix + strconv.FormatUint(torrent.ID, 36) - _, err := conn.Do("SADD", setKey, getPeerHashKey(peer)) - if err != nil { - return err - } - err = conn.setPeer(peer) - if err != nil { - return err - } - if torrent.Seeders == nil { - torrent.Seeders = make(map[string]storage.Peer) - } - torrent.Seeders[storage.PeerMapKey(peer)] = *peer - return nil + setKey := conn.conf.Prefix + SeedersPrefix + strconv.FormatUint(torrent.ID, 36) + _, err := conn.Do("SADD", setKey, getPeerHashKey(peer)) + if err != nil { + return err + } + err = conn.setPeer(peer) + if err != nil { + return err + } + if torrent.Seeders == nil { + torrent.Seeders = make(map[string]storage.Peer) + } + torrent.Seeders[storage.PeerMapKey(peer)] = *peer + return nil } // SetSeeder updates a torrent's seeder. @@ -639,51 +639,51 @@ func (conn *Conn) AddSeeder(torrent *storage.Torrent, peer *storage.Peer) error // Setting assumes that the peer is already a seeder, and only needs to be updated. // This function does not return an error if the seeder does not exist or is not in the torrent's seeder set. func (conn *Conn) SetSeeder(t *storage.Torrent, p *storage.Peer) error { - err := conn.setPeer(p) - if err != nil { - return err - } - t.Seeders[storage.PeerMapKey(p)] = *p - return nil + err := conn.setPeer(p) + if err != nil { + return err + } + t.Seeders[storage.PeerMapKey(p)] = *p + return nil } // RemoveSeeder removes the given peer from a torrent's seeder set. // This modifies the torrent argument, as well as the torrent's set and peer's hash in Redis. // This function does not return an error if the peer doesn't exist, or is not in the set. func (conn *Conn) RemoveSeeder(t *storage.Torrent, p *storage.Peer) error { - err := conn.removePeer(p, SeedersPrefix) - if err != nil { - return err - } - delete(t.Seeders, storage.PeerMapKey(p)) - return nil + err := conn.removePeer(p, SeedersPrefix) + if err != nil { + return err + } + delete(t.Seeders, storage.PeerMapKey(p)) + return nil } // IncrementSlots increment a user's Slots by one. // This function modifies the argument as well as the hash field in Redis. func (conn *Conn) IncrementSlots(u *storage.User) error { - hashkey := conn.conf.Prefix + UserPrefix + u.Passkey - slotCount, err := redis.Int(conn.Do("HINCRBY", hashkey, "slots", 1)) - if err != nil { - return err - } - u.Slots = int64(slotCount) - return nil + hashkey := conn.conf.Prefix + UserPrefix + u.Passkey + slotCount, err := redis.Int(conn.Do("HINCRBY", hashkey, "slots", 1)) + if err != nil { + return err + } + u.Slots = int64(slotCount) + return nil } // IncrementSlots increment a user's Slots by one. // This function modifies the argument as well as the hash field in Redis. func (conn *Conn) DecrementSlots(u *storage.User) error { - hashkey := conn.conf.Prefix + UserPrefix + u.Passkey - slotCount, err := redis.Int(conn.Do("HINCRBY", hashkey, "slots", -1)) - if err != nil { - return err - } - u.Slots = int64(slotCount) - return nil + hashkey := conn.conf.Prefix + UserPrefix + u.Passkey + slotCount, err := redis.Int(conn.Do("HINCRBY", hashkey, "slots", -1)) + if err != nil { + return err + } + u.Slots = int64(slotCount) + return nil } // init registers the redis driver func init() { - tracker.Register("redis", &driver{}) + tracker.Register("redis", &driver{}) } diff --git a/storage/tracker/redis/redis_bench_test.go b/storage/tracker/redis/redis_bench_test.go index 530b466..e8634c6 100644 --- a/storage/tracker/redis/redis_bench_test.go +++ b/storage/tracker/redis/redis_bench_test.go @@ -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() } diff --git a/storage/tracker/redis/redis_test.go b/storage/tracker/redis/redis_test.go index 9ae7d2b..828f86a 100644 --- a/storage/tracker/redis/redis_test.go +++ b/storage/tracker/redis/redis_test.go @@ -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)) + } }