remove register pattern for hooks
This commit is contained in:
parent
9a8cdccc6c
commit
732b2d536e
3 changed files with 77 additions and 83 deletions
|
@ -14,70 +14,109 @@
|
||||||
|
|
||||||
// Package trakr implements a BitTorrent Tracker that supports multiple
|
// Package trakr implements a BitTorrent Tracker that supports multiple
|
||||||
// protocols and configurable Hooks that execute before and after a Response
|
// protocols and configurable Hooks that execute before and after a Response
|
||||||
// has been delievered to a BitTorrent client.
|
// has been delivered to a BitTorrent client.
|
||||||
package backend
|
package backend
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"log"
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
"github.com/jzelinskie/trakr/bittorrent"
|
"github.com/jzelinskie/trakr/bittorrent"
|
||||||
"github.com/jzelinskie/trakr/frontend"
|
"github.com/jzelinskie/trakr/frontend"
|
||||||
"golang.org/x/net/context"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// GenericConfig is a block of configuration who's structure is unknown.
|
|
||||||
type GenericConfig struct {
|
|
||||||
name string `yaml:"name"`
|
|
||||||
config interface{} `yaml:"config"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type BackendConfig struct {
|
type BackendConfig struct {
|
||||||
AnnounceInterval time.Duration `yaml:"announce_interval"`
|
AnnounceInterval time.Duration `yaml:"announce_interval"`
|
||||||
PreHooks []GenericConfig `yaml:"prehooks"`
|
|
||||||
PostHooks []GenericConfig `yaml:"posthooks"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var _ frontend.TrackerFuncs = &Backend{}
|
var _ frontend.TrackerFuncs = &Backend{}
|
||||||
|
|
||||||
func New(config BackendConfig, peerStore PeerStore) (*Backend, error) {
|
func New(config BackendConfig, peerStore PeerStore, announcePreHooks, announcePostHooks, scrapePreHooks, scrapePostHooks []Hook) (*Backend, error) {
|
||||||
// Build TrackerFuncs from the PreHooks and PostHooks
|
toReturn := &Backend{
|
||||||
return &Backend{peerStore: peerStore}, nil
|
announceInterval: config.AnnounceInterval,
|
||||||
|
peerStore: peerStore,
|
||||||
|
announcePreHooks: announcePreHooks,
|
||||||
|
announcePostHooks: announcePostHooks,
|
||||||
|
scrapePreHooks: scrapePreHooks,
|
||||||
|
scrapePostHooks: scrapePostHooks,
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(toReturn.announcePreHooks) == 0 {
|
||||||
|
toReturn.announcePreHooks = []Hook{nopHook{}}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(toReturn.announcePostHooks) == 0 {
|
||||||
|
toReturn.announcePostHooks = []Hook{nopHook{}}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(toReturn.scrapePreHooks) == 0 {
|
||||||
|
toReturn.scrapePreHooks = []Hook{nopHook{}}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(toReturn.scrapePostHooks) == 0 {
|
||||||
|
toReturn.scrapePostHooks = []Hook{nopHook{}}
|
||||||
|
}
|
||||||
|
|
||||||
|
return toReturn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Backend is a multi-protocol, customizable BitTorrent Tracker.
|
// Backend is a protocol-agnostic backend of a BitTorrent tracker.
|
||||||
type Backend struct {
|
type Backend struct {
|
||||||
peerStore PeerStore
|
announceInterval time.Duration
|
||||||
handleAnnounce func(context.Context, *bittorrent.AnnounceRequest) (*bittorrent.AnnounceResponse, error)
|
peerStore PeerStore
|
||||||
afterAnnounce func(context.Context, *bittorrent.AnnounceRequest, *bittorrent.AnnounceResponse) error
|
announcePreHooks []Hook
|
||||||
handleScrape func(context.Context, *bittorrent.ScrapeRequest) (*bittorrent.ScrapeResponse, error)
|
announcePostHooks []Hook
|
||||||
afterScrape func(context.Context, *bittorrent.ScrapeRequest, *bittorrent.ScrapeResponse) error
|
scrapePreHooks []Hook
|
||||||
|
scrapePostHooks []Hook
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleAnnounce generates a response for an Announce.
|
// HandleAnnounce generates a response for an Announce.
|
||||||
func (b *Backend) HandleAnnounce(ctx context.Context, req *bittorrent.AnnounceRequest) (*bittorrent.AnnounceResponse, error) {
|
func (b *Backend) HandleAnnounce(ctx context.Context, req *bittorrent.AnnounceRequest) (*bittorrent.AnnounceResponse, error) {
|
||||||
return b.handleAnnounce(ctx, req)
|
resp := &bittorrent.AnnounceResponse{
|
||||||
|
Interval: b.announceInterval,
|
||||||
|
}
|
||||||
|
for _, h := range b.announcePreHooks {
|
||||||
|
if err := h.HandleAnnounce(ctx, req, resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AfterAnnounce does something with the results of an Announce after it
|
// AfterAnnounce does something with the results of an Announce after it
|
||||||
// has been completed.
|
// has been completed.
|
||||||
func (b *Backend) AfterAnnounce(ctx context.Context, req *bittorrent.AnnounceRequest, resp *bittorrent.AnnounceResponse) {
|
func (b *Backend) AfterAnnounce(ctx context.Context, req *bittorrent.AnnounceRequest, resp *bittorrent.AnnounceResponse) {
|
||||||
err := b.afterAnnounce(ctx, req, resp)
|
for _, h := range b.announcePostHooks {
|
||||||
if err != nil {
|
if err := h.HandleAnnounce(ctx, req, resp); err != nil {
|
||||||
log.Println("trakr: post-announce hooks failed:", err.Error())
|
log.Println("trakr: post-announce hooks failed:", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// HandleScrape generates a response for a Scrape.
|
// HandleScrape generates a response for a Scrape.
|
||||||
func (b *Backend) HandleScrape(ctx context.Context, req *bittorrent.ScrapeRequest) (*bittorrent.ScrapeResponse, error) {
|
func (b *Backend) HandleScrape(ctx context.Context, req *bittorrent.ScrapeRequest) (*bittorrent.ScrapeResponse, error) {
|
||||||
return b.handleScrape(ctx, req)
|
resp := &bittorrent.ScrapeResponse{
|
||||||
|
Files: make(map[bittorrent.InfoHash]bittorrent.Scrape),
|
||||||
|
}
|
||||||
|
for _, h := range b.scrapePreHooks {
|
||||||
|
if err := h.HandleScrape(ctx, req, resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// AfterScrape does something with the results of a Scrape after it has been completed.
|
// AfterScrape does something with the results of a Scrape after it has been completed.
|
||||||
func (b *Backend) AfterScrape(ctx context.Context, req *bittorrent.ScrapeRequest, resp *bittorrent.ScrapeResponse) {
|
func (b *Backend) AfterScrape(ctx context.Context, req *bittorrent.ScrapeRequest, resp *bittorrent.ScrapeResponse) {
|
||||||
err := b.afterScrape(ctx, req, resp)
|
for _, h := range b.scrapePostHooks {
|
||||||
if err != nil {
|
if err := h.HandleScrape(ctx, req, resp); err != nil {
|
||||||
log.Println("trakr: post-scrape hooks failed:", err.Error())
|
log.Println("trakr: post-scrape hooks failed:", err.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,8 +15,6 @@
|
||||||
package backend
|
package backend
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
|
|
||||||
"golang.org/x/net/context"
|
"golang.org/x/net/context"
|
||||||
|
|
||||||
"github.com/jzelinskie/trakr/bittorrent"
|
"github.com/jzelinskie/trakr/bittorrent"
|
||||||
|
@ -29,55 +27,12 @@ type Hook interface {
|
||||||
HandleScrape(context.Context, *bittorrent.ScrapeRequest, *bittorrent.ScrapeResponse) error
|
HandleScrape(context.Context, *bittorrent.ScrapeRequest, *bittorrent.ScrapeResponse) error
|
||||||
}
|
}
|
||||||
|
|
||||||
// HookConstructor is a function used to create a new instance of a Hook.
|
type nopHook struct{}
|
||||||
type HookConstructor func(interface{}) (Hook, error)
|
|
||||||
|
|
||||||
var preHooks = make(map[string]HookConstructor)
|
func (nopHook) HandleAnnounce(context.Context, *bittorrent.AnnounceRequest, *bittorrent.AnnounceResponse) error {
|
||||||
|
return nil
|
||||||
// RegisterPreHook makes a HookConstructor available by the provided name.
|
|
||||||
//
|
|
||||||
// If this function is called twice with the same name or if the
|
|
||||||
// HookConstructor is nil, it panics.
|
|
||||||
func RegisterPreHook(name string, con HookConstructor) {
|
|
||||||
if con == nil {
|
|
||||||
panic("trakr: could not register nil HookConstructor")
|
|
||||||
}
|
|
||||||
if _, dup := preHooks[name]; dup {
|
|
||||||
panic("trakr: could not register duplicate HookConstructor: " + name)
|
|
||||||
}
|
|
||||||
preHooks[name] = con
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewPreHook creates an instance of the given PreHook by name.
|
func (nopHook) HandleScrape(context.Context, *bittorrent.ScrapeRequest, *bittorrent.ScrapeResponse) error {
|
||||||
func NewPreHook(name string, config interface{}) (Hook, error) {
|
return nil
|
||||||
con, ok := preHooks[name]
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("trakr: unknown PreHook %q (forgotten import?)", name)
|
|
||||||
}
|
|
||||||
return con(config)
|
|
||||||
}
|
|
||||||
|
|
||||||
var postHooks = make(map[string]HookConstructor)
|
|
||||||
|
|
||||||
// RegisterPostHook makes a HookConstructor available by the provided name.
|
|
||||||
//
|
|
||||||
// If this function is called twice with the same name or if the
|
|
||||||
// HookConstructor is nil, it panics.
|
|
||||||
func RegisterPostHook(name string, con HookConstructor) {
|
|
||||||
if con == nil {
|
|
||||||
panic("trakr: could not register nil HookConstructor")
|
|
||||||
}
|
|
||||||
if _, dup := postHooks[name]; dup {
|
|
||||||
panic("trakr: could not register duplicate HookConstructor: " + name)
|
|
||||||
}
|
|
||||||
preHooks[name] = con
|
|
||||||
}
|
|
||||||
|
|
||||||
// NewPostHook creates an instance of the given PostHook by name.
|
|
||||||
func NewPostHook(name string, config interface{}) (Hook, error) {
|
|
||||||
con, ok := preHooks[name]
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("trakr: unknown PostHook %q (forgotten import?)", name)
|
|
||||||
}
|
|
||||||
return con(config)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@ import (
|
||||||
"gopkg.in/yaml.v2"
|
"gopkg.in/yaml.v2"
|
||||||
|
|
||||||
"github.com/jzelinskie/trakr/backend"
|
"github.com/jzelinskie/trakr/backend"
|
||||||
|
|
||||||
httpfrontend "github.com/jzelinskie/trakr/frontend/http"
|
httpfrontend "github.com/jzelinskie/trakr/frontend/http"
|
||||||
udpfrontend "github.com/jzelinskie/trakr/frontend/udp"
|
udpfrontend "github.com/jzelinskie/trakr/frontend/udp"
|
||||||
)
|
)
|
||||||
|
@ -95,7 +94,8 @@ func main() {
|
||||||
}()
|
}()
|
||||||
|
|
||||||
// TODO create PeerStore
|
// TODO create PeerStore
|
||||||
trackerBackend, err := backend.New(configFile.Config.BackendConfig, nil)
|
// TODO create Hooks
|
||||||
|
trackerBackend, err := backend.New(configFile.Config.BackendConfig, nil, nil, nil, nil, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,7 @@ func main() {
|
||||||
|
|
||||||
if configFile.Config.HTTPConfig.Addr != "" {
|
if configFile.Config.HTTPConfig.Addr != "" {
|
||||||
// TODO get the real TrackerFuncs
|
// TODO get the real TrackerFuncs
|
||||||
hFrontend = httpfrontend.NewFrontend(trackerBackend.TrackerFuncs, configFile.Config.HTTPConfig)
|
hFrontend = httpfrontend.NewFrontend(trackerBackend, configFile.Config.HTTPConfig)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
log.Println("started serving HTTP on", configFile.Config.HTTPConfig.Addr)
|
log.Println("started serving HTTP on", configFile.Config.HTTPConfig.Addr)
|
||||||
|
@ -120,7 +120,7 @@ func main() {
|
||||||
|
|
||||||
if configFile.Config.UDPConfig.Addr != "" {
|
if configFile.Config.UDPConfig.Addr != "" {
|
||||||
// TODO get the real TrackerFuncs
|
// TODO get the real TrackerFuncs
|
||||||
uFrontend = udpfrontend.NewFrontend(trackerBackend.TrackerFuncs, configFile.Config.UDPConfig)
|
uFrontend = udpfrontend.NewFrontend(trackerBackend, configFile.Config.UDPConfig)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
log.Println("started serving UDP on", configFile.Config.UDPConfig.Addr)
|
log.Println("started serving UDP on", configFile.Config.UDPConfig.Addr)
|
||||||
|
|
Loading…
Add table
Reference in a new issue