package store import ( "errors" "path/filepath" "sync" "github.com/anacrolix/torrent" "github.com/anacrolix/torrent/metainfo" "github.com/philippgille/gokv" "github.com/philippgille/gokv/badgerdb" "github.com/philippgille/gokv/encoding" ) func NewExcludedFiles(metaDir string, storage TorrentFileDeleter) (*ExlcudedFiles, error) { excludedFilesStore, err := badgerdb.NewStore(badgerdb.Options{ Dir: filepath.Join(metaDir, "excluded-files"), Codec: encoding.JSON, }) if err != nil { return nil, err } r := &ExlcudedFiles{ excludedFiles: excludedFilesStore, storage: storage, } return r, nil } type ExlcudedFiles struct { m sync.RWMutex excludedFiles gokv.Store storage TorrentFileDeleter } var ErrNotFound = errors.New("not found") type TorrentFileDeleter interface { DeleteFile(file *torrent.File) error } func (r *ExlcudedFiles) ExcludeFile(file *torrent.File) error { r.m.Lock() defer r.m.Unlock() hash := file.Torrent().InfoHash() var excludedFiles []string found, err := r.excludedFiles.Get(hash.AsString(), &excludedFiles) if err != nil { return err } if !found { excludedFiles = []string{} } excludedFiles = unique(append(excludedFiles, file.Path())) err = r.storage.DeleteFile(file) if err != nil { return err } return r.excludedFiles.Set(hash.AsString(), excludedFiles) } func (r *ExlcudedFiles) ExcludedFiles(hash metainfo.Hash) ([]string, error) { r.m.Lock() defer r.m.Unlock() var excludedFiles []string found, err := r.excludedFiles.Get(hash.AsString(), &excludedFiles) if err != nil { return nil, err } if !found { return nil, nil } return excludedFiles, nil } func unique[C comparable](intSlice []C) []C { keys := make(map[C]bool) list := []C{} for _, entry := range intSlice { if _, value := keys[entry]; !value { keys[entry] = true list = append(list, entry) } } return list }