diff --git a/cmd/chihaya/main.go b/cmd/chihaya/main.go index 905821b..60f5061 100644 --- a/cmd/chihaya/main.go +++ b/cmd/chihaya/main.go @@ -11,7 +11,7 @@ import ( "os/signal" "syscall" - "github.com/chihaya/chihaya/config" + "github.com/chihaya/chihaya" "github.com/chihaya/chihaya/server" "github.com/chihaya/chihaya/tracker" @@ -31,7 +31,7 @@ func init() { func main() { flag.Parse() - cfg, err := config.Open(configPath) + cfg, err := chihaya.OpenConfigFile(configPath) if err != nil { log.Fatal("failed to load config: " + err.Error()) } diff --git a/config/config.go b/config.go similarity index 61% rename from config/config.go rename to config.go index 686dec4..1016566 100644 --- a/config/config.go +++ b/config.go @@ -2,8 +2,7 @@ // Use of this source code is governed by the BSD 2-Clause license, // which can be found in the LICENSE file. -// Package config implements the opening and parsing of a chihaya configuration. -package config +package chihaya import ( "io" @@ -31,8 +30,8 @@ type Config struct { Servers []ServerConfig `yaml:"servers"` } -// TrackerConfig represents the configuration of the BitTorrent tracker used by -// chihaya. +// TrackerConfig represents the configuration of protocol-agnostic BitTorrent +// Tracker used by Servers started by chihaya. type TrackerConfig struct { AnnounceInterval time.Duration `yaml:"announce"` MinAnnounceInterval time.Duration `yaml:"min_announce"` @@ -40,15 +39,39 @@ type TrackerConfig struct { ScrapeMiddleware []string `yaml:"scrape_middleware"` } -// ServerConfig represents the configuration of the servers started by chihaya. +// ServerConfig represents the configuration of the Servers started by chihaya. type ServerConfig struct { Name string `yaml:"name"` Config interface{} `yaml:"config"` } -// Open is a shortcut to open a file, read it, and allocates a new Config. -// It supports relative and absolute paths. Given "", it returns DefaultConfig. -func Open(path string) (*Config, error) { +// ConfigFile represents a YAML configuration file that namespaces all chihaya +// configuration under the "chihaya" namespace. +type ConfigFile struct { + Chihaya Config `yaml:"chihaya"` +} + +// DecodeConfigFile unmarshals an io.Reader into a new Config. +func DecodeConfigFile(r io.Reader) (*Config, error) { + contents, err := ioutil.ReadAll(r) + if err != nil { + return nil, err + } + + cfgFile := &ConfigFile{} + err = yaml.Unmarshal(contents, cfgFile) + if err != nil { + return nil, err + } + + return &cfgFile.Chihaya, nil +} + +// OpenConfigFile returns a new Config given the path to a YAML configuration +// file. +// It supports relative and absolute paths and environment variables. +// Given "", it returns DefaultConfig. +func OpenConfigFile(path string) (*Config, error) { if path == "" { return &DefaultConfig, nil } @@ -59,23 +82,7 @@ func Open(path string) (*Config, error) { } defer f.Close() - cfg, err := Decode(f) - if err != nil { - return nil, err - } - - return cfg, nil -} - -// Decode unmarshals an io.Reader into a newly allocated *Config. -func Decode(r io.Reader) (*Config, error) { - contents, err := ioutil.ReadAll(r) - if err != nil { - return nil, err - } - - cfg := &Config{} - err = yaml.Unmarshal(contents, cfg) + cfg, err := DecodeConfigFile(f) if err != nil { return nil, err } diff --git a/config/example.yaml b/config/example.yaml deleted file mode 100644 index c2489f9..0000000 --- a/config/example.yaml +++ /dev/null @@ -1,39 +0,0 @@ -# Copyright 2016 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. - -tracker: - announce: 10m - min_announce: 5m - announce_middleware: - - prometheus - - store_client_validation - - store_create_on_announce - scrape_middleware: - - prometheus - - store_client_validation - -servers: - - name: store - config: - addr: localhost:6880 - request_timeout: 10s - read_timeout: 10s - write_timeout: 10s - client_store: memory - ip_store: memory - peer_store: memory - peer_store_config: - gcAfter: 30m - shards: 1 - - - name: http - config: - addr: localhost:6881 - request_timeout: 10s - read_timeout: 10s - write_timeout: 10s - - - name: udp - config: - addr: localhost:6882 diff --git a/config_example.yaml b/config_example.yaml new file mode 100644 index 0000000..45874a2 --- /dev/null +++ b/config_example.yaml @@ -0,0 +1,40 @@ +# Copyright 2016 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. + +chihaya: + tracker: + announce: 10m + min_announce: 5m + announce_middleware: + - prometheus + - store_client_validation + - store_create_on_announce + scrape_middleware: + - prometheus + - store_client_validation + + servers: + - name: store + config: + addr: localhost:6880 + request_timeout: 10s + read_timeout: 10s + write_timeout: 10s + client_store: memory + ip_store: memory + peer_store: memory + peer_store_config: + gcAfter: 30m + shards: 1 + + - name: http + config: + addr: localhost:6881 + request_timeout: 10s + read_timeout: 10s + write_timeout: 10s + + - name: udp + config: + addr: localhost:6882 diff --git a/server/http/config.go b/server/http/config.go index 34108ef..9f14193 100644 --- a/server/http/config.go +++ b/server/http/config.go @@ -7,8 +7,9 @@ package http import ( "time" - "github.com/chihaya/chihaya/config" "gopkg.in/yaml.v2" + + "github.com/chihaya/chihaya" ) type httpConfig struct { @@ -21,7 +22,7 @@ type httpConfig struct { RealIPHeader string `yaml:"real_ip_header"` } -func newHTTPConfig(srvcfg *config.ServerConfig) (*httpConfig, error) { +func newHTTPConfig(srvcfg *chihaya.ServerConfig) (*httpConfig, error) { bytes, err := yaml.Marshal(srvcfg.Config) if err != nil { return nil, err diff --git a/server/http/server.go b/server/http/server.go index a2cdfc5..129e0b8 100644 --- a/server/http/server.go +++ b/server/http/server.go @@ -13,7 +13,7 @@ import ( "github.com/julienschmidt/httprouter" "github.com/tylerb/graceful" - "github.com/chihaya/chihaya/config" + "github.com/chihaya/chihaya" "github.com/chihaya/chihaya/server" "github.com/chihaya/chihaya/tracker" ) @@ -22,7 +22,7 @@ func init() { server.Register("http", constructor) } -func constructor(srvcfg *config.ServerConfig, tkr *tracker.Tracker) (server.Server, error) { +func constructor(srvcfg *chihaya.ServerConfig, tkr *tracker.Tracker) (server.Server, error) { cfg, err := newHTTPConfig(srvcfg) if err != nil { return nil, errors.New("http: invalid config: " + err.Error()) diff --git a/server/pool.go b/server/pool.go index d6c812f..9aa368b 100644 --- a/server/pool.go +++ b/server/pool.go @@ -7,7 +7,7 @@ package server import ( "sync" - "github.com/chihaya/chihaya/config" + "github.com/chihaya/chihaya" "github.com/chihaya/chihaya/tracker" ) @@ -17,9 +17,9 @@ type Pool struct { wg sync.WaitGroup } -// StartPool creates a new pool of servers specified by the provided config and -// runs them. -func StartPool(cfgs []config.ServerConfig, tkr *tracker.Tracker) (*Pool, error) { +// StartPool creates a new pool of servers specified by the provided +// configuration and runs them. +func StartPool(cfgs []chihaya.ServerConfig, tkr *tracker.Tracker) (*Pool, error) { var toReturn Pool for _, cfg := range cfgs { diff --git a/server/server.go b/server/server.go index 1d0fa3e..9c561e4 100644 --- a/server/server.go +++ b/server/server.go @@ -12,14 +12,14 @@ package server import ( "fmt" - "github.com/chihaya/chihaya/config" + "github.com/chihaya/chihaya" "github.com/chihaya/chihaya/tracker" ) var constructors = make(map[string]Constructor) // Constructor is a function that creates a new Server. -type Constructor func(*config.ServerConfig, *tracker.Tracker) (Server, error) +type Constructor func(*chihaya.ServerConfig, *tracker.Tracker) (Server, error) // Register makes a Constructor available by the provided name. // @@ -36,7 +36,7 @@ func Register(name string, con Constructor) { } // New creates a Server specified by a configuration. -func New(cfg *config.ServerConfig, tkr *tracker.Tracker) (Server, error) { +func New(cfg *chihaya.ServerConfig, tkr *tracker.Tracker) (Server, error) { con, ok := constructors[cfg.Name] if !ok { return nil, fmt.Errorf( diff --git a/server/store/middleware/client/blacklist.go b/server/store/middleware/client/blacklist.go index 84f1182..ce857a5 100644 --- a/server/store/middleware/client/blacklist.go +++ b/server/store/middleware/client/blacklist.go @@ -6,7 +6,6 @@ package ip import ( "github.com/chihaya/chihaya" - "github.com/chihaya/chihaya/config" "github.com/chihaya/chihaya/server/store" "github.com/chihaya/chihaya/tracker" ) @@ -22,7 +21,7 @@ var ErrBlockedClient = tracker.ClientError("disallowed client") // blacklistAnnounceClient provides a middleware that only allows Clients to // announce that are not stored in a ClientStore. func blacklistAnnounceClient(next tracker.AnnounceHandler) tracker.AnnounceHandler { - return func(cfg *config.TrackerConfig, req *chihaya.AnnounceRequest, resp *chihaya.AnnounceResponse) error { + return func(cfg *chihaya.TrackerConfig, req *chihaya.AnnounceRequest, resp *chihaya.AnnounceResponse) error { blacklisted, err := store.MustGetStore().FindClient(req.PeerID) if err != nil { diff --git a/server/store/middleware/client/whitelist.go b/server/store/middleware/client/whitelist.go index 305c59c..dc8c442 100644 --- a/server/store/middleware/client/whitelist.go +++ b/server/store/middleware/client/whitelist.go @@ -6,7 +6,6 @@ package ip import ( "github.com/chihaya/chihaya" - "github.com/chihaya/chihaya/config" "github.com/chihaya/chihaya/server/store" "github.com/chihaya/chihaya/tracker" ) @@ -18,7 +17,7 @@ func init() { // whitelistAnnounceClient provides a middleware that only allows Clients to // announce that are stored in a ClientStore. func whitelistAnnounceClient(next tracker.AnnounceHandler) tracker.AnnounceHandler { - return func(cfg *config.TrackerConfig, req *chihaya.AnnounceRequest, resp *chihaya.AnnounceResponse) error { + return func(cfg *chihaya.TrackerConfig, req *chihaya.AnnounceRequest, resp *chihaya.AnnounceResponse) error { whitelisted, err := store.MustGetStore().FindClient(req.PeerID) if err != nil { diff --git a/server/store/middleware/ip/blacklist.go b/server/store/middleware/ip/blacklist.go index a2f460e..deee714 100644 --- a/server/store/middleware/ip/blacklist.go +++ b/server/store/middleware/ip/blacklist.go @@ -8,7 +8,6 @@ import ( "net" "github.com/chihaya/chihaya" - "github.com/chihaya/chihaya/config" "github.com/chihaya/chihaya/server/store" "github.com/chihaya/chihaya/tracker" ) @@ -24,7 +23,7 @@ var ErrBlockedIP = tracker.ClientError("disallowed IP address") // blacklistAnnounceIP provides a middleware that only allows IPs to announce // that are not stored in an IPStore. func blacklistAnnounceIP(next tracker.AnnounceHandler) tracker.AnnounceHandler { - return func(cfg *config.TrackerConfig, req *chihaya.AnnounceRequest, resp *chihaya.AnnounceResponse) (err error) { + return func(cfg *chihaya.TrackerConfig, req *chihaya.AnnounceRequest, resp *chihaya.AnnounceResponse) (err error) { blacklisted := false storage := store.MustGetStore() diff --git a/server/store/middleware/ip/whitelist.go b/server/store/middleware/ip/whitelist.go index 2ad9808..71cd7d9 100644 --- a/server/store/middleware/ip/whitelist.go +++ b/server/store/middleware/ip/whitelist.go @@ -8,7 +8,6 @@ import ( "net" "github.com/chihaya/chihaya" - "github.com/chihaya/chihaya/config" "github.com/chihaya/chihaya/server/store" "github.com/chihaya/chihaya/tracker" ) @@ -20,7 +19,7 @@ func init() { // whitelistAnnounceIP provides a middleware that only allows IPs to announce // that are stored in an IPStore. func whitelistAnnounceIP(next tracker.AnnounceHandler) tracker.AnnounceHandler { - return func(cfg *config.TrackerConfig, req *chihaya.AnnounceRequest, resp *chihaya.AnnounceResponse) (err error) { + return func(cfg *chihaya.TrackerConfig, req *chihaya.AnnounceRequest, resp *chihaya.AnnounceResponse) (err error) { whitelisted := false storage := store.MustGetStore() diff --git a/server/store/store.go b/server/store/store.go index 9215af4..801cd56 100644 --- a/server/store/store.go +++ b/server/store/store.go @@ -12,7 +12,7 @@ import ( "gopkg.in/yaml.v2" - "github.com/chihaya/chihaya/config" + "github.com/chihaya/chihaya" "github.com/chihaya/chihaya/server" "github.com/chihaya/chihaya/tracker" ) @@ -23,7 +23,7 @@ func init() { server.Register("store", constructor) } -func constructor(srvcfg *config.ServerConfig, tkr *tracker.Tracker) (server.Server, error) { +func constructor(srvcfg *chihaya.ServerConfig, tkr *tracker.Tracker) (server.Server, error) { if theStore == nil { cfg, err := newConfig(srvcfg) if err != nil { @@ -71,7 +71,7 @@ type Config struct { IPStoreConfig interface{} `yaml:"ip_store_config"` } -func newConfig(srvcfg *config.ServerConfig) (*Config, error) { +func newConfig(srvcfg *chihaya.ServerConfig) (*Config, error) { bytes, err := yaml.Marshal(srvcfg.Config) if err != nil { return nil, err diff --git a/tracker/middleware.go b/tracker/middleware.go index 60e4742..995506b 100644 --- a/tracker/middleware.go +++ b/tracker/middleware.go @@ -1,20 +1,17 @@ // Copyright 2016 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 middleware +// which can be found in the LICENSE file. package tracker -import ( - "github.com/chihaya/chihaya" - "github.com/chihaya/chihaya/config" -) +import "github.com/chihaya/chihaya" // AnnounceHandler is a function that operates on an AnnounceResponse before it // has been delivered to a client. -type AnnounceHandler func(*config.TrackerConfig, *chihaya.AnnounceRequest, *chihaya.AnnounceResponse) error +type AnnounceHandler func(*chihaya.TrackerConfig, *chihaya.AnnounceRequest, *chihaya.AnnounceResponse) error -// AnnounceMiddleware is higher-order AnnounceHandler used to implement modular -// behavior processing an announce. +// AnnounceMiddleware is a higher-order function used to implement the chaining +// of AnnounceHandlers. type AnnounceMiddleware func(AnnounceHandler) AnnounceHandler type announceChain struct{ mw []AnnounceMiddleware } @@ -24,9 +21,10 @@ func (c *announceChain) Append(mw ...AnnounceMiddleware) { } func (c *announceChain) Handler() AnnounceHandler { - final := func(cfg *config.TrackerConfig, req *chihaya.AnnounceRequest, resp *chihaya.AnnounceResponse) error { + final := func(cfg *chihaya.TrackerConfig, req *chihaya.AnnounceRequest, resp *chihaya.AnnounceResponse) error { return nil } + for i := len(c.mw) - 1; i >= 0; i-- { final = c.mw[i](final) } @@ -35,8 +33,8 @@ func (c *announceChain) Handler() AnnounceHandler { var announceMiddleware = make(map[string]AnnounceMiddleware) -// RegisterAnnounceMiddleware makes a middleware available to the tracker under -// the provided named. +// RegisterAnnounceMiddleware makes a middleware globally available under the +// provided named. // // If this function is called twice with the same name or if the handler is nil, // it panics. @@ -52,12 +50,12 @@ func RegisterAnnounceMiddleware(name string, mw AnnounceMiddleware) { announceMiddleware[name] = mw } -// ScrapeHandler is a middleware function that operates on a ScrapeResponse -// before it has been delivered to a client. -type ScrapeHandler func(*config.TrackerConfig, *chihaya.ScrapeRequest, *chihaya.ScrapeResponse) error +// ScrapeHandler is a function that operates on a ScrapeResponse before it has +// been delivered to a client. +type ScrapeHandler func(*chihaya.TrackerConfig, *chihaya.ScrapeRequest, *chihaya.ScrapeResponse) error -// ScrapeMiddleware is higher-order ScrapeHandler used to implement modular -// behavior processing a scrape. +// ScrapeMiddleware is higher-order function used to implement the chaining of +// ScrapeHandlers. type ScrapeMiddleware func(ScrapeHandler) ScrapeHandler type scrapeChain struct{ mw []ScrapeMiddleware } @@ -67,7 +65,7 @@ func (c *scrapeChain) Append(mw ...ScrapeMiddleware) { } func (c *scrapeChain) Handler() ScrapeHandler { - final := func(cfg *config.TrackerConfig, req *chihaya.ScrapeRequest, resp *chihaya.ScrapeResponse) error { + final := func(cfg *chihaya.TrackerConfig, req *chihaya.ScrapeRequest, resp *chihaya.ScrapeResponse) error { return nil } for i := len(c.mw) - 1; i >= 0; i-- { @@ -78,8 +76,8 @@ func (c *scrapeChain) Handler() ScrapeHandler { var scrapeMiddleware = make(map[string]ScrapeMiddleware) -// RegisterScrapeMiddleware makes a middleware available to the tracker under -// the provided named. +// RegisterScrapeMiddleware makes a middleware globally available under the +// provided named. // // If this function is called twice with the same name or if the handler is nil, // it panics. diff --git a/tracker/middleware_test.go b/tracker/middleware_test.go index dfe281e..5fd6011 100644 --- a/tracker/middleware_test.go +++ b/tracker/middleware_test.go @@ -1,6 +1,6 @@ // Copyright 2016 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 middleware +// which can be found in the LICENSE file. package tracker @@ -10,11 +10,10 @@ import ( "github.com/stretchr/testify/assert" "github.com/chihaya/chihaya" - "github.com/chihaya/chihaya/config" ) func testAnnounceMW1(next AnnounceHandler) AnnounceHandler { - return func(cfg *config.TrackerConfig, req *chihaya.AnnounceRequest, resp *chihaya.AnnounceResponse) error { + return func(cfg *chihaya.TrackerConfig, req *chihaya.AnnounceRequest, resp *chihaya.AnnounceResponse) error { resp.IPv4Peers = append(resp.IPv4Peers, chihaya.Peer{ Port: 1, }) @@ -23,7 +22,7 @@ func testAnnounceMW1(next AnnounceHandler) AnnounceHandler { } func testAnnounceMW2(next AnnounceHandler) AnnounceHandler { - return func(cfg *config.TrackerConfig, req *chihaya.AnnounceRequest, resp *chihaya.AnnounceResponse) error { + return func(cfg *chihaya.TrackerConfig, req *chihaya.AnnounceRequest, resp *chihaya.AnnounceResponse) error { resp.IPv4Peers = append(resp.IPv4Peers, chihaya.Peer{ Port: 2, }) @@ -32,7 +31,7 @@ func testAnnounceMW2(next AnnounceHandler) AnnounceHandler { } func testAnnounceMW3(next AnnounceHandler) AnnounceHandler { - return func(cfg *config.TrackerConfig, req *chihaya.AnnounceRequest, resp *chihaya.AnnounceResponse) error { + return func(cfg *chihaya.TrackerConfig, req *chihaya.AnnounceRequest, resp *chihaya.AnnounceResponse) error { resp.IPv4Peers = append(resp.IPv4Peers, chihaya.Peer{ Port: 3, }) @@ -49,5 +48,5 @@ func TestAnnounceChain(t *testing.T) { resp := &chihaya.AnnounceResponse{} err := handler(nil, &chihaya.AnnounceRequest{}, resp) assert.Nil(t, err, "the handler should not return an error") - assert.Equal(t, resp.IPv4Peers, []chihaya.Peer{chihaya.Peer{Port: 1}, chihaya.Peer{Port: 2}, chihaya.Peer{Port: 3}}, "the list of peers added from the middleware should be in the same order.") + assert.Equal(t, resp.IPv4Peers, []chihaya.Peer{{Port: 1}, {Port: 2}, {Port: 3}}, "the list of peers added from the middleware should be in the same order.") } diff --git a/tracker/tracker.go b/tracker/tracker.go index 389e36f..e4cc7b2 100644 --- a/tracker/tracker.go +++ b/tracker/tracker.go @@ -1,31 +1,35 @@ // Copyright 2016 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 middleware +// which can be found in the LICENSE file. +// Package tracker implements a protocol-independent, middleware-composed +// BitTorrent tracker. package tracker import ( "errors" "github.com/chihaya/chihaya" - "github.com/chihaya/chihaya/config" ) +// ClientError represents an error that should be exposed to the client over +// the BitTorrent protocol implementation. type ClientError string +// Error implements the error interface for ClientError. func (c ClientError) Error() string { return string(c) } -// Tracker represents a protocol independent, middleware-composed BitTorrent +// Tracker represents a protocol-independent, middleware-composed BitTorrent // tracker. type Tracker struct { - cfg *config.TrackerConfig + cfg *chihaya.TrackerConfig handleAnnounce AnnounceHandler handleScrape ScrapeHandler } -// NewTracker parses a config and generates a Tracker composed by the middleware -// specified in the config. -func NewTracker(cfg *config.TrackerConfig) (*Tracker, error) { +// NewTracker constructs a newly allocated Tracker composed of the middleware +// in the provided configuration. +func NewTracker(cfg *chihaya.TrackerConfig) (*Tracker, error) { var achain announceChain for _, mwName := range cfg.AnnounceMiddleware { mw, ok := announceMiddleware[mwName] @@ -51,7 +55,7 @@ func NewTracker(cfg *config.TrackerConfig) (*Tracker, error) { }, nil } -// HandleAnnounce runs an AnnounceRequest through a Tracker's middleware and +// HandleAnnounce runs an AnnounceRequest through the Tracker's middleware and // returns the result. func (t *Tracker) HandleAnnounce(req *chihaya.AnnounceRequest) (*chihaya.AnnounceResponse, error) { resp := &chihaya.AnnounceResponse{} @@ -59,8 +63,8 @@ func (t *Tracker) HandleAnnounce(req *chihaya.AnnounceRequest) (*chihaya.Announc return resp, err } -// HandleScrape runs a ScrapeRequest through a Tracker's middleware and returns -// the result. +// HandleScrape runs a ScrapeRequest through the Tracker's middleware and +// returns the result. func (t *Tracker) HandleScrape(req *chihaya.ScrapeRequest) (*chihaya.ScrapeResponse, error) { resp := &chihaya.ScrapeResponse{} err := t.handleScrape(t.cfg, req, resp)