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