diff --git a/internal/fs/copy.go b/internal/fs/copy.go index f1bff409..c569e377 100644 --- a/internal/fs/copy.go +++ b/internal/fs/copy.go @@ -7,9 +7,12 @@ import ( "github.com/alist-org/alist/v3/internal/driver" "github.com/alist-org/alist/v3/internal/model" "github.com/alist-org/alist/v3/internal/operations" + "github.com/alist-org/alist/v3/internal/task" "github.com/pkg/errors" ) +var copyTaskManager = task.NewTaskManager() + func CopyBetween2Accounts(ctx context.Context, srcAccount, dstAccount driver.Driver, srcPath, dstPath string) error { srcFile, err := operations.Get(ctx, srcAccount, srcPath) if err != nil { diff --git a/internal/fs/write.go b/internal/fs/write.go index 0a353fc8..f476f759 100644 --- a/internal/fs/write.go +++ b/internal/fs/write.go @@ -2,10 +2,12 @@ package fs import ( "context" + "fmt" "github.com/alist-org/alist/v3/internal/driver" "github.com/alist-org/alist/v3/internal/model" "github.com/alist-org/alist/v3/internal/operations" + "github.com/alist-org/alist/v3/internal/task" "github.com/pkg/errors" ) @@ -42,32 +44,25 @@ func Rename(ctx context.Context, account driver.Driver, srcPath, dstName string) // Copy if in an account, call move method // if not, add copy task -func Copy(ctx context.Context, account driver.Driver, srcPath, dstPath string) error { +func Copy(ctx context.Context, account driver.Driver, srcPath, dstPath string) (bool, error) { srcAccount, srcActualPath, err := operations.GetAccountAndActualPath(srcPath) if err != nil { - return errors.WithMessage(err, "failed get src account") + return false, errors.WithMessage(err, "failed get src account") } dstAccount, dstActualPath, err := operations.GetAccountAndActualPath(srcPath) if err != nil { - return errors.WithMessage(err, "failed get dst account") + return false, errors.WithMessage(err, "failed get dst account") } // copy if in an account, just call driver.Copy if srcAccount.GetAccount() == dstAccount.GetAccount() { - return operations.Copy(ctx, account, srcActualPath, dstActualPath) + return false, operations.Copy(ctx, account, srcActualPath, dstActualPath) } // not in an account - return CopyBetween2Accounts(ctx, srcAccount, dstAccount, srcActualPath, dstActualPath) - // srcFile, err := operations.Get(ctx, srcAccount, srcActualPath) - // if srcFile.IsDir() { - // // TODO: recursive copy - // return nil - // } - // // TODO: add copy task, maybe like this: - // // operations.Link(ctx,srcAccount,srcActualPath,args) - // // get a Reader from link - // // boxing the Reader to a driver.FileStream - // // operations.Put(ctx,dstParentPath, stream) - // panic("TODO") + // TODO add status set callback to put + copyTaskManager.Add(fmt.Sprintf("copy %s to %s", srcActualPath, dstActualPath), func(task *task.Task) error { + return CopyBetween2Accounts(context.TODO(), srcAccount, dstAccount, srcActualPath, dstActualPath) + }) + return true, nil } func Remove(ctx context.Context, account driver.Driver, path string) error { diff --git a/internal/task/manager.go b/internal/task/manager.go new file mode 100644 index 00000000..834fcd13 --- /dev/null +++ b/internal/task/manager.go @@ -0,0 +1,61 @@ +package task + +import ( + "sync/atomic" + + "github.com/alist-org/alist/v3/pkg/generic_sync" +) + +func NewTaskManager() *TaskManager { + return &TaskManager{ + tasks: generic_sync.MapOf[int64, *Task]{}, + curID: 0, + } +} + +type TaskManager struct { + curID int64 + tasks generic_sync.MapOf[int64, *Task] +} + +func (tm *TaskManager) AddTask(task *Task) { + task.ID = tm.curID + atomic.AddInt64(&tm.curID, 1) + tm.tasks.Store(task.ID, task) +} + +func (tm *TaskManager) GetAll() []*Task { + return tm.tasks.Values() +} + +func (tm *TaskManager) Get(id int64) (*Task, bool) { + return tm.tasks.Load(id) +} + +func (tm *TaskManager) Remove(id int64) { + tm.tasks.Delete(id) +} + +func (tm *TaskManager) RemoveFinished() { + tasks := tm.GetAll() + for _, task := range tasks { + if task.Status == FINISHED { + tm.Remove(task.ID) + } + } +} + +func (tm *TaskManager) RemoveError() { + tasks := tm.GetAll() + for _, task := range tasks { + if task.Error != nil { + tm.Remove(task.ID) + } + } +} + +func (tm *TaskManager) Add(name string, f Func) { + task := NewTask(name, f) + tm.AddTask(task) + go task.Run() +} diff --git a/internal/task/task.go b/internal/task/task.go index b78cce44..e90fbfe8 100644 --- a/internal/task/task.go +++ b/internal/task/task.go @@ -1,10 +1,36 @@ // manage task, such as file upload, file copy between accounts, offline download, etc. package task +type Func func(task *Task) error + +var ( + PENDING = "pending" + RUNNING = "running" + FINISHED = "finished" +) + type Task struct { - Name string - Status string - Error error - Finish bool - Children []*Task + ID int64 + Name string + Status string + Error error + Func Func +} + +func NewTask(name string, func_ Func) *Task { + return &Task{ + Name: name, + Status: PENDING, + Func: func_, + } +} + +func (t *Task) SetStatus(status string) { + t.Status = status +} + +func (t *Task) Run() { + t.Status = RUNNING + t.Error = t.Func(t) + t.Status = FINISHED }