2022-06-15 10:58:26 +00:00
package fs
import (
"context"
2022-06-17 13:23:44 +00:00
"fmt"
2022-06-17 13:42:56 +00:00
stdpath "path"
2022-06-21 08:14:37 +00:00
"sync/atomic"
2022-06-17 13:42:56 +00:00
2022-06-17 13:23:44 +00:00
"github.com/alist-org/alist/v3/pkg/task"
"github.com/alist-org/alist/v3/pkg/utils"
2022-06-15 10:58:26 +00:00
"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/pkg/errors"
)
2022-06-21 08:14:37 +00:00
var CopyTaskManager = task . NewTaskManager [ uint64 , struct { } ] ( 3 , func ( tid * uint64 ) {
atomic . AddUint64 ( tid , 1 )
} )
2022-06-17 07:57:16 +00:00
2022-06-17 13:35:46 +00:00
// Copy if in an account, call move method
// if not, add copy task
2022-06-21 08:37:51 +00:00
func Copy ( ctx context . Context , account driver . Driver , srcObjPath , dstDirPath string ) ( bool , error ) {
srcAccount , srcObjActualPath , err := operations . GetAccountAndActualPath ( srcObjPath )
2022-06-17 13:35:46 +00:00
if err != nil {
return false , errors . WithMessage ( err , "failed get src account" )
}
2022-06-21 08:37:51 +00:00
dstAccount , dstDirActualPath , err := operations . GetAccountAndActualPath ( dstDirPath )
2022-06-17 13:35:46 +00:00
if err != nil {
return false , errors . WithMessage ( err , "failed get dst account" )
}
// copy if in an account, just call driver.Copy
if srcAccount . GetAccount ( ) == dstAccount . GetAccount ( ) {
2022-06-21 08:37:51 +00:00
return false , operations . Copy ( ctx , account , srcObjActualPath , dstDirActualPath )
2022-06-17 13:35:46 +00:00
}
// not in an account
2022-06-21 08:14:37 +00:00
CopyTaskManager . Submit ( task . WithCancelCtx ( & task . Task [ uint64 , struct { } ] {
2022-06-21 08:37:51 +00:00
Name : fmt . Sprintf ( "copy [%s](%s) to [%s](%s)" , srcAccount . GetAccount ( ) . VirtualPath , srcObjActualPath , dstAccount . GetAccount ( ) . VirtualPath , dstDirActualPath ) ,
2022-06-21 08:14:37 +00:00
Func : func ( task * task . Task [ uint64 , struct { } ] ) error {
2022-06-21 08:37:51 +00:00
return CopyBetween2Accounts ( task , srcAccount , dstAccount , srcObjActualPath , dstDirActualPath )
2022-06-21 08:14:37 +00:00
} ,
} ) )
2022-06-17 13:35:46 +00:00
return true , nil
}
2022-06-21 08:37:51 +00:00
func CopyBetween2Accounts ( t * task . Task [ uint64 , struct { } ] , srcAccount , dstAccount driver . Driver , srcObjPath , dstDirPath string ) error {
2022-06-18 12:06:45 +00:00
t . SetStatus ( "getting src object" )
2022-06-21 08:37:51 +00:00
srcObj , err := operations . Get ( t . Ctx , srcAccount , srcObjPath )
2022-06-15 10:58:26 +00:00
if err != nil {
2022-06-21 08:37:51 +00:00
return errors . WithMessagef ( err , "failed get src [%s] file" , srcObjPath )
2022-06-15 10:58:26 +00:00
}
2022-06-17 13:23:44 +00:00
if srcObj . IsDir ( ) {
2022-06-18 12:06:45 +00:00
t . SetStatus ( "src object is dir, listing objs" )
2022-06-21 08:37:51 +00:00
objs , err := operations . List ( t . Ctx , srcAccount , srcObjPath )
2022-06-15 10:58:26 +00:00
if err != nil {
2022-06-21 08:37:51 +00:00
return errors . WithMessagef ( err , "failed list src [%s] objs" , srcObjPath )
2022-06-15 10:58:26 +00:00
}
2022-06-17 13:30:16 +00:00
for _ , obj := range objs {
2022-06-18 12:06:45 +00:00
if utils . IsCanceled ( t . Ctx ) {
2022-06-17 13:23:44 +00:00
return nil
}
2022-06-21 08:37:51 +00:00
srcObjPath := stdpath . Join ( srcObjPath , obj . GetName ( ) )
dstObjPath := stdpath . Join ( dstDirPath , obj . GetName ( ) )
2022-06-21 08:14:37 +00:00
CopyTaskManager . Submit ( task . WithCancelCtx ( & task . Task [ uint64 , struct { } ] {
Name : fmt . Sprintf ( "copy [%s](%s) to [%s](%s)" , srcAccount . GetAccount ( ) . VirtualPath , srcObjPath , dstAccount . GetAccount ( ) . VirtualPath , dstObjPath ) ,
Func : func ( t * task . Task [ uint64 , struct { } ] ) error {
2022-06-18 12:06:45 +00:00
return CopyBetween2Accounts ( t , srcAccount , dstAccount , srcObjPath , dstObjPath )
2022-06-21 08:14:37 +00:00
} ,
} ) )
2022-06-15 10:58:26 +00:00
}
2022-06-17 13:23:44 +00:00
} else {
2022-06-21 08:14:37 +00:00
CopyTaskManager . Submit ( task . WithCancelCtx ( & task . Task [ uint64 , struct { } ] {
2022-06-21 08:37:51 +00:00
Name : fmt . Sprintf ( "copy [%s](%s) to [%s](%s)" , srcAccount . GetAccount ( ) . VirtualPath , srcObjPath , dstAccount . GetAccount ( ) . VirtualPath , dstDirPath ) ,
2022-06-21 08:14:37 +00:00
Func : func ( t * task . Task [ uint64 , struct { } ] ) error {
2022-06-21 08:37:51 +00:00
return CopyFileBetween2Accounts ( t , srcAccount , dstAccount , srcObjPath , dstDirPath )
2022-06-21 08:14:37 +00:00
} ,
} ) )
2022-06-17 13:23:44 +00:00
}
return nil
}
2022-06-21 08:37:51 +00:00
func CopyFileBetween2Accounts ( tsk * task . Task [ uint64 , struct { } ] , srcAccount , dstAccount driver . Driver , srcFilePath , dstDirPath string ) error {
srcFile , err := operations . Get ( tsk . Ctx , srcAccount , srcFilePath )
2022-06-17 13:23:44 +00:00
if err != nil {
2022-06-21 08:37:51 +00:00
return errors . WithMessagef ( err , "failed get src [%s] file" , srcFilePath )
2022-06-15 10:58:26 +00:00
}
2022-06-21 08:37:51 +00:00
link , err := operations . Link ( tsk . Ctx , srcAccount , srcFilePath , model . LinkArgs { } )
2022-06-15 10:58:26 +00:00
if err != nil {
2022-06-21 08:37:51 +00:00
return errors . WithMessagef ( err , "failed get [%s] link" , srcFilePath )
2022-06-15 10:58:26 +00:00
}
stream , err := getFileStreamFromLink ( srcFile , link )
if err != nil {
2022-06-21 08:37:51 +00:00
return errors . WithMessagef ( err , "failed get [%s] stream" , srcFilePath )
2022-06-15 10:58:26 +00:00
}
2022-06-21 08:37:51 +00:00
return operations . Put ( tsk . Ctx , dstAccount , dstDirPath , stream , tsk . SetProgress )
2022-06-15 10:58:26 +00:00
}