chore: rename module from torrentclaw-cli to unarr
- Rename Go module path github.com/torrentclaw/torrentclaw-cli → github.com/torrentclaw/unarr - Update all imports, ldflags, scripts, docs, and Docker config - Add GitHub Actions release workflow (goreleaser on tag push)
This commit is contained in:
parent
9cc806d11f
commit
5a7449b9e6
58 changed files with 166 additions and 141 deletions
|
|
@ -5,7 +5,7 @@ import (
|
|||
"log"
|
||||
"sync"
|
||||
|
||||
"github.com/torrentclaw/torrentclaw-cli/internal/agent"
|
||||
"github.com/torrentclaw/unarr/internal/agent"
|
||||
)
|
||||
|
||||
// ManagerConfig holds download manager settings.
|
||||
|
|
@ -24,6 +24,7 @@ type Manager struct {
|
|||
|
||||
activeMu sync.RWMutex
|
||||
active map[string]*Task
|
||||
cancels map[string]context.CancelFunc // per-task cancel functions
|
||||
|
||||
sem chan struct{}
|
||||
wg sync.WaitGroup
|
||||
|
|
@ -45,6 +46,7 @@ func NewManager(cfg ManagerConfig, reporter *ProgressReporter, downloaders ...Do
|
|||
reporter: reporter,
|
||||
downloaders: dlMap,
|
||||
active: make(map[string]*Task),
|
||||
cancels: make(map[string]context.CancelFunc),
|
||||
sem: make(chan struct{}, cfg.MaxConcurrent),
|
||||
}
|
||||
}
|
||||
|
|
@ -53,8 +55,12 @@ func NewManager(cfg ManagerConfig, reporter *ProgressReporter, downloaders ...Do
|
|||
func (m *Manager) Submit(ctx context.Context, at agent.Task) {
|
||||
task := NewTaskFromAgent(at)
|
||||
|
||||
// Per-task cancellable context so CancelTask can unblock the goroutine
|
||||
taskCtx, taskCancel := context.WithCancel(ctx)
|
||||
|
||||
m.activeMu.Lock()
|
||||
m.active[task.ID] = task
|
||||
m.cancels[task.ID] = taskCancel
|
||||
m.activeMu.Unlock()
|
||||
|
||||
m.reporter.Track(task)
|
||||
|
|
@ -65,7 +71,8 @@ func (m *Manager) Submit(ctx context.Context, at agent.Task) {
|
|||
m.wg.Add(1)
|
||||
go func() {
|
||||
defer m.wg.Done()
|
||||
m.processTask(ctx, task)
|
||||
defer taskCancel()
|
||||
m.processTask(taskCtx, task)
|
||||
}()
|
||||
return
|
||||
}
|
||||
|
|
@ -74,6 +81,7 @@ func (m *Manager) Submit(ctx context.Context, at agent.Task) {
|
|||
select {
|
||||
case m.sem <- struct{}{}:
|
||||
case <-ctx.Done():
|
||||
taskCancel()
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -81,7 +89,8 @@ func (m *Manager) Submit(ctx context.Context, at agent.Task) {
|
|||
go func() {
|
||||
defer m.wg.Done()
|
||||
defer func() { <-m.sem }()
|
||||
m.processTask(ctx, task)
|
||||
defer taskCancel()
|
||||
m.processTask(taskCtx, task)
|
||||
}()
|
||||
}
|
||||
|
||||
|
|
@ -119,12 +128,19 @@ func (m *Manager) ActiveTasks() []*Task {
|
|||
func (m *Manager) CancelTask(taskID string) {
|
||||
m.activeMu.RLock()
|
||||
task, ok := m.active[taskID]
|
||||
cancel := m.cancels[taskID]
|
||||
m.activeMu.RUnlock()
|
||||
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
// Cancel the task's context first — this unblocks the goroutine
|
||||
// (e.g. stuck waiting for metadata) so it exits and releases the semaphore slot.
|
||||
if cancel != nil {
|
||||
cancel()
|
||||
}
|
||||
|
||||
if dl, exists := m.downloaders[task.ResolvedMethod]; exists {
|
||||
dl.Pause(taskID) // stop download, keep files
|
||||
}
|
||||
|
|
@ -141,12 +157,17 @@ func (m *Manager) CancelTask(taskID string) {
|
|||
func (m *Manager) PauseTask(taskID string) {
|
||||
m.activeMu.RLock()
|
||||
task, ok := m.active[taskID]
|
||||
cancel := m.cancels[taskID]
|
||||
m.activeMu.RUnlock()
|
||||
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if cancel != nil {
|
||||
cancel()
|
||||
}
|
||||
|
||||
if dl, exists := m.downloaders[task.ResolvedMethod]; exists {
|
||||
dl.Pause(taskID) // stop download, keep files for resume
|
||||
}
|
||||
|
|
@ -159,12 +180,17 @@ func (m *Manager) PauseTask(taskID string) {
|
|||
func (m *Manager) CancelAndDeleteFiles(taskID string) {
|
||||
m.activeMu.RLock()
|
||||
task, ok := m.active[taskID]
|
||||
cancel := m.cancels[taskID]
|
||||
m.activeMu.RUnlock()
|
||||
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
if cancel != nil {
|
||||
cancel()
|
||||
}
|
||||
|
||||
if dl, exists := m.downloaders[task.ResolvedMethod]; exists {
|
||||
dl.Cancel(taskID) // stop download + delete files
|
||||
}
|
||||
|
|
@ -204,8 +230,12 @@ func (m *Manager) Shutdown(ctx context.Context) {
|
|||
}
|
||||
}
|
||||
|
||||
// Clean active map
|
||||
// Clean active map and cancel functions
|
||||
m.activeMu.Lock()
|
||||
for id, cancel := range m.cancels {
|
||||
cancel()
|
||||
delete(m.cancels, id)
|
||||
}
|
||||
m.active = make(map[string]*Task)
|
||||
m.activeMu.Unlock()
|
||||
}
|
||||
|
|
@ -214,6 +244,7 @@ func (m *Manager) processTask(ctx context.Context, task *Task) {
|
|||
defer func() {
|
||||
m.activeMu.Lock()
|
||||
delete(m.active, task.ID)
|
||||
delete(m.cancels, task.ID)
|
||||
m.activeMu.Unlock()
|
||||
}()
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue