remove all private tracker logic

There are no consumers of any of this logic nor is it complete. We're
better off without it in the meantime until we have a use case and a
more cohesive model for expressing it.
This commit is contained in:
Jimmy Zelinskie 2016-01-04 18:26:23 -05:00
parent f70be94911
commit 9862a57b73
21 changed files with 24 additions and 516 deletions

View file

@ -45,26 +45,19 @@ Limits the number of outstanding requests. Set to `0` to disable.
Then listen address for the UDP server. If only a port is specified, the tracker will listen on all interfaces. If left empty, the tracker will not run a UDP endpoint. Then listen address for the UDP server. If only a port is specified, the tracker will listen on all interfaces. If left empty, the tracker will not run a UDP endpoint.
##### `privateEnabled`
type: bool
default: true
Whether this is a public or private tracker.
##### `createOnAnnounce` ##### `createOnAnnounce`
type: bool type: bool
default: true default: true
Whether to register new torrents with the tracker when any client announces (`true`), or to return an error if the torrent doesn't exist (`false`). This should be set to `false` for private trackers in most cases. Whether to register new torrents with the tracker when any client announces (`true`), or to return an error if the torrent doesn't exist (`false`).
##### `purgeInactiveTorrents` ##### `purgeInactiveTorrents`
type: bool type: bool
default: true default: true
If torrents should be forgotten when there are no active peers. This should be set to `false` for private trackers. If torrents should be forgotten when there are no active peers.
##### `announce` ##### `announce`
@ -129,13 +122,6 @@ Enables the peer ID whitelist.
List of peer ID prefixes to allow if `client_whitelist_enabled` is set to true. List of peer ID prefixes to allow if `client_whitelist_enabled` is set to true.
##### `freeleechEnabled`
type: bool
default: false
For private trackers only, whether download stats should be counted or ignored for users.
##### `torrentMapShards` ##### `torrentMapShards`
type: integer type: integer

View file

@ -14,7 +14,6 @@ RUN godep restore
# Add source # Add source
ADD *.go /go/src/github.com/chihaya/chihaya/ ADD *.go /go/src/github.com/chihaya/chihaya/
ADD api /go/src/github.com/chihaya/chihaya/api ADD api /go/src/github.com/chihaya/chihaya/api
ADD backend /go/src/github.com/chihaya/chihaya/backend
ADD cmd /go/src/github.com/chihaya/chihaya/cmd ADD cmd /go/src/github.com/chihaya/chihaya/cmd
ADD config /go/src/github.com/chihaya/chihaya/config ADD config /go/src/github.com/chihaya/chihaya/config
ADD http /go/src/github.com/chihaya/chihaya/http ADD http /go/src/github.com/chihaya/chihaya/http

View file

@ -84,11 +84,6 @@ func (s *Server) Serve() {
func newRouter(s *Server) *httprouter.Router { func newRouter(s *Server) *httprouter.Router {
r := httprouter.New() r := httprouter.New()
if s.config.PrivateEnabled {
r.PUT("/users/:passkey", makeHandler(s.putUser))
r.DELETE("/users/:passkey", makeHandler(s.delUser))
}
if s.config.ClientWhitelistEnabled { if s.config.ClientWhitelistEnabled {
r.GET("/clients/:clientID", makeHandler(s.getClient)) r.GET("/clients/:clientID", makeHandler(s.getClient))
r.PUT("/clients/:clientID", makeHandler(s.putClient)) r.PUT("/clients/:clientID", makeHandler(s.putClient))

View file

@ -32,13 +32,6 @@ func handleError(err error) (int, error) {
} }
func (s *Server) check(w http.ResponseWriter, r *http.Request, p httprouter.Params) (int, error) { func (s *Server) check(w http.ResponseWriter, r *http.Request, p httprouter.Params) (int, error) {
// Attempt to ping the backend if private tracker is enabled.
if s.config.PrivateEnabled {
if err := s.tracker.Backend.Ping(); err != nil {
return handleError(err)
}
}
_, err := w.Write([]byte("STILL-ALIVE")) _, err := w.Write([]byte("STILL-ALIVE"))
return handleError(err) return handleError(err)
} }
@ -109,35 +102,6 @@ func (s *Server) delTorrent(w http.ResponseWriter, r *http.Request, p httprouter
return http.StatusOK, nil return http.StatusOK, nil
} }
func (s *Server) getUser(w http.ResponseWriter, r *http.Request, p httprouter.Params) (int, error) {
user, err := s.tracker.FindUser(p.ByName("passkey"))
if err == models.ErrUserDNE {
return http.StatusNotFound, err
} else if err != nil {
return http.StatusInternalServerError, err
}
w.Header().Set("Content-Type", jsonContentType)
e := json.NewEncoder(w)
return handleError(e.Encode(user))
}
func (s *Server) putUser(w http.ResponseWriter, r *http.Request, p httprouter.Params) (int, error) {
var user models.User
err := json.NewDecoder(r.Body).Decode(&user)
if err != nil {
return http.StatusBadRequest, err
}
s.tracker.PutUser(&user)
return http.StatusOK, nil
}
func (s *Server) delUser(w http.ResponseWriter, r *http.Request, p httprouter.Params) (int, error) {
s.tracker.DeleteUser(p.ByName("passkey"))
return http.StatusOK, nil
}
func (s *Server) getClient(w http.ResponseWriter, r *http.Request, p httprouter.Params) (int, error) { func (s *Server) getClient(w http.ResponseWriter, r *http.Request, p httprouter.Params) (int, error) {
if err := s.tracker.ClientApproved(p.ByName("clientID")); err != nil { if err := s.tracker.ClientApproved(p.ByName("clientID")); err != nil {
return http.StatusNotFound, err return http.StatusNotFound, err

View file

@ -1,35 +0,0 @@
# Implementing a Driver
The [`backend`] package is meant to provide announce deltas to a slower and more consistent database, such as the one powering a torrent-indexing website. Implementing a backend driver is heavily inspired by the standard library's [`database/sql`] package: simply create a package that implements the [`backend.Driver`] and [`backend.Conn`] interfaces and calls [`backend.Register`] in it's [`init()`]. Please note that [`backend.Conn`] must be thread-safe. A great place to start is to read the [`no-op`] driver which comes out-of-the-box with Chihaya and is meant to be used for public trackers.
[`init()`]: http://golang.org/ref/spec#Program_execution
[`database/sql`]: http://godoc.org/database/sql
[`backend`]: http://godoc.org/github.com/chihaya/chihaya/backend
[`backend.Register`]: http://godoc.org/github.com/chihaya/chihaya/backend#Register
[`backend.Driver`]: http://godoc.org/github.com/chihaya/chihaya/backend#Driver
[`backend.Conn`]: http://godoc.org/github.com/chihaya/chihaya/backend#Conn
[`no-op`]: http://godoc.org/github.com/chihaya/chihaya/backend/noop
## Creating a binary with your own driver
Chihaya is designed to be extended. If you require more than the drivers provided out-of-the-box, you are free to create your own and then produce your own custom Chihaya binary. To create this binary, simply create your own main package, import your custom drivers, then call [`chihaya.Boot`] from main.
[`chihaya.Boot`]: http://godoc.org/github.com/chihaya/chihaya
### Example
```go
package main
import (
"github.com/chihaya/chihaya"
// Import any of your own drivers.
_ "github.com/yourusername/chihaya-custom-backend"
)
func main() {
// Start Chihaya normally.
chihaya.Boot()
}
```

View file

@ -1,75 +0,0 @@
// Copyright 2015 The Chihaya Authors. All rights reserved.
// Use of this source code is governed by the BSD 2-Clause license,
// which can be found in the LICENSE file.
// Package backend provides a generic interface for manipulating a
// BitTorrent tracker's consistent backend data store (usually for
// a web application).
package backend
import (
"fmt"
"github.com/chihaya/chihaya/config"
"github.com/chihaya/chihaya/tracker/models"
)
var drivers = make(map[string]Driver)
// Driver represents an interface to a long-running connection with a
// consistent data store.
type Driver interface {
New(*config.DriverConfig) (Conn, error)
}
// Register makes a database driver available by the provided name.
// If Register is called twice with the same name or if driver is nil,
// it panics.
func Register(name string, driver Driver) {
if driver == nil {
panic("backend: Register driver is nil")
}
if _, dup := drivers[name]; dup {
panic("backend: Register called twice for driver " + name)
}
drivers[name] = driver
}
// Open creates a connection specified by a configuration.
func Open(cfg *config.DriverConfig) (Conn, error) {
driver, ok := drivers[cfg.Name]
if !ok {
return nil, fmt.Errorf(
"backend: unknown driver %q (forgotten import?)",
cfg.Name,
)
}
return driver.New(cfg)
}
// Conn represents a connection to the data store.
type Conn interface {
// Close terminates connections to the database(s) and gracefully shuts
// down the driver
Close() error
// Ping just checks to see if the database is still alive. This is typically
// used for health checks.
Ping() error
// RecordAnnounce is called once per announce, and is passed the delta in
// statistics for the client peer since its last announce.
RecordAnnounce(delta *models.AnnounceDelta) error
// LoadTorrents fetches and returns the specified torrents.
LoadTorrents(ids []uint64) ([]*models.Torrent, error)
// LoadAllTorrents fetches and returns all torrents.
LoadAllTorrents() ([]*models.Torrent, error)
// LoadUsers fetches and returns the specified users.
LoadUsers(ids []uint64) ([]*models.User, error)
// LoadAllUsers fetches and returns all users.
LoadAllUsers() ([]*models.User, error)
}

View file

@ -1,64 +0,0 @@
// Copyright 2015 The Chihaya Authors. All rights reserved.
// Use of this source code is governed by the BSD 2-Clause license,
// which can be found in the LICENSE file.
// Package noop implements a Chihaya backend storage driver as a no-op. This is
// useful for running Chihaya as a public tracker.
package noop
import (
"github.com/chihaya/chihaya/backend"
"github.com/chihaya/chihaya/config"
"github.com/chihaya/chihaya/tracker/models"
)
type driver struct{}
// NoOp is a backend driver for Chihaya that does nothing. This is used by
// public trackers.
type NoOp struct{}
// New returns a new Chihaya backend driver that does nothing.
func (d *driver) New(cfg *config.DriverConfig) (backend.Conn, error) {
return &NoOp{}, nil
}
// Close returns nil.
func (n *NoOp) Close() error {
return nil
}
// Ping returns nil.
func (n *NoOp) Ping() error {
return nil
}
// RecordAnnounce returns nil.
func (n *NoOp) RecordAnnounce(delta *models.AnnounceDelta) error {
return nil
}
// LoadTorrents returns (nil, nil).
func (n *NoOp) LoadTorrents(ids []uint64) ([]*models.Torrent, error) {
return nil, nil
}
// LoadAllTorrents returns (nil, nil).
func (n *NoOp) LoadAllTorrents() ([]*models.Torrent, error) {
return nil, nil
}
// LoadUsers returns (nil, nil).
func (n *NoOp) LoadUsers(ids []uint64) ([]*models.User, error) {
return nil, nil
}
// LoadAllUsers returns (nil, nil).
func (n *NoOp) LoadAllUsers() ([]*models.User, error) {
return nil, nil
}
// Init registers the noop driver as a backend for Chihaya.
func init() {
backend.Register("noop", &driver{})
}

View file

@ -23,9 +23,6 @@ import (
"github.com/chihaya/chihaya/stats" "github.com/chihaya/chihaya/stats"
"github.com/chihaya/chihaya/tracker" "github.com/chihaya/chihaya/tracker"
"github.com/chihaya/chihaya/udp" "github.com/chihaya/chihaya/udp"
// See the README for how to import custom drivers.
_ "github.com/chihaya/chihaya/backend/noop"
) )
var ( var (

View file

@ -7,16 +7,11 @@ package config
import ( import (
"encoding/json" "encoding/json"
"errors"
"io" "io"
"os" "os"
"time" "time"
) )
// ErrMissingRequiredParam is used by drivers to indicate that an entry required
// to be within the DriverConfig.Params map is not present.
var ErrMissingRequiredParam = errors.New("A parameter that was required by a driver is not present")
// Duration wraps a time.Duration and adds JSON marshalling. // Duration wraps a time.Duration and adds JSON marshalling.
type Duration struct{ time.Duration } type Duration struct{ time.Duration }
@ -33,13 +28,6 @@ func (d *Duration) UnmarshalJSON(b []byte) error {
return err return err
} }
// DriverConfig is the configuration used to connect to a tracker.Driver or
// a backend.Driver.
type DriverConfig struct {
Name string `json:"driver"`
Params map[string]string `json:"params,omitempty"`
}
// SubnetConfig is the configuration used to specify if local peers should be // SubnetConfig is the configuration used to specify if local peers should be
// given a preference when responding to an announce. // given a preference when responding to an announce.
type SubnetConfig struct { type SubnetConfig struct {
@ -75,8 +63,6 @@ type WhitelistConfig struct {
// TrackerConfig is the configuration for tracker functionality. // TrackerConfig is the configuration for tracker functionality.
type TrackerConfig struct { type TrackerConfig struct {
CreateOnAnnounce bool `json:"createOnAnnounce"` CreateOnAnnounce bool `json:"createOnAnnounce"`
PrivateEnabled bool `json:"privateEnabled"`
FreeleechEnabled bool `json:"freeleechEnabled"`
PurgeInactiveTorrents bool `json:"purgeInactiveTorrents"` PurgeInactiveTorrents bool `json:"purgeInactiveTorrents"`
Announce Duration `json:"announce"` Announce Duration `json:"announce"`
MinAnnounce Duration `json:"minAnnounce"` MinAnnounce Duration `json:"minAnnounce"`
@ -119,7 +105,6 @@ type Config struct {
APIConfig APIConfig
HTTPConfig HTTPConfig
UDPConfig UDPConfig
DriverConfig
StatsConfig StatsConfig
} }
@ -127,8 +112,6 @@ type Config struct {
var DefaultConfig = Config{ var DefaultConfig = Config{
TrackerConfig: TrackerConfig{ TrackerConfig: TrackerConfig{
CreateOnAnnounce: true, CreateOnAnnounce: true,
PrivateEnabled: false,
FreeleechEnabled: false,
PurgeInactiveTorrents: true, PurgeInactiveTorrents: true,
Announce: Duration{30 * time.Minute}, Announce: Duration{30 * time.Minute},
MinAnnounce: Duration{15 * time.Minute}, MinAnnounce: Duration{15 * time.Minute},
@ -166,10 +149,6 @@ var DefaultConfig = Config{
ListenAddr: "localhost:6882", ListenAddr: "localhost:6882",
}, },
DriverConfig: DriverConfig{
Name: "noop",
},
StatsConfig: StatsConfig{ StatsConfig: StatsConfig{
BufferSize: 0, BufferSize: 0,
IncludeMem: true, IncludeMem: true,

View file

@ -1,7 +1,5 @@
{ {
"createOnAnnounce": true, "createOnAnnounce": true,
"privateEnabled": false,
"freeleechEnabled": false,
"purgeInactiveTorrents": true, "purgeInactiveTorrents": true,
"announce": "30m", "announce": "30m",
"minAnnounce": "15m", "minAnnounce": "15m",

View file

@ -120,46 +120,6 @@ func TestStalePeerPurging(t *testing.T) {
} }
} }
func TestPrivateAnnounce(t *testing.T) {
cfg := config.DefaultConfig
cfg.PrivateEnabled = true
tkr, err := tracker.New(&cfg)
if err != nil {
t.Fatal(err)
}
loadPrivateTestData(tkr)
srv, err := createServer(tkr, &cfg)
if err != nil {
t.Fatal(err)
}
defer srv.Close()
baseURL := srv.URL
peer1 := makePeerParams("-TR2820-peer1", false)
peer2 := makePeerParams("-TR2820-peer2", false)
peer3 := makePeerParams("-TR2820-peer3", true)
expected := makeResponse(0, 1, peer1)
srv.URL = baseURL + "/users/vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv1"
checkAnnounce(peer1, expected, srv, t)
expected = makeResponse(0, 2, peer1)
srv.URL = baseURL + "/users/vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv2"
checkAnnounce(peer2, expected, srv, t)
expected = makeResponse(1, 2, peer1, peer2)
srv.URL = baseURL + "/users/vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv3"
checkAnnounce(peer3, expected, srv, t)
expected = makeResponse(1, 2, peer2, peer3)
srv.URL = baseURL + "/users/vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv1"
checkAnnounce(peer1, expected, srv, t)
}
func TestPreferredSubnet(t *testing.T) { func TestPreferredSubnet(t *testing.T) {
cfg := config.DefaultConfig cfg := config.DefaultConfig
cfg.PreferredSubnet = true cfg.PreferredSubnet = true
@ -337,29 +297,3 @@ func checkAnnounce(p params, expected interface{}, srv *httptest.Server, t *test
} }
return true return true
} }
func loadPrivateTestData(tkr *tracker.Tracker) {
users := []string{
"vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv1",
"vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv2",
"vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv3",
}
for i, passkey := range users {
tkr.PutUser(&models.User{
ID: uint64(i + 1),
Passkey: passkey,
})
}
tkr.PutClient("TR2820")
torrent := &models.Torrent{
ID: 1,
Infohash: infoHash,
Seeders: models.NewPeerMap(true, tkr.Config),
Leechers: models.NewPeerMap(false, tkr.Config),
}
tkr.PutTorrent(torrent)
}

View file

@ -73,13 +73,8 @@ func makeHandler(handler ResponseHandler) httprouter.Handle {
func newRouter(s *Server) *httprouter.Router { func newRouter(s *Server) *httprouter.Router {
r := httprouter.New() r := httprouter.New()
if s.config.PrivateEnabled { r.GET("/announce", makeHandler(s.serveAnnounce))
r.GET("/users/:passkey/announce", makeHandler(s.serveAnnounce)) r.GET("/scrape", makeHandler(s.serveScrape))
r.GET("/users/:passkey/scrape", makeHandler(s.serveScrape))
} else {
r.GET("/announce", makeHandler(s.serveAnnounce))
r.GET("/scrape", makeHandler(s.serveScrape))
}
return r return r
} }

View file

@ -15,8 +15,6 @@ import (
"github.com/chihaya/chihaya/config" "github.com/chihaya/chihaya/config"
"github.com/chihaya/chihaya/stats" "github.com/chihaya/chihaya/stats"
"github.com/chihaya/chihaya/tracker" "github.com/chihaya/chihaya/tracker"
_ "github.com/chihaya/chihaya/backend/noop"
) )
type params map[string]string type params map[string]string

View file

@ -76,7 +76,6 @@ func (s *Server) newAnnounce(r *http.Request, p httprouter.Params) (*models.Anno
Infohash: infohash, Infohash: infohash,
Left: left, Left: left,
NumWant: numWant, NumWant: numWant,
Passkey: p.ByName("passkey"),
PeerID: peerID, PeerID: peerID,
Uploaded: uploaded, Uploaded: uploaded,
}, nil }, nil
@ -98,9 +97,7 @@ func (s *Server) newScrape(r *http.Request, p httprouter.Params) (*models.Scrape
} }
return &models.Scrape{ return &models.Scrape{
Config: s.config, Config: s.config,
Passkey: p.ByName("passkey"),
Infohashes: q.Infohashes, Infohashes: q.Infohashes,
}, nil }, nil
} }

View file

@ -18,13 +18,6 @@ func (tkr *Tracker) HandleAnnounce(ann *models.Announce, w Writer) (err error) {
} }
} }
var user *models.User
if tkr.Config.PrivateEnabled {
if user, err = tkr.FindUser(ann.Passkey); err != nil {
return err
}
}
torrent, err := tkr.FindTorrent(ann.Infohash) torrent, err := tkr.FindTorrent(ann.Infohash)
if err == models.ErrTorrentDNE && tkr.Config.CreateOnAnnounce { if err == models.ErrTorrentDNE && tkr.Config.CreateOnAnnounce {
@ -40,30 +33,19 @@ func (tkr *Tracker) HandleAnnounce(ann *models.Announce, w Writer) (err error) {
return err return err
} }
ann.BuildPeer(user, torrent) ann.BuildPeer(torrent)
var delta *models.AnnounceDelta
if tkr.Config.PrivateEnabled { _, err = tkr.updateSwarm(ann)
delta = newAnnounceDelta(ann, torrent)
}
created, err := tkr.updateSwarm(ann)
if err != nil { if err != nil {
return err return err
} }
snatched, err := tkr.handleEvent(ann) _, err = tkr.handleEvent(ann)
if err != nil { if err != nil {
return err return err
} }
if tkr.Config.PrivateEnabled { if tkr.Config.PurgeInactiveTorrents && torrent.PeerCount() == 0 {
delta.Created = created
delta.Snatched = snatched
if err = tkr.Backend.RecordAnnounce(delta); err != nil {
return err
}
} else if tkr.Config.PurgeInactiveTorrents && torrent.PeerCount() == 0 {
// Rather than deleting the torrent explicitly, let the tracker driver // Rather than deleting the torrent explicitly, let the tracker driver
// ensure there are no race conditions. // ensure there are no race conditions.
tkr.PurgeInactiveTorrent(torrent.Infohash) tkr.PurgeInactiveTorrent(torrent.Infohash)
@ -74,49 +56,6 @@ func (tkr *Tracker) HandleAnnounce(ann *models.Announce, w Writer) (err error) {
return w.WriteAnnounce(newAnnounceResponse(ann)) return w.WriteAnnounce(newAnnounceResponse(ann))
} }
// Builds a partially populated AnnounceDelta, without the Snatched and Created
// fields set.
func newAnnounceDelta(ann *models.Announce, t *models.Torrent) *models.AnnounceDelta {
var oldUp, oldDown, rawDeltaUp, rawDeltaDown uint64
switch {
case t.Seeders.Contains(ann.Peer.Key()):
oldPeer, _ := t.Seeders.LookUp(ann.Peer.Key())
oldUp = oldPeer.Uploaded
oldDown = oldPeer.Downloaded
case t.Leechers.Contains(ann.Peer.Key()):
oldPeer, _ := t.Leechers.LookUp(ann.Peer.Key())
oldUp = oldPeer.Uploaded
oldDown = oldPeer.Downloaded
}
// Restarting a torrent may cause a delta to be negative.
if ann.Peer.Uploaded > oldUp {
rawDeltaUp = ann.Peer.Uploaded - oldUp
}
if ann.Peer.Downloaded > oldDown {
rawDeltaDown = ann.Peer.Downloaded - oldDown
}
uploaded := uint64(float64(rawDeltaUp) * ann.User.UpMultiplier * ann.Torrent.UpMultiplier)
downloaded := uint64(float64(rawDeltaDown) * ann.User.DownMultiplier * ann.Torrent.DownMultiplier)
if ann.Config.FreeleechEnabled {
downloaded = 0
}
return &models.AnnounceDelta{
Peer: ann.Peer,
Torrent: ann.Torrent,
User: ann.User,
Uploaded: uploaded,
RawUploaded: rawDeltaUp,
Downloaded: downloaded,
RawDownloaded: rawDeltaDown,
}
}
// updateSwarm handles the changes to a torrent's swarm given an announce. // updateSwarm handles the changes to a torrent's swarm given an announce.
func (tkr *Tracker) updateSwarm(ann *models.Announce) (created bool, err error) { func (tkr *Tracker) updateSwarm(ann *models.Announce) (created bool, err error) {
var createdv4, createdv6 bool var createdv4, createdv6 bool

View file

@ -24,17 +24,11 @@ var (
// not a leecher or a "stopped" event while not active. // not a leecher or a "stopped" event while not active.
ErrBadRequest = ClientError("bad request") ErrBadRequest = ClientError("bad request")
// ErrUserDNE is returned when a user does not exist.
ErrUserDNE = NotFoundError("user does not exist")
// ErrTorrentDNE is returned when a torrent does not exist. // ErrTorrentDNE is returned when a torrent does not exist.
ErrTorrentDNE = NotFoundError("torrent does not exist") ErrTorrentDNE = NotFoundError("torrent does not exist")
// ErrClientUnapproved is returned when a clientID is not in the whitelist. // ErrClientUnapproved is returned when a clientID is not in the whitelist.
ErrClientUnapproved = ClientError("client is not approved") ErrClientUnapproved = ClientError("client is not approved")
// ErrInvalidPasskey is returned when a passkey is not properly formatted.
ErrInvalidPasskey = ClientError("passkey is invalid")
) )
type ClientError string type ClientError string
@ -89,8 +83,6 @@ type Endpoint struct {
// Peer represents a participant in a BitTorrent swarm. // Peer represents a participant in a BitTorrent swarm.
type Peer struct { type Peer struct {
ID string `json:"id"` ID string `json:"id"`
UserID uint64 `json:"userId"`
TorrentID uint64 `json:"torrentId"`
Uploaded uint64 `json:"uploaded"` Uploaded uint64 `json:"uploaded"`
Downloaded uint64 `json:"downloaded"` Downloaded uint64 `json:"downloaded"`
Left uint64 `json:"left"` Left uint64 `json:"left"`
@ -117,16 +109,12 @@ func (p *Peer) Key() PeerKey {
// Torrent represents a BitTorrent swarm and its metadata. // Torrent represents a BitTorrent swarm and its metadata.
type Torrent struct { type Torrent struct {
ID uint64 `json:"id"` Infohash string `json:"infohash"`
Infohash string `json:"infohash"` Snatches uint64 `json:"snatches"`
LastAction int64 `json:"lastAction"`
Seeders *PeerMap `json:"seeders"` Seeders *PeerMap `json:"seeders"`
Leechers *PeerMap `json:"leechers"` Leechers *PeerMap `json:"leechers"`
Snatches uint64 `json:"snatches"`
UpMultiplier float64 `json:"upMultiplier"`
DownMultiplier float64 `json:"downMultiplier"`
LastAction int64 `json:"lastAction"`
} }
// PeerCount returns the total number of peers connected on this Torrent. // PeerCount returns the total number of peers connected on this Torrent.
@ -134,15 +122,6 @@ func (t *Torrent) PeerCount() int {
return t.Seeders.Len() + t.Leechers.Len() return t.Seeders.Len() + t.Leechers.Len()
} }
// User is a registered user for private trackers.
type User struct {
ID uint64 `json:"id"`
Passkey string `json:"passkey"`
UpMultiplier float64 `json:"upMultiplier"`
DownMultiplier float64 `json:"downMultiplier"`
}
// Announce is an Announce by a Peer. // Announce is an Announce by a Peer.
type Announce struct { type Announce struct {
Config *config.Config `json:"config"` Config *config.Config `json:"config"`
@ -155,12 +134,10 @@ type Announce struct {
Infohash string `json:"infohash"` Infohash string `json:"infohash"`
Left uint64 `json:"left"` Left uint64 `json:"left"`
NumWant int `json:"numwant"` NumWant int `json:"numwant"`
Passkey string `json:"passkey"`
PeerID string `json:"peer_id"` PeerID string `json:"peer_id"`
Uploaded uint64 `json:"uploaded"` Uploaded uint64 `json:"uploaded"`
Torrent *Torrent `json:"-"` Torrent *Torrent `json:"-"`
User *User `json:"-"`
Peer *Peer `json:"-"` Peer *Peer `json:"-"`
PeerV4 *Peer `json:"-"` // Only valid if HasIPv4() is true. PeerV4 *Peer `json:"-"` // Only valid if HasIPv4() is true.
PeerV6 *Peer `json:"-"` // Only valid if HasIPv6() is true. PeerV6 *Peer `json:"-"` // Only valid if HasIPv6() is true.
@ -193,11 +170,9 @@ func (a *Announce) HasIPv6() bool {
return a.IPv6.IP != nil return a.IPv6.IP != nil
} }
// BuildPeer creates the Peer representation of an Announce. When provided nil // BuildPeer creates the Peer representation of an Announce. BuildPeer creates
// for the user or torrent parameter, it creates a Peer{UserID: 0} or // one peer for each IP in the announce, and panics if there are none.
// Peer{TorrentID: 0}, respectively. BuildPeer creates one peer for each IP func (a *Announce) BuildPeer(t *Torrent) {
// in the announce, and panics if there are none.
func (a *Announce) BuildPeer(u *User, t *Torrent) {
a.Peer = &Peer{ a.Peer = &Peer{
ID: a.PeerID, ID: a.PeerID,
Uploaded: a.Uploaded, Uploaded: a.Uploaded,
@ -207,15 +182,9 @@ func (a *Announce) BuildPeer(u *User, t *Torrent) {
} }
if t != nil { if t != nil {
a.Peer.TorrentID = t.ID
a.Torrent = t a.Torrent = t
} }
if u != nil {
a.Peer.UserID = u.ID
a.User = u
}
if a.HasIPv4() && a.HasIPv6() { if a.HasIPv4() && a.HasIPv6() {
a.PeerV4 = a.Peer a.PeerV4 = a.Peer
a.PeerV4.Endpoint = a.IPv4 a.PeerV4.Endpoint = a.IPv4
@ -230,31 +199,10 @@ func (a *Announce) BuildPeer(u *User, t *Torrent) {
} else { } else {
panic("models: announce must have an IP") panic("models: announce must have an IP")
} }
return return
} }
// AnnounceDelta contains the changes to a Peer's state. These changes are
// recorded by the backend driver.
type AnnounceDelta struct {
Peer *Peer
Torrent *Torrent
User *User
// Created is true if this announce created a new peer or changed an existing
// peer's address
Created bool
// Snatched is true if this announce completed the download
Snatched bool
// Uploaded contains the upload delta for this announce, in bytes
Uploaded uint64
RawUploaded uint64
// Downloaded contains the download delta for this announce, in bytes
Downloaded uint64
RawDownloaded uint64
}
// AnnounceResponse contains the information needed to fulfill an announce. // AnnounceResponse contains the information needed to fulfill an announce.
type AnnounceResponse struct { type AnnounceResponse struct {
Announce *Announce Announce *Announce
@ -267,9 +215,7 @@ type AnnounceResponse struct {
// Scrape is a Scrape by a Peer. // Scrape is a Scrape by a Peer.
type Scrape struct { type Scrape struct {
Config *config.Config `json:"config"` Config *config.Config `json:"config"`
Passkey string
Infohashes []string Infohashes []string
} }

View file

@ -201,5 +201,5 @@ func AppendPeer(ipv4s, ipv6s *PeerList, ann *Announce, peer *Peer) int {
// peersEquivalent checks if two peers represent the same entity. // peersEquivalent checks if two peers represent the same entity.
func peersEquivalent(a, b *Peer) bool { func peersEquivalent(a, b *Peer) bool {
return a.ID == b.ID || a.UserID != 0 && a.UserID == b.UserID return a.ID == b.ID
} }

View file

@ -12,12 +12,6 @@ import (
// HandleScrape encapsulates all the logic of handling a BitTorrent client's // HandleScrape encapsulates all the logic of handling a BitTorrent client's
// scrape without being coupled to any transport protocol. // scrape without being coupled to any transport protocol.
func (tkr *Tracker) HandleScrape(scrape *models.Scrape, w Writer) (err error) { func (tkr *Tracker) HandleScrape(scrape *models.Scrape, w Writer) (err error) {
if tkr.Config.PrivateEnabled {
if _, err = tkr.FindUser(scrape.Passkey); err != nil {
return err
}
}
var torrents []*models.Torrent var torrents []*models.Torrent
for _, infohash := range scrape.Infohashes { for _, infohash := range scrape.Infohashes {
torrent, err := tkr.FindTorrent(infohash) torrent, err := tkr.FindTorrent(infohash)

View file

@ -22,9 +22,6 @@ type Torrents struct {
} }
type Storage struct { type Storage struct {
users map[string]*models.User
usersM sync.RWMutex
shards []Torrents shards []Torrents
size int32 size int32
@ -34,7 +31,6 @@ type Storage struct {
func NewStorage(cfg *config.Config) *Storage { func NewStorage(cfg *config.Config) *Storage {
s := &Storage{ s := &Storage{
users: make(map[string]*models.User),
shards: make([]Torrents, cfg.TorrentMapShards), shards: make([]Torrents, cfg.TorrentMapShards),
clients: make(map[string]bool), clients: make(map[string]bool),
} }
@ -251,34 +247,6 @@ func (s *Storage) PurgeInactivePeers(purgeEmptyTorrents bool, before time.Time)
return nil return nil
} }
func (s *Storage) FindUser(passkey string) (*models.User, error) {
s.usersM.RLock()
defer s.usersM.RUnlock()
user, exists := s.users[passkey]
if !exists {
return nil, models.ErrUserDNE
}
userCopy := *user
return &userCopy, nil
}
func (s *Storage) PutUser(user *models.User) {
s.usersM.Lock()
defer s.usersM.Unlock()
userCopy := *user
s.users[user.Passkey] = &userCopy
}
func (s *Storage) DeleteUser(passkey string) {
s.usersM.Lock()
defer s.usersM.Unlock()
delete(s.users, passkey)
}
func (s *Storage) ClientApproved(peerID string) error { func (s *Storage) ClientApproved(peerID string) error {
s.clientsM.RLock() s.clientsM.RLock()
defer s.clientsM.RUnlock() defer s.clientsM.RUnlock()

View file

@ -11,7 +11,6 @@ import (
"github.com/golang/glog" "github.com/golang/glog"
"github.com/chihaya/chihaya/backend"
"github.com/chihaya/chihaya/config" "github.com/chihaya/chihaya/config"
"github.com/chihaya/chihaya/tracker/models" "github.com/chihaya/chihaya/tracker/models"
) )
@ -19,22 +18,15 @@ import (
// Tracker represents the logic necessary to service BitTorrent announces, // Tracker represents the logic necessary to service BitTorrent announces,
// independently of the underlying data transports used. // independently of the underlying data transports used.
type Tracker struct { type Tracker struct {
Config *config.Config Config *config.Config
Backend backend.Conn
*Storage *Storage
} }
// New creates a new Tracker, and opens any necessary connections. // New creates a new Tracker, and opens any necessary connections.
// Maintenance routines are automatically spawned in the background. // Maintenance routines are automatically spawned in the background.
func New(cfg *config.Config) (*Tracker, error) { func New(cfg *config.Config) (*Tracker, error) {
bc, err := backend.Open(&cfg.DriverConfig)
if err != nil {
return nil, err
}
tkr := &Tracker{ tkr := &Tracker{
Config: cfg, Config: cfg,
Backend: bc,
Storage: NewStorage(cfg), Storage: NewStorage(cfg),
} }
@ -53,7 +45,10 @@ func New(cfg *config.Config) (*Tracker, error) {
// Close gracefully shutdowns a Tracker by closing any database connections. // Close gracefully shutdowns a Tracker by closing any database connections.
func (tkr *Tracker) Close() error { func (tkr *Tracker) Close() error {
return tkr.Backend.Close()
// TODO(jzelinskie): shutdown purgeInactivePeers goroutine.
return nil
} }
// LoadApprovedClients loads a list of client IDs into the tracker's storage. // LoadApprovedClients loads a list of client IDs into the tracker's storage.

View file

@ -14,8 +14,6 @@ import (
"github.com/chihaya/chihaya/config" "github.com/chihaya/chihaya/config"
"github.com/chihaya/chihaya/tracker" "github.com/chihaya/chihaya/tracker"
_ "github.com/chihaya/chihaya/backend/noop"
) )
var ( var (