Resolve race condition issues
This commit is contained in:
@@ -19,6 +19,7 @@ type ConfigInterface interface {
|
||||
MeetsConditions(directory, torrentID, torrentName string, fileNames []string) bool
|
||||
GetOnLibraryUpdate() string
|
||||
GetNetworkBufferSize() int
|
||||
GetMountPath() string
|
||||
}
|
||||
|
||||
func LoadZurgConfig(filename string) (ConfigInterface, error) {
|
||||
|
||||
@@ -10,6 +10,7 @@ type ZurgConfig struct {
|
||||
CanRepair bool `yaml:"enable_repair"`
|
||||
OnLibraryUpdate string `yaml:"on_library_update"`
|
||||
NetworkBufferSize int `yaml:"network_buffer_size"`
|
||||
MountPath string `yaml:"mount_path"`
|
||||
}
|
||||
|
||||
func (z *ZurgConfig) GetToken() string {
|
||||
@@ -55,3 +56,7 @@ func (z *ZurgConfig) GetNetworkBufferSize() int {
|
||||
}
|
||||
return z.NetworkBufferSize
|
||||
}
|
||||
|
||||
func (z *ZurgConfig) GetMountPath() string {
|
||||
return z.MountPath
|
||||
}
|
||||
|
||||
38
internal/mount/mount.go
Normal file
38
internal/mount/mount.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package mount
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
"os"
|
||||
|
||||
"bazil.org/fuse"
|
||||
"github.com/mdlayher/sdnotify"
|
||||
)
|
||||
|
||||
func Mount(mountpoint string) error {
|
||||
n, err := sdnotify.New()
|
||||
if err != nil && !errors.Is(err, os.ErrNotExist) {
|
||||
log.Fatalf("failed to open systemd notifier: %v", err)
|
||||
}
|
||||
err = n.Notify(
|
||||
sdnotify.Statusf("service started successfully"),
|
||||
sdnotify.Ready,
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to send ready notification: %v", err)
|
||||
}
|
||||
return Unmount(mountpoint, n)
|
||||
}
|
||||
|
||||
func Unmount(mountpoint string, n *sdnotify.Notifier) error {
|
||||
log.Println("Unmounting...")
|
||||
err := n.Notify(
|
||||
sdnotify.Statusf("service stopped successfully"),
|
||||
sdnotify.Ready,
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to send stop notification: %v", err)
|
||||
}
|
||||
fuse.Unmount(mountpoint)
|
||||
return nil
|
||||
}
|
||||
@@ -16,33 +16,41 @@ import (
|
||||
)
|
||||
|
||||
type TorrentManager struct {
|
||||
requiredVersion string
|
||||
torrents []Torrent
|
||||
inProgress []string
|
||||
checksum string
|
||||
config config.ConfigInterface
|
||||
cache *expirable.LRU[string, string]
|
||||
workerPool chan bool
|
||||
TorrentDirectoriesMap map[string][]string
|
||||
processedTorrents map[string][]string
|
||||
requiredVersion string
|
||||
torrents []Torrent
|
||||
inProgress []string
|
||||
checksum string
|
||||
config config.ConfigInterface
|
||||
cache *expirable.LRU[string, string]
|
||||
workerPool chan bool
|
||||
directoryMap map[string][]string
|
||||
processedTorrents map[string][]string
|
||||
mu *sync.Mutex
|
||||
}
|
||||
|
||||
// NewTorrentManager creates a new torrent manager
|
||||
// it will fetch all torrents and their info in the background
|
||||
// and store them in-memory
|
||||
// and store them in-memory; it is called only once at startup
|
||||
func NewTorrentManager(config config.ConfigInterface, cache *expirable.LRU[string, string]) *TorrentManager {
|
||||
t := &TorrentManager{
|
||||
requiredVersion: "28.10.2023",
|
||||
config: config,
|
||||
cache: cache,
|
||||
workerPool: make(chan bool, config.GetNumOfWorkers()),
|
||||
TorrentDirectoriesMap: make(map[string][]string),
|
||||
processedTorrents: make(map[string][]string),
|
||||
requiredVersion: "4.11.2023",
|
||||
config: config,
|
||||
cache: cache,
|
||||
workerPool: make(chan bool, config.GetNumOfWorkers()),
|
||||
directoryMap: make(map[string][]string),
|
||||
processedTorrents: make(map[string][]string),
|
||||
mu: &sync.Mutex{},
|
||||
}
|
||||
|
||||
// Initialize torrents for the first time
|
||||
log.Println("Initializing torrents")
|
||||
t.mu.Lock()
|
||||
log.Println("Fetching torrents")
|
||||
t.torrents = t.getFreshListFromAPI()
|
||||
t.checksum = t.getChecksum()
|
||||
t.mu.Unlock()
|
||||
log.Println("Finished fetching torrents")
|
||||
|
||||
// log.Println("First checksum", t.checksum)
|
||||
|
||||
var wg sync.WaitGroup
|
||||
@@ -72,7 +80,7 @@ func NewTorrentManager(config config.ConfigInterface, cache *expirable.LRU[strin
|
||||
func (t *TorrentManager) GetByDirectory(directory string) []Torrent {
|
||||
var torrents []Torrent
|
||||
for i := range t.torrents {
|
||||
for _, dir := range t.TorrentDirectoriesMap[t.torrents[i].Name] {
|
||||
for _, dir := range t.directoryMap[t.torrents[i].Name] {
|
||||
if dir == directory {
|
||||
torrents = append(torrents, t.torrents[i])
|
||||
}
|
||||
@@ -195,8 +203,11 @@ func (t *TorrentManager) startRefreshJob() {
|
||||
wg.Wait()
|
||||
|
||||
// apply side effects
|
||||
t.mu.Lock()
|
||||
t.torrents = newTorrents
|
||||
t.checksum = t.getChecksum()
|
||||
t.mu.Unlock()
|
||||
|
||||
// log.Println("Checksum changed", t.checksum)
|
||||
if t.config.EnableRepair() {
|
||||
go t.repairAll(&wg)
|
||||
@@ -223,6 +234,8 @@ func (t *TorrentManager) getFreshListFromAPI() []Torrent {
|
||||
torrentV2 := Torrent{
|
||||
Torrent: torrent,
|
||||
SelectedFiles: nil,
|
||||
ForRepair: false,
|
||||
lock: &sync.Mutex{},
|
||||
}
|
||||
torrentsV2 = append(torrentsV2, torrentV2)
|
||||
|
||||
@@ -361,7 +374,7 @@ func (t *TorrentManager) mapToDirectories() {
|
||||
if configV1.MeetsConditions(directory, t.torrents[i].ID, t.torrents[i].Name, filenames) {
|
||||
found := false
|
||||
// check if it is already mapped to this directory
|
||||
for _, dir := range t.TorrentDirectoriesMap[t.torrents[i].Name] {
|
||||
for _, dir := range t.directoryMap[t.torrents[i].Name] {
|
||||
if dir == directory {
|
||||
found = true
|
||||
break // it is already mapped to this directory
|
||||
@@ -369,12 +382,16 @@ func (t *TorrentManager) mapToDirectories() {
|
||||
}
|
||||
if !found {
|
||||
counter[directory]++
|
||||
t.TorrentDirectoriesMap[t.torrents[i].Name] = append(t.TorrentDirectoriesMap[t.torrents[i].Name], directory)
|
||||
t.mu.Lock()
|
||||
t.directoryMap[t.torrents[i].Name] = append(t.directoryMap[t.torrents[i].Name], directory)
|
||||
t.mu.Unlock()
|
||||
break // we found a directory for this torrent, so we can stop looking for more
|
||||
}
|
||||
}
|
||||
}
|
||||
t.mu.Lock()
|
||||
t.processedTorrents[t.torrents[i].Name] = append(t.processedTorrents[t.torrents[i].Name], group)
|
||||
t.mu.Unlock()
|
||||
}
|
||||
sum := 0
|
||||
for _, count := range counter {
|
||||
@@ -439,7 +456,6 @@ func (t *TorrentManager) readFromFile(torrentID string) *Torrent {
|
||||
dataDecoder := gob.NewDecoder(file)
|
||||
err = dataDecoder.Decode(&torrent)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed decoding file: %s", err)
|
||||
return nil
|
||||
}
|
||||
if torrent.Version != t.requiredVersion {
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
package torrent
|
||||
|
||||
import "github.com/debridmediamanager.com/zurg/pkg/realdebrid"
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/debridmediamanager.com/zurg/pkg/realdebrid"
|
||||
)
|
||||
|
||||
type Torrent struct {
|
||||
Version string
|
||||
realdebrid.Torrent
|
||||
SelectedFiles []File
|
||||
ForRepair bool
|
||||
lock *sync.Mutex
|
||||
}
|
||||
|
||||
type File struct {
|
||||
|
||||
Reference in New Issue
Block a user