Merge pull request #128 from chihaya/rmprivate
remove all private tracker logic
This commit is contained in:
commit
4d018d5081
21 changed files with 24 additions and 516 deletions
|
@ -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.
|
||||
|
||||
##### `privateEnabled`
|
||||
|
||||
type: bool
|
||||
default: true
|
||||
|
||||
Whether this is a public or private tracker.
|
||||
|
||||
##### `createOnAnnounce`
|
||||
|
||||
type: bool
|
||||
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`
|
||||
|
||||
type: bool
|
||||
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`
|
||||
|
||||
|
@ -129,13 +122,6 @@ Enables the peer ID whitelist.
|
|||
|
||||
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`
|
||||
|
||||
type: integer
|
||||
|
@ -225,4 +211,4 @@ Whether the information about memory should be verbose.
|
|||
type: duration
|
||||
default: "5s"
|
||||
|
||||
Interval at which to collect statistics about memory.
|
||||
Interval at which to collect statistics about memory.
|
||||
|
|
|
@ -14,7 +14,6 @@ RUN godep restore
|
|||
# Add source
|
||||
ADD *.go /go/src/github.com/chihaya/chihaya/
|
||||
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 config /go/src/github.com/chihaya/chihaya/config
|
||||
ADD http /go/src/github.com/chihaya/chihaya/http
|
||||
|
|
|
@ -84,11 +84,6 @@ func (s *Server) Serve() {
|
|||
func newRouter(s *Server) *httprouter.Router {
|
||||
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 {
|
||||
r.GET("/clients/:clientID", makeHandler(s.getClient))
|
||||
r.PUT("/clients/:clientID", makeHandler(s.putClient))
|
||||
|
|
|
@ -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) {
|
||||
// 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"))
|
||||
return handleError(err)
|
||||
}
|
||||
|
@ -109,35 +102,6 @@ func (s *Server) delTorrent(w http.ResponseWriter, r *http.Request, p httprouter
|
|||
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) {
|
||||
if err := s.tracker.ClientApproved(p.ByName("clientID")); err != nil {
|
||||
return http.StatusNotFound, err
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
```
|
|
@ -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)
|
||||
}
|
|
@ -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{})
|
||||
}
|
|
@ -23,9 +23,6 @@ import (
|
|||
"github.com/chihaya/chihaya/stats"
|
||||
"github.com/chihaya/chihaya/tracker"
|
||||
"github.com/chihaya/chihaya/udp"
|
||||
|
||||
// See the README for how to import custom drivers.
|
||||
_ "github.com/chihaya/chihaya/backend/noop"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
|
@ -7,16 +7,11 @@ package config
|
|||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"io"
|
||||
"os"
|
||||
"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.
|
||||
type Duration struct{ time.Duration }
|
||||
|
||||
|
@ -33,13 +28,6 @@ func (d *Duration) UnmarshalJSON(b []byte) error {
|
|||
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
|
||||
// given a preference when responding to an announce.
|
||||
type SubnetConfig struct {
|
||||
|
@ -75,8 +63,6 @@ type WhitelistConfig struct {
|
|||
// TrackerConfig is the configuration for tracker functionality.
|
||||
type TrackerConfig struct {
|
||||
CreateOnAnnounce bool `json:"createOnAnnounce"`
|
||||
PrivateEnabled bool `json:"privateEnabled"`
|
||||
FreeleechEnabled bool `json:"freeleechEnabled"`
|
||||
PurgeInactiveTorrents bool `json:"purgeInactiveTorrents"`
|
||||
Announce Duration `json:"announce"`
|
||||
MinAnnounce Duration `json:"minAnnounce"`
|
||||
|
@ -119,7 +105,6 @@ type Config struct {
|
|||
APIConfig
|
||||
HTTPConfig
|
||||
UDPConfig
|
||||
DriverConfig
|
||||
StatsConfig
|
||||
}
|
||||
|
||||
|
@ -127,8 +112,6 @@ type Config struct {
|
|||
var DefaultConfig = Config{
|
||||
TrackerConfig: TrackerConfig{
|
||||
CreateOnAnnounce: true,
|
||||
PrivateEnabled: false,
|
||||
FreeleechEnabled: false,
|
||||
PurgeInactiveTorrents: true,
|
||||
Announce: Duration{30 * time.Minute},
|
||||
MinAnnounce: Duration{15 * time.Minute},
|
||||
|
@ -166,10 +149,6 @@ var DefaultConfig = Config{
|
|||
ListenAddr: "localhost:6882",
|
||||
},
|
||||
|
||||
DriverConfig: DriverConfig{
|
||||
Name: "noop",
|
||||
},
|
||||
|
||||
StatsConfig: StatsConfig{
|
||||
BufferSize: 0,
|
||||
IncludeMem: true,
|
||||
|
|
|
@ -1,7 +1,5 @@
|
|||
{
|
||||
"createOnAnnounce": true,
|
||||
"privateEnabled": false,
|
||||
"freeleechEnabled": false,
|
||||
"purgeInactiveTorrents": true,
|
||||
"announce": "30m",
|
||||
"minAnnounce": "15m",
|
||||
|
|
|
@ -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) {
|
||||
cfg := config.DefaultConfig
|
||||
cfg.PreferredSubnet = true
|
||||
|
@ -337,29 +297,3 @@ func checkAnnounce(p params, expected interface{}, srv *httptest.Server, t *test
|
|||
}
|
||||
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)
|
||||
}
|
||||
|
|
|
@ -73,13 +73,8 @@ func makeHandler(handler ResponseHandler) httprouter.Handle {
|
|||
func newRouter(s *Server) *httprouter.Router {
|
||||
r := httprouter.New()
|
||||
|
||||
if s.config.PrivateEnabled {
|
||||
r.GET("/users/:passkey/announce", makeHandler(s.serveAnnounce))
|
||||
r.GET("/users/:passkey/scrape", makeHandler(s.serveScrape))
|
||||
} else {
|
||||
r.GET("/announce", makeHandler(s.serveAnnounce))
|
||||
r.GET("/scrape", makeHandler(s.serveScrape))
|
||||
}
|
||||
r.GET("/announce", makeHandler(s.serveAnnounce))
|
||||
r.GET("/scrape", makeHandler(s.serveScrape))
|
||||
|
||||
return r
|
||||
}
|
||||
|
|
|
@ -15,8 +15,6 @@ import (
|
|||
"github.com/chihaya/chihaya/config"
|
||||
"github.com/chihaya/chihaya/stats"
|
||||
"github.com/chihaya/chihaya/tracker"
|
||||
|
||||
_ "github.com/chihaya/chihaya/backend/noop"
|
||||
)
|
||||
|
||||
type params map[string]string
|
||||
|
|
|
@ -76,7 +76,6 @@ func (s *Server) newAnnounce(r *http.Request, p httprouter.Params) (*models.Anno
|
|||
Infohash: infohash,
|
||||
Left: left,
|
||||
NumWant: numWant,
|
||||
Passkey: p.ByName("passkey"),
|
||||
PeerID: peerID,
|
||||
Uploaded: uploaded,
|
||||
}, nil
|
||||
|
@ -98,9 +97,7 @@ func (s *Server) newScrape(r *http.Request, p httprouter.Params) (*models.Scrape
|
|||
}
|
||||
|
||||
return &models.Scrape{
|
||||
Config: s.config,
|
||||
|
||||
Passkey: p.ByName("passkey"),
|
||||
Config: s.config,
|
||||
Infohashes: q.Infohashes,
|
||||
}, nil
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
||||
if err == models.ErrTorrentDNE && tkr.Config.CreateOnAnnounce {
|
||||
|
@ -40,30 +33,19 @@ func (tkr *Tracker) HandleAnnounce(ann *models.Announce, w Writer) (err error) {
|
|||
return err
|
||||
}
|
||||
|
||||
ann.BuildPeer(user, torrent)
|
||||
var delta *models.AnnounceDelta
|
||||
ann.BuildPeer(torrent)
|
||||
|
||||
if tkr.Config.PrivateEnabled {
|
||||
delta = newAnnounceDelta(ann, torrent)
|
||||
}
|
||||
|
||||
created, err := tkr.updateSwarm(ann)
|
||||
_, err = tkr.updateSwarm(ann)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
snatched, err := tkr.handleEvent(ann)
|
||||
_, err = tkr.handleEvent(ann)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if tkr.Config.PrivateEnabled {
|
||||
delta.Created = created
|
||||
delta.Snatched = snatched
|
||||
if err = tkr.Backend.RecordAnnounce(delta); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if tkr.Config.PurgeInactiveTorrents && torrent.PeerCount() == 0 {
|
||||
if tkr.Config.PurgeInactiveTorrents && torrent.PeerCount() == 0 {
|
||||
// Rather than deleting the torrent explicitly, let the tracker driver
|
||||
// ensure there are no race conditions.
|
||||
tkr.PurgeInactiveTorrent(torrent.Infohash)
|
||||
|
@ -74,49 +56,6 @@ func (tkr *Tracker) HandleAnnounce(ann *models.Announce, w Writer) (err error) {
|
|||
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.
|
||||
func (tkr *Tracker) updateSwarm(ann *models.Announce) (created bool, err error) {
|
||||
var createdv4, createdv6 bool
|
||||
|
|
|
@ -24,17 +24,11 @@ var (
|
|||
// not a leecher or a "stopped" event while not active.
|
||||
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 = NotFoundError("torrent does not exist")
|
||||
|
||||
// ErrClientUnapproved is returned when a clientID is not in the whitelist.
|
||||
ErrClientUnapproved = ClientError("client is not approved")
|
||||
|
||||
// ErrInvalidPasskey is returned when a passkey is not properly formatted.
|
||||
ErrInvalidPasskey = ClientError("passkey is invalid")
|
||||
)
|
||||
|
||||
type ClientError string
|
||||
|
@ -89,8 +83,6 @@ type Endpoint struct {
|
|||
// Peer represents a participant in a BitTorrent swarm.
|
||||
type Peer struct {
|
||||
ID string `json:"id"`
|
||||
UserID uint64 `json:"userId"`
|
||||
TorrentID uint64 `json:"torrentId"`
|
||||
Uploaded uint64 `json:"uploaded"`
|
||||
Downloaded uint64 `json:"downloaded"`
|
||||
Left uint64 `json:"left"`
|
||||
|
@ -117,16 +109,12 @@ func (p *Peer) Key() PeerKey {
|
|||
|
||||
// Torrent represents a BitTorrent swarm and its metadata.
|
||||
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"`
|
||||
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.
|
||||
|
@ -134,15 +122,6 @@ func (t *Torrent) PeerCount() int {
|
|||
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.
|
||||
type Announce struct {
|
||||
Config *config.Config `json:"config"`
|
||||
|
@ -155,12 +134,10 @@ type Announce struct {
|
|||
Infohash string `json:"infohash"`
|
||||
Left uint64 `json:"left"`
|
||||
NumWant int `json:"numwant"`
|
||||
Passkey string `json:"passkey"`
|
||||
PeerID string `json:"peer_id"`
|
||||
Uploaded uint64 `json:"uploaded"`
|
||||
|
||||
Torrent *Torrent `json:"-"`
|
||||
User *User `json:"-"`
|
||||
Peer *Peer `json:"-"`
|
||||
PeerV4 *Peer `json:"-"` // Only valid if HasIPv4() 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
|
||||
}
|
||||
|
||||
// BuildPeer creates the Peer representation of an Announce. When provided nil
|
||||
// for the user or torrent parameter, it creates a Peer{UserID: 0} or
|
||||
// Peer{TorrentID: 0}, respectively. BuildPeer creates one peer for each IP
|
||||
// in the announce, and panics if there are none.
|
||||
func (a *Announce) BuildPeer(u *User, t *Torrent) {
|
||||
// BuildPeer creates the Peer representation of an Announce. BuildPeer creates
|
||||
// one peer for each IP in the announce, and panics if there are none.
|
||||
func (a *Announce) BuildPeer(t *Torrent) {
|
||||
a.Peer = &Peer{
|
||||
ID: a.PeerID,
|
||||
Uploaded: a.Uploaded,
|
||||
|
@ -207,15 +182,9 @@ func (a *Announce) BuildPeer(u *User, t *Torrent) {
|
|||
}
|
||||
|
||||
if t != nil {
|
||||
a.Peer.TorrentID = t.ID
|
||||
a.Torrent = t
|
||||
}
|
||||
|
||||
if u != nil {
|
||||
a.Peer.UserID = u.ID
|
||||
a.User = u
|
||||
}
|
||||
|
||||
if a.HasIPv4() && a.HasIPv6() {
|
||||
a.PeerV4 = a.Peer
|
||||
a.PeerV4.Endpoint = a.IPv4
|
||||
|
@ -230,31 +199,10 @@ func (a *Announce) BuildPeer(u *User, t *Torrent) {
|
|||
} else {
|
||||
panic("models: announce must have an IP")
|
||||
}
|
||||
|
||||
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.
|
||||
type AnnounceResponse struct {
|
||||
Announce *Announce
|
||||
|
@ -267,9 +215,7 @@ type AnnounceResponse struct {
|
|||
|
||||
// Scrape is a Scrape by a Peer.
|
||||
type Scrape struct {
|
||||
Config *config.Config `json:"config"`
|
||||
|
||||
Passkey string
|
||||
Config *config.Config `json:"config"`
|
||||
Infohashes []string
|
||||
}
|
||||
|
||||
|
|
|
@ -201,5 +201,5 @@ func AppendPeer(ipv4s, ipv6s *PeerList, ann *Announce, peer *Peer) int {
|
|||
|
||||
// peersEquivalent checks if two peers represent the same entity.
|
||||
func peersEquivalent(a, b *Peer) bool {
|
||||
return a.ID == b.ID || a.UserID != 0 && a.UserID == b.UserID
|
||||
return a.ID == b.ID
|
||||
}
|
||||
|
|
|
@ -12,12 +12,6 @@ import (
|
|||
// HandleScrape encapsulates all the logic of handling a BitTorrent client's
|
||||
// scrape without being coupled to any transport protocol.
|
||||
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
|
||||
for _, infohash := range scrape.Infohashes {
|
||||
torrent, err := tkr.FindTorrent(infohash)
|
||||
|
|
|
@ -22,9 +22,6 @@ type Torrents struct {
|
|||
}
|
||||
|
||||
type Storage struct {
|
||||
users map[string]*models.User
|
||||
usersM sync.RWMutex
|
||||
|
||||
shards []Torrents
|
||||
size int32
|
||||
|
||||
|
@ -34,7 +31,6 @@ type Storage struct {
|
|||
|
||||
func NewStorage(cfg *config.Config) *Storage {
|
||||
s := &Storage{
|
||||
users: make(map[string]*models.User),
|
||||
shards: make([]Torrents, cfg.TorrentMapShards),
|
||||
clients: make(map[string]bool),
|
||||
}
|
||||
|
@ -251,34 +247,6 @@ func (s *Storage) PurgeInactivePeers(purgeEmptyTorrents bool, before time.Time)
|
|||
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 {
|
||||
s.clientsM.RLock()
|
||||
defer s.clientsM.RUnlock()
|
||||
|
|
|
@ -11,7 +11,6 @@ import (
|
|||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"github.com/chihaya/chihaya/backend"
|
||||
"github.com/chihaya/chihaya/config"
|
||||
"github.com/chihaya/chihaya/tracker/models"
|
||||
)
|
||||
|
@ -19,22 +18,15 @@ import (
|
|||
// Tracker represents the logic necessary to service BitTorrent announces,
|
||||
// independently of the underlying data transports used.
|
||||
type Tracker struct {
|
||||
Config *config.Config
|
||||
Backend backend.Conn
|
||||
Config *config.Config
|
||||
*Storage
|
||||
}
|
||||
|
||||
// New creates a new Tracker, and opens any necessary connections.
|
||||
// Maintenance routines are automatically spawned in the background.
|
||||
func New(cfg *config.Config) (*Tracker, error) {
|
||||
bc, err := backend.Open(&cfg.DriverConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
tkr := &Tracker{
|
||||
Config: cfg,
|
||||
Backend: bc,
|
||||
Storage: NewStorage(cfg),
|
||||
}
|
||||
|
||||
|
@ -53,7 +45,10 @@ func New(cfg *config.Config) (*Tracker, error) {
|
|||
|
||||
// Close gracefully shutdowns a Tracker by closing any database connections.
|
||||
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.
|
||||
|
|
|
@ -14,8 +14,6 @@ import (
|
|||
|
||||
"github.com/chihaya/chihaya/config"
|
||||
"github.com/chihaya/chihaya/tracker"
|
||||
|
||||
_ "github.com/chihaya/chihaya/backend/noop"
|
||||
)
|
||||
|
||||
var (
|
||||
|
|
Loading…
Reference in a new issue