overhaul everything

This commit is contained in:
Jimmy Zelinskie
2014-06-23 22:47:43 -04:00
parent 18f6c32d97
commit 3bfb3074b4
27 changed files with 1193 additions and 1143 deletions

View File

@@ -0,0 +1,238 @@
// Copyright 2013 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 mock
import (
"github.com/chihaya/chihaya/drivers/tracker"
"github.com/chihaya/chihaya/models"
)
// Conn implements a connection to a memory-based tracker data store.
type Conn struct {
*Pool
}
func (c *Conn) FindUser(passkey string) (*models.User, error) {
c.usersM.RLock()
defer c.usersM.RUnlock()
user, exists := c.users[passkey]
if !exists {
return nil, tracker.ErrUserDNE
}
return &*user, nil
}
func (c *Conn) FindTorrent(infohash string) (*models.Torrent, error) {
c.torrentsM.RLock()
defer c.torrentsM.RUnlock()
torrent, exists := c.torrents[infohash]
if !exists {
return nil, tracker.ErrTorrentDNE
}
return &*torrent, nil
}
func (c *Conn) ClientWhitelisted(peerID string) error {
c.whitelistM.RLock()
defer c.whitelistM.RUnlock()
_, ok := c.whitelist[peerID]
if !ok {
return tracker.ErrClientUnapproved
}
return nil
}
func (c *Conn) IncrementSnatches(t *models.Torrent) error {
c.torrentsM.Lock()
defer c.torrentsM.Unlock()
torrent, ok := c.torrents[t.Infohash]
if !ok {
return tracker.ErrTorrentDNE
}
torrent.Snatches++
t.Snatches++
return nil
}
func (c *Conn) MarkActive(t *models.Torrent) error {
c.torrentsM.Lock()
defer c.torrentsM.Unlock()
torrent, ok := c.torrents[t.Infohash]
if !ok {
return tracker.ErrTorrentDNE
}
torrent.Active = true
t.Active = true
return nil
}
func (c *Conn) MarkInactive(t *models.Torrent) error {
c.torrentsM.Lock()
defer c.torrentsM.Unlock()
torrent, ok := c.torrents[t.Infohash]
if !ok {
return tracker.ErrTorrentDNE
}
torrent.Active = false
t.Active = false
return nil
}
func (c *Conn) AddLeecher(t *models.Torrent, p *models.Peer) error {
c.torrentsM.Lock()
defer c.torrentsM.Unlock()
torrent, ok := c.torrents[t.Infohash]
if !ok {
return tracker.ErrTorrentDNE
}
torrent.Leechers[p.Key()] = *p
t.Leechers[p.Key()] = *p
return nil
}
func (c *Conn) AddSeeder(t *models.Torrent, p *models.Peer) error {
c.torrentsM.Lock()
defer c.torrentsM.Unlock()
torrent, ok := c.torrents[t.Infohash]
if !ok {
return tracker.ErrTorrentDNE
}
torrent.Seeders[p.Key()] = *p
t.Seeders[p.Key()] = *p
return nil
}
func (c *Conn) RemoveLeecher(t *models.Torrent, p *models.Peer) error {
c.torrentsM.Lock()
defer c.torrentsM.Unlock()
torrent, ok := c.torrents[t.Infohash]
if !ok {
return tracker.ErrTorrentDNE
}
delete(torrent.Leechers, p.Key())
delete(t.Leechers, p.Key())
return nil
}
func (c *Conn) RemoveSeeder(t *models.Torrent, p *models.Peer) error {
c.torrentsM.Lock()
defer c.torrentsM.Unlock()
torrent, ok := c.torrents[t.Infohash]
if !ok {
return tracker.ErrTorrentDNE
}
delete(torrent.Seeders, p.Key())
delete(t.Seeders, p.Key())
return nil
}
func (c *Conn) SetLeecher(t *models.Torrent, p *models.Peer) error {
c.torrentsM.Lock()
defer c.torrentsM.Unlock()
torrent, ok := c.torrents[t.Infohash]
if !ok {
return tracker.ErrTorrentDNE
}
torrent.Leechers[p.Key()] = *p
t.Leechers[p.Key()] = *p
return nil
}
func (c *Conn) SetSeeder(t *models.Torrent, p *models.Peer) error {
c.torrentsM.Lock()
defer c.torrentsM.Unlock()
torrent, ok := c.torrents[t.Infohash]
if !ok {
return tracker.ErrTorrentDNE
}
torrent.Seeders[p.Key()] = *p
t.Seeders[p.Key()] = *p
return nil
}
func (c *Conn) AddTorrent(t *models.Torrent) error {
c.torrentsM.Lock()
defer c.torrentsM.Unlock()
torrent := *t
c.torrents[t.Infohash] = &torrent
return nil
}
func (c *Conn) RemoveTorrent(t *models.Torrent) error {
c.torrentsM.Lock()
defer c.torrentsM.Unlock()
delete(c.torrents, t.Infohash)
return nil
}
func (c *Conn) AddUser(u *models.User) error {
c.usersM.Lock()
defer c.usersM.Unlock()
user := *u
c.users[u.Passkey] = &user
return nil
}
func (c *Conn) RemoveUser(u *models.User) error {
c.usersM.Lock()
defer c.usersM.Unlock()
delete(c.users, u.Passkey)
return nil
}
func (c *Conn) WhitelistClient(peerID string) error {
c.whitelistM.Lock()
defer c.whitelistM.Unlock()
c.whitelist[peerID] = true
return nil
}
func (c *Conn) UnWhitelistClient(peerID string) error {
c.whitelistM.Lock()
defer c.whitelistM.Unlock()
delete(c.whitelist, peerID)
return nil
}

View File

@@ -0,0 +1,28 @@
// Copyright 2013 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 mock implements the models interface for a BitTorrent tracker
// within memory. It can be used in production, but isn't recommended.
// Stored values will not persist if the tracker is restarted.
package mock
import (
"github.com/chihaya/chihaya/config"
"github.com/chihaya/chihaya/drivers/tracker"
"github.com/chihaya/chihaya/models"
)
type driver struct{}
func (d *driver) New(conf *config.DataStore) tracker.Pool {
return &Pool{
users: make(map[string]*models.User),
torrents: make(map[string]*models.Torrent),
whitelist: make(map[string]bool),
}
}
func init() {
tracker.Register("mock", &driver{})
}

View File

@@ -0,0 +1,33 @@
// Copyright 2013 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 mock
import (
"sync"
"github.com/chihaya/chihaya/drivers/tracker"
"github.com/chihaya/chihaya/models"
)
type Pool struct {
users map[string]*models.User
usersM sync.RWMutex
torrents map[string]*models.Torrent
torrentsM sync.RWMutex
whitelist map[string]bool
whitelistM sync.RWMutex
}
func (p *Pool) Get() (tracker.Conn, error) {
return &Conn{
Pool: p,
}, nil
}
func (p *Pool) Close() error {
return nil
}

104
drivers/tracker/tracker.go Normal file
View File

@@ -0,0 +1,104 @@
// Copyright 2013 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 tracker provides a generic interface for manipulating a
// BitTorrent tracker's fast-moving data.
package tracker
import (
"errors"
"fmt"
"github.com/chihaya/chihaya/config"
"github.com/chihaya/chihaya/models"
)
var (
// ErrUserDNE is returned when a user does not exist.
ErrUserDNE = errors.New("user does not exist")
// ErrTorrentDNE is returned when a torrent does not exist.
ErrTorrentDNE = errors.New("torrent does not exist")
// ErrClientUnapproved is returned when a clientID is not in the whitelist.
ErrClientUnapproved = errors.New("client is not approved")
// ErrInvalidPasskey is returned when a passkey is not properly formatted.
ErrInvalidPasskey = errors.New("passkey is invalid")
drivers = make(map[string]Driver)
)
// Driver represents an interface to pool of connections to models used for
// the tracker.
type Driver interface {
New(*config.DataStore) Pool
}
// 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("tracker: Register driver is nil")
}
if _, dup := drivers[name]; dup {
panic("tracker: Register called twice for driver " + name)
}
drivers[name] = driver
}
// Open creates a pool of data store connections specified by a models configuration.
func Open(conf *config.DataStore) (Pool, error) {
driver, ok := drivers[conf.Driver]
if !ok {
return nil, fmt.Errorf(
"unknown driver %q (forgotten import?)",
conf.Driver,
)
}
pool := driver.New(conf)
return pool, nil
}
// Pool represents a thread-safe pool of connections to the data store
// that can be used to safely within concurrent goroutines.
type Pool interface {
Close() error
Get() (Conn, error)
}
// Conn represents a connection to the data store that can be used
// to make reads/writes.
type Conn interface {
// Reads
FindUser(passkey string) (*models.User, error)
FindTorrent(infohash string) (*models.Torrent, error)
ClientWhitelisted(clientID string) error
// Writes
IncrementSnatches(t *models.Torrent) error
MarkActive(t *models.Torrent) error
AddLeecher(t *models.Torrent, p *models.Peer) error
AddSeeder(t *models.Torrent, p *models.Peer) error
RemoveLeecher(t *models.Torrent, p *models.Peer) error
RemoveSeeder(t *models.Torrent, p *models.Peer) error
SetLeecher(t *models.Torrent, p *models.Peer) error
SetSeeder(t *models.Torrent, p *models.Peer) error
// Priming / Testing
AddTorrent(t *models.Torrent) error
RemoveTorrent(t *models.Torrent) error
AddUser(u *models.User) error
RemoveUser(u *models.User) error
WhitelistClient(clientID string) error
UnWhitelistClient(clientID string) error
}
// LeecherFinished moves a peer from the leeching pool to the seeder pool.
func LeecherFinished(c Conn, t *models.Torrent, p *models.Peer) error {
err := c.RemoveLeecher(t, p)
if err != nil {
return err
}
err = c.AddSeeder(t, p)
return err
}