diff --git a/frontend/http/writer.go b/frontend/http/writer.go index aed1c69..4adbbda 100644 --- a/frontend/http/writer.go +++ b/frontend/http/writer.go @@ -1,7 +1,7 @@ package http import ( - "github.com/zeebo/bencode" + "github.com/anacrolix/torrent/bencode" "net/http" "github.com/chihaya/chihaya/bittorrent" diff --git a/go.mod b/go.mod index e493164..47485dc 100644 --- a/go.mod +++ b/go.mod @@ -7,7 +7,6 @@ require ( github.com/alicebob/gopher-json v0.0.0-20180125190556-5a6b3ba71ee6 // indirect github.com/alicebob/miniredis v2.5.0+incompatible github.com/anacrolix/torrent v1.28.0 - github.com/fsnotify/fsnotify v1.4.9 github.com/go-redsync/redsync v1.4.2 github.com/gomodule/redigo v2.0.0+incompatible github.com/julienschmidt/httprouter v1.3.0 @@ -19,6 +18,5 @@ require ( github.com/spf13/cobra v1.1.3 github.com/stretchr/testify v1.7.0 github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb // indirect - github.com/zeebo/bencode v1.0.0 gopkg.in/yaml.v2 v2.4.0 ) diff --git a/middleware/torrentapproval/container/container.go b/middleware/torrentapproval/container/container.go index aa5d684..9f6648d 100644 --- a/middleware/torrentapproval/container/container.go +++ b/middleware/torrentapproval/container/container.go @@ -8,28 +8,30 @@ import ( "sync" ) -type Builder interface { - New() (Container, error) +type Constructor func () Configuration + +type Configuration interface { + Build() (Container, error) } var ( - buildersMU sync.Mutex - builders = make(map[string]Builder) + constructorsMU sync.Mutex + constructors = make(map[string]Constructor) ErrContainerDoesNotExist = errors.New("torrent hash container with that name does not exist") ) -func Register(n string, c Builder) { +func Register(n string, c Constructor) { if len(n) == 0 { panic("middleware: could not register a Container with an empty name") } if c == nil { - panic("middleware: could not register a Container with nil builder") + panic("middleware: could not register a Container with nil builder constructor") } - buildersMU.Lock() - defer buildersMU.Unlock() - builders[n] = c + constructorsMU.Lock() + defer constructorsMU.Unlock() + constructors[n] = c } type Container interface { @@ -38,15 +40,16 @@ type Container interface { } func GetContainer(name string, confBytes []byte) (Container, error) { - buildersMU.Lock() - defer buildersMU.Unlock() + constructorsMU.Lock() + defer constructorsMU.Unlock() var err error var cn Container - if builder, exist := builders[name]; !exist { + if getConfig, exist := constructors[name]; !exist { err = ErrContainerDoesNotExist } else { - if err = yaml.Unmarshal(confBytes, &cn); err == nil { - cn, err = builder.New() + conf := getConfig() + if err = yaml.Unmarshal(confBytes, &conf); err == nil { + cn, err = conf.Build() } } return cn, err diff --git a/middleware/torrentapproval/container/directory/directory.go b/middleware/torrentapproval/container/directory/directory.go index f3dbd61..e95de54 100644 --- a/middleware/torrentapproval/container/directory/directory.go +++ b/middleware/torrentapproval/container/directory/directory.go @@ -2,103 +2,65 @@ package directory import ( "fmt" - "github.com/chihaya/chihaya/bittorrent" + "github.com/anacrolix/torrent/util/dirwatch" "github.com/chihaya/chihaya/middleware/torrentapproval/container" "github.com/chihaya/chihaya/middleware/torrentapproval/container/list" - "github.com/chihaya/chihaya/pkg/log" "github.com/chihaya/chihaya/pkg/stop" - "github.com/fsnotify/fsnotify" - "os" - "path/filepath" "sync" ) func init() { - container.Register("list", builder{}) + container.Register("list", func() container.Configuration { + return Config{} + }) } -type builder struct { +type Config struct { WhitelistPath string `yaml:"whitelist_path"` BlacklistPath string `yaml:"blacklist_path"` } -func (b builder) New() (container.Container, error) { +func (b Config) Build() (container.Container, error) { if len(b.WhitelistPath) > 0 && len(b.BlacklistPath) > 0 { return nil, fmt.Errorf("using both whitelist and blacklist is invalid") } var err error - dirLister := &directory{ + lst := &directory{ List: list.List{ Hashes: sync.Map{}, Invert: len(b.WhitelistPath) == 0, }, - files: sync.Map{}, - root: b.WhitelistPath, watcher: nil, } - if dirLister.Invert { - dirLister.root = b.BlacklistPath + dir := b.WhitelistPath + if lst.Invert { + dir = b.BlacklistPath } - var w *fsnotify.Watcher - if w, err = fsnotify.NewWatcher(); err != nil { - return nil, fmt.Errorf("unable to initialize fsnotify mechanism") + var w *dirwatch.Instance + w, err = dirwatch.New(dir) + if w, err = dirwatch.New(dir); err != nil { + return nil, fmt.Errorf("unable to initialize directory watch") } - if dirContent, err := os.ReadDir(dirLister.root); err != nil { - return nil, err - } else { - for _, f := range dirContent { - if !f.IsDir() { - if err = dirLister.processFile(f.Name(), false); err != nil { - log.Warn(err) - } + lst.watcher = w + go func() { + for event := range lst.watcher.Events { + switch event.Change { + case dirwatch.Added: + lst.Hashes.Store(event.InfoHash, list.DUMMY) + case dirwatch.Removed: + lst.Hashes.Delete(event.InfoHash) } } - } - if err = w.Add(dirLister.root); err != nil { - _ = w.Close() - dirLister = nil - } - return dirLister, err -} - -func (d *directory) watch() { - go func() { - for err := range d.watcher.Errors { - log.Error(err) - } }() - go func() { - for event := range d.watcher.Events { - log.Debug(event.String()) - //todo: implement event type parsing - } - }() -} - -func (d *directory) processFile(name string, delete bool) error { - fullName := filepath.Join(d.root, name) - if delete { - if hash, found := d.files.Load(fullName); found{ - d.Hashes.Delete(hash) - } - } else { - var hashBytes []byte - info := bittorrent.InfoHashFromBytes(hashBytes) - d.files.Store(fullName, info) - d.Hashes.Store(info, list.DUMMY) - } - return nil + return lst, err } type directory struct { list.List - files sync.Map - root string - watcher *fsnotify.Watcher + watcher *dirwatch.Instance } func (d *directory) Stop() stop.Result { - ch := make(stop.Channel) - go ch.Done(d.watcher.Close()) - return ch.Result() + d.watcher.Close() + return stop.AlreadyStopped } diff --git a/middleware/torrentapproval/container/list/list.go b/middleware/torrentapproval/container/list/list.go index 6c5f022..fd948c2 100644 --- a/middleware/torrentapproval/container/list/list.go +++ b/middleware/torrentapproval/container/list/list.go @@ -10,29 +10,31 @@ import ( ) func init() { - container.Register("list", Builder{}) + container.Register("list", func() container.Configuration { + return Config{} + }) } -type Builder struct { +type Config struct { Whitelist []string `yaml:"whitelist"` Blacklist []string `yaml:"blacklist"` } var DUMMY struct{} -func (b Builder) New() (container.Container, error) { - if len(b.Whitelist) > 0 && len(b.Blacklist) > 0 { +func (c Config) Build() (container.Container, error) { + if len(c.Whitelist) > 0 && len(c.Blacklist) > 0 { return nil, fmt.Errorf("using both whitelist and blacklist is invalid") } l := &List{ Hashes: sync.Map{}, - Invert: len(b.Whitelist) == 0, + Invert: len(c.Whitelist) == 0, } - hashList := b.Whitelist + hashList := c.Whitelist if l.Invert { l.Invert = true - hashList = b.Blacklist + hashList = c.Blacklist } for _, hashString := range hashList { diff --git a/middleware/torrentapproval/torrentapproval_test.go b/middleware/torrentapproval/torrentapproval_test.go index 72ad41f..16da4b3 100644 --- a/middleware/torrentapproval/torrentapproval_test.go +++ b/middleware/torrentapproval/torrentapproval_test.go @@ -4,6 +4,8 @@ import ( "context" "encoding/hex" "fmt" + "github.com/chihaya/chihaya/middleware" + "gopkg.in/yaml.v2" "testing" "github.com/stretchr/testify/require" @@ -12,38 +14,50 @@ import ( ) var cases = []struct { - cfg Config + cfg middleware.Config ih string approved bool }{ // Infohash is whitelisted { - Config{ - Whitelist: []string{"3532cf2d327fad8448c075b4cb42c8136964a435"}, + middleware.Config{ + Name: "list", + Options: map[string]interface{}{ + "Whitelist": []string{"3532cf2d327fad8448c075b4cb42c8136964a435"}, + }, }, "3532cf2d327fad8448c075b4cb42c8136964a435", true, }, // Infohash is not whitelisted { - Config{ - Whitelist: []string{"3532cf2d327fad8448c075b4cb42c8136964a435"}, + middleware.Config{ + Name: "list", + Options: map[string]interface{}{ + "Whitelist": []string{"3532cf2d327fad8448c075b4cb42c8136964a435"}, + }, }, "4532cf2d327fad8448c075b4cb42c8136964a435", false, }, // Infohash is not blacklisted { - Config{ - Blacklist: []string{"3532cf2d327fad8448c075b4cb42c8136964a435"}, + middleware.Config{ + Name: "list", + Options: map[string]interface{}{ + "Blacklist": []string{"3532cf2d327fad8448c075b4cb42c8136964a435"}, + }, }, "4532cf2d327fad8448c075b4cb42c8136964a435", true, }, // Infohash is blacklisted { - Config{ - Blacklist: []string{"3532cf2d327fad8448c075b4cb42c8136964a435"}, + middleware.Config{ + Name: "list", + Options: map[string]interface{}{ + "Blacklist": []string{"3532cf2d327fad8448c075b4cb42c8136964a435"}, + }, }, "3532cf2d327fad8448c075b4cb42c8136964a435", false, @@ -53,7 +67,10 @@ var cases = []struct { func TestHandleAnnounce(t *testing.T) { for _, tt := range cases { t.Run(fmt.Sprintf("testing hash %s", tt.ih), func(t *testing.T) { - h, err := NewHook(tt.cfg) + d := driver{} + cfg, err := yaml.Marshal(tt) + require.Nil(t, err) + h, err := d.NewHook(cfg) require.Nil(t, err) ctx := context.Background()