aliyunpan/internal/syncdrive/file_action_task_mgr.go

829 lines
25 KiB
Go
Raw Normal View History

2022-05-24 23:01:08 +08:00
package syncdrive
2022-06-01 21:55:03 +08:00
import (
"context"
"fmt"
mapset "github.com/deckarep/golang-set"
"github.com/tickstep/aliyunpan/internal/localfile"
"github.com/tickstep/aliyunpan/internal/waitgroup"
"github.com/tickstep/aliyunpan/library/collection"
"github.com/tickstep/library-go/logger"
"path"
"strings"
"sync"
"time"
)
2022-05-24 23:01:08 +08:00
type (
2022-06-01 21:55:03 +08:00
FileActionTaskList []*FileActionTask
2022-05-24 23:01:08 +08:00
FileActionTaskManager struct {
2022-06-05 22:19:16 +08:00
mutex *sync.Mutex
folderCreateMutex *sync.Mutex
2022-06-01 21:55:03 +08:00
task *SyncTask
wg *waitgroup.WaitGroup
ctx context.Context
cancelFunc context.CancelFunc
2022-06-04 13:20:33 +08:00
fileInProcessQueue *collection.Queue
fileDownloadParallel int
fileUploadParallel int
2022-06-05 22:19:16 +08:00
fileDownloadBlockSize int64
fileUploadBlockSize int64
2022-06-10 14:36:52 +08:00
2022-06-12 17:03:05 +08:00
maxDownloadRate int64 // 限制最大下载速度
maxUploadRate int64 // 限制最大上传速度
2022-06-10 14:36:52 +08:00
useInternalUrl bool
2022-06-01 21:55:03 +08:00
}
localFileSet struct {
items LocalFileList
localFolderPath string
}
panFileSet struct {
items PanFileList
panFolderPath string
2022-05-24 23:01:08 +08:00
}
)
2022-06-12 17:03:05 +08:00
func NewFileActionTaskManager(task *SyncTask, maxDownloadRate, maxUploadRate int64) *FileActionTaskManager {
2022-05-24 23:01:08 +08:00
return &FileActionTaskManager{
2022-06-05 22:19:16 +08:00
mutex: &sync.Mutex{},
folderCreateMutex: &sync.Mutex{},
task: task,
2022-06-04 13:20:33 +08:00
fileInProcessQueue: collection.NewFifoQueue(),
2022-06-10 13:55:00 +08:00
fileDownloadParallel: task.fileDownloadParallel,
fileUploadParallel: task.fileUploadParallel,
2022-06-05 22:19:16 +08:00
2022-06-10 13:55:00 +08:00
fileDownloadBlockSize: task.fileDownloadBlockSize,
fileUploadBlockSize: task.fileUploadBlockSize,
2022-06-10 14:36:52 +08:00
useInternalUrl: task.useInternalUrl,
2022-06-12 17:03:05 +08:00
maxDownloadRate: maxDownloadRate,
maxUploadRate: maxUploadRate,
2022-05-24 23:01:08 +08:00
}
}
2022-06-09 14:52:49 +08:00
// Start 启动文件动作任务管理进程
// 通过对本地数据库的对比,决策对文件进行下载、上传、删除等动作
2022-06-01 21:55:03 +08:00
func (f *FileActionTaskManager) Start() error {
if f.ctx != nil {
return fmt.Errorf("task have starting")
}
2022-06-04 13:20:33 +08:00
f.wg = waitgroup.NewWaitGroup(0)
2022-06-01 21:55:03 +08:00
var cancel context.CancelFunc
f.ctx, cancel = context.WithCancel(context.Background())
f.cancelFunc = cancel
2022-06-04 13:20:33 +08:00
go f.doLocalFileDiffRoutine(f.ctx)
go f.doPanFileDiffRoutine(f.ctx)
2022-06-01 21:55:03 +08:00
go f.fileActionTaskExecutor(f.ctx)
2022-05-24 23:01:08 +08:00
return nil
}
2022-06-01 21:55:03 +08:00
func (f *FileActionTaskManager) Stop() error {
if f.ctx == nil {
return nil
}
// cancel all sub task & process
f.cancelFunc()
// wait for finished
f.wg.Wait()
f.ctx = nil
f.cancelFunc = nil
return nil
}
// getPanPathFromLocalPath 通过本地文件路径获取网盘文件的对应路径
func (f *FileActionTaskManager) getPanPathFromLocalPath(localPath string) string {
localPath = strings.ReplaceAll(localPath, "\\", "/")
localRootPath := strings.ReplaceAll(f.task.LocalFolderPath, "\\", "/")
relativePath := strings.TrimPrefix(localPath, localRootPath)
return path.Join(path.Clean(f.task.PanFolderPath), relativePath)
}
// getLocalPathFromPanPath 通过网盘文件路径获取对应的本地文件的对应路径
func (f *FileActionTaskManager) getLocalPathFromPanPath(panPath string) string {
panPath = strings.ReplaceAll(panPath, "\\", "/")
panRootPath := strings.ReplaceAll(f.task.PanFolderPath, "\\", "/")
relativePath := strings.TrimPrefix(panPath, panRootPath)
return path.Join(path.Clean(f.task.LocalFolderPath), relativePath)
}
2022-06-04 13:20:33 +08:00
// doLocalFileDiffRoutine 对比网盘文件和本地文件信息,差异化上传或者下载文件
func (f *FileActionTaskManager) doLocalFileDiffRoutine(ctx context.Context) {
2022-06-01 21:55:03 +08:00
localFolderQueue := collection.NewFifoQueue()
2022-06-06 19:13:37 +08:00
var localRootFolder *LocalFileItem
var er error
2022-06-04 13:20:33 +08:00
f.wg.AddDelta()
defer f.wg.Done()
for {
select {
case <-ctx.Done():
// cancel routine & done
logger.Verboseln("file diff routine done")
return
default:
2022-06-06 19:13:37 +08:00
if localRootFolder == nil {
localRootFolder, er = f.task.localFileDb.Get(f.task.LocalFolderPath)
if er == nil {
localFolderQueue.Push(localRootFolder)
} else {
time.Sleep(1 * time.Second)
continue
}
}
2022-06-12 17:44:16 +08:00
//logger.Verboseln("do file diff process")
2022-06-04 13:20:33 +08:00
localFiles := LocalFileList{}
panFiles := PanFileList{}
var err error
var objLocal interface{}
objLocal = localFolderQueue.Pop()
if objLocal == nil {
// restart over
localFolderQueue.Push(localRootFolder)
time.Sleep(3 * time.Second)
continue
}
localItem := objLocal.(*LocalFileItem)
localFiles, err = f.task.localFileDb.GetFileList(localItem.Path)
if err != nil {
localFiles = LocalFileList{}
}
panFiles, err = f.task.panFileDb.GetFileList(f.getPanPathFromLocalPath(localItem.Path))
if err != nil {
panFiles = PanFileList{}
}
f.doFileDiffRoutine(panFiles, localFiles, nil, localFolderQueue)
}
}
}
// doPanFileDiffRoutine 对比网盘文件和本地文件信息,差异化上传或者下载文件
func (f *FileActionTaskManager) doPanFileDiffRoutine(ctx context.Context) {
panFolderQueue := collection.NewFifoQueue()
2022-06-06 19:13:37 +08:00
var panRootFolder *PanFileItem
var er error
2022-06-01 21:55:03 +08:00
f.wg.AddDelta()
defer f.wg.Done()
for {
select {
case <-ctx.Done():
// cancel routine & done
logger.Verboseln("file diff routine done")
return
default:
2022-06-06 19:13:37 +08:00
if panRootFolder == nil {
panRootFolder, er = f.task.panFileDb.Get(f.task.PanFolderPath)
if er == nil {
panFolderQueue.Push(panRootFolder)
} else {
time.Sleep(1 * time.Second)
continue
}
}
2022-06-12 17:44:16 +08:00
//logger.Verboseln("do file diff process")
2022-06-01 21:55:03 +08:00
localFiles := LocalFileList{}
panFiles := PanFileList{}
var err error
2022-06-04 13:20:33 +08:00
var objPan interface{}
2022-06-01 21:55:03 +08:00
2022-06-04 13:20:33 +08:00
objPan = panFolderQueue.Pop()
if objPan == nil {
// restart over
panFolderQueue.Push(panRootFolder)
time.Sleep(3 * time.Second)
2022-06-01 21:55:03 +08:00
continue
}
2022-06-04 13:20:33 +08:00
panItem := objPan.(*PanFileItem)
panFiles, err = f.task.panFileDb.GetFileList(panItem.Path)
if err != nil {
panFiles = PanFileList{}
2022-06-01 21:55:03 +08:00
}
2022-06-04 13:20:33 +08:00
localFiles, err = f.task.localFileDb.GetFileList(f.getLocalPathFromPanPath(panItem.Path))
if err != nil {
localFiles = LocalFileList{}
2022-06-01 21:55:03 +08:00
}
2022-06-04 13:20:33 +08:00
f.doFileDiffRoutine(panFiles, localFiles, panFolderQueue, nil)
time.Sleep(500 * time.Millisecond)
}
}
}
func (f *FileActionTaskManager) doFileDiffRoutine(panFiles PanFileList, localFiles LocalFileList, panFolderQueue *collection.Queue, localFolderQueue *collection.Queue) {
// empty loop
if len(panFiles) == 0 && len(localFiles) == 0 {
time.Sleep(100 * time.Millisecond)
return
}
localFilesSet := &localFileSet{
items: localFiles,
localFolderPath: f.task.LocalFolderPath,
}
panFilesSet := &panFileSet{
items: panFiles,
panFolderPath: f.task.PanFolderPath,
}
localFilesNeedToUpload := localFilesSet.Difference(panFilesSet)
panFilesNeedToDownload := panFilesSet.Difference(localFilesSet)
localFilesNeedToCheck, panFilesNeedToCheck := localFilesSet.Intersection(panFilesSet)
// download file from pan drive
2022-06-09 19:58:16 +08:00
if panFilesNeedToDownload != nil {
for _, file := range panFilesNeedToDownload {
if file.ScanStatus == ScanStatusNormal { // 下载文件
if f.task.Mode == DownloadOnly || f.task.Mode == SyncTwoWay {
2022-06-09 14:52:49 +08:00
if file.IsFolder() {
if panFolderQueue != nil {
panFolderQueue.PushUnique(file)
}
continue
}
fileActionTask := &FileActionTask{
syncItem: &SyncFileItem{
2022-06-10 13:55:00 +08:00
Action: SyncFileActionDownload,
Status: SyncFileStatusCreate,
LocalFile: nil,
PanFile: file,
StatusUpdateTime: "",
PanFolderPath: f.task.PanFolderPath,
LocalFolderPath: f.task.LocalFolderPath,
DriveId: f.task.DriveId,
DownloadBlockSize: f.fileDownloadBlockSize,
UploadBlockSize: f.fileUploadBlockSize,
2022-06-10 14:36:52 +08:00
UseInternalUrl: f.useInternalUrl,
2022-06-09 14:52:49 +08:00
},
}
f.addToSyncDb(fileActionTask)
2022-06-09 19:58:16 +08:00
}
} else if file.ScanStatus == ScanStatusDiscard { // 删除对应本地文件(文件夹)
if f.task.Mode == DownloadOnly || f.task.Mode == SyncTwoWay {
2022-06-09 14:52:49 +08:00
fileActionTask := &FileActionTask{
syncItem: &SyncFileItem{
2022-06-10 13:55:00 +08:00
Action: SyncFileActionDeleteLocal,
Status: SyncFileStatusCreate,
LocalFile: nil,
PanFile: file,
StatusUpdateTime: "",
PanFolderPath: f.task.PanFolderPath,
LocalFolderPath: f.task.LocalFolderPath,
DriveId: f.task.DriveId,
DownloadBlockSize: f.fileDownloadBlockSize,
UploadBlockSize: f.fileUploadBlockSize,
2022-06-10 14:36:52 +08:00
UseInternalUrl: f.useInternalUrl,
2022-06-09 14:52:49 +08:00
},
}
f.addToSyncDb(fileActionTask)
2022-06-09 19:58:16 +08:00
} else if f.task.Mode == UploadOnly {
// 删除无用记录
f.task.panFileDb.Delete(file.Path)
2022-06-01 21:55:03 +08:00
}
2022-06-04 13:20:33 +08:00
}
}
}
2022-06-01 21:55:03 +08:00
2022-06-04 13:20:33 +08:00
// upload file to pan drive
2022-06-09 19:58:16 +08:00
if localFilesNeedToUpload != nil {
for _, file := range localFilesNeedToUpload {
if file.ScanStatus == ScanStatusNormal { // 上传文件到云盘
if f.task.Mode == UploadOnly || f.task.Mode == SyncTwoWay {
2022-06-09 14:52:49 +08:00
if file.IsFolder() {
if localFolderQueue != nil {
localFolderQueue.PushUnique(file)
}
continue
}
fileActionTask := &FileActionTask{
syncItem: &SyncFileItem{
2022-06-10 13:55:00 +08:00
Action: SyncFileActionUpload,
Status: SyncFileStatusCreate,
LocalFile: file,
PanFile: nil,
StatusUpdateTime: "",
PanFolderPath: f.task.PanFolderPath,
LocalFolderPath: f.task.LocalFolderPath,
DriveId: f.task.DriveId,
DownloadBlockSize: f.fileDownloadBlockSize,
UploadBlockSize: f.fileUploadBlockSize,
2022-06-10 14:36:52 +08:00
UseInternalUrl: f.useInternalUrl,
2022-06-09 14:52:49 +08:00
},
}
f.addToSyncDb(fileActionTask)
2022-06-09 19:58:16 +08:00
}
} else if file.ScanStatus == ScanStatusDiscard { // 删除对应云盘文件(文件夹)
if f.task.Mode == UploadOnly || f.task.Mode == SyncTwoWay {
2022-06-09 14:52:49 +08:00
fileActionTask := &FileActionTask{
syncItem: &SyncFileItem{
2022-06-10 13:55:00 +08:00
Action: SyncFileActionDeletePan,
Status: SyncFileStatusCreate,
LocalFile: file,
PanFile: nil,
StatusUpdateTime: "",
PanFolderPath: f.task.PanFolderPath,
LocalFolderPath: f.task.LocalFolderPath,
DriveId: f.task.DriveId,
DownloadBlockSize: f.fileDownloadBlockSize,
UploadBlockSize: f.fileUploadBlockSize,
2022-06-10 14:36:52 +08:00
UseInternalUrl: f.useInternalUrl,
2022-06-09 14:52:49 +08:00
},
}
f.addToSyncDb(fileActionTask)
2022-06-09 19:58:16 +08:00
} else if f.task.Mode == DownloadOnly {
// 删除无用记录
f.task.localFileDb.Delete(file.Path)
2022-06-01 21:55:03 +08:00
}
}
2022-06-04 13:20:33 +08:00
}
}
2022-06-01 21:55:03 +08:00
2022-06-09 14:52:49 +08:00
// compare file to decide download / upload / delete
2022-06-04 13:20:33 +08:00
for idx, _ := range localFilesNeedToCheck {
localFile := localFilesNeedToCheck[idx]
panFile := panFilesNeedToCheck[idx]
2022-06-09 14:52:49 +08:00
//
// do delete local / pan file check
//
if localFile.ScanStatus == ScanStatusDiscard && panFile.ScanStatus == ScanStatusDiscard {
// 清除过期数据项
f.task.localFileDb.Delete(localFile.Path)
f.task.panFileDb.Delete(panFile.Path)
continue
}
if localFile.ScanStatus == ScanStatusDiscard && panFile.ScanStatus == ScanStatusNormal && localFile.Sha1Hash == panFile.Sha1Hash {
if f.task.Mode == UploadOnly || f.task.Mode == SyncTwoWay {
// 删除对应的云盘文件
deletePanFile := &FileActionTask{
syncItem: &SyncFileItem{
2022-06-10 13:55:00 +08:00
Action: SyncFileActionDeletePan,
Status: SyncFileStatusCreate,
LocalFile: localFile,
PanFile: panFile,
StatusUpdateTime: "",
PanFolderPath: f.task.PanFolderPath,
LocalFolderPath: f.task.LocalFolderPath,
DriveId: f.task.DriveId,
DownloadBlockSize: f.fileDownloadBlockSize,
UploadBlockSize: f.fileUploadBlockSize,
2022-06-10 14:36:52 +08:00
UseInternalUrl: f.useInternalUrl,
2022-06-09 14:52:49 +08:00
},
}
f.addToSyncDb(deletePanFile)
2022-06-09 19:58:16 +08:00
} else if f.task.Mode == DownloadOnly {
// 删除无用记录
f.task.localFileDb.Delete(localFile.Path)
2022-06-09 14:52:49 +08:00
}
continue
}
if panFile.ScanStatus == ScanStatusDiscard && localFile.ScanStatus == ScanStatusNormal && localFile.Sha1Hash == panFile.Sha1Hash {
if f.task.Mode == DownloadOnly || f.task.Mode == SyncTwoWay {
// 删除对应的本地文件
deletePanFile := &FileActionTask{
syncItem: &SyncFileItem{
2022-06-10 13:55:00 +08:00
Action: SyncFileActionDeleteLocal,
Status: SyncFileStatusCreate,
LocalFile: localFile,
PanFile: panFile,
StatusUpdateTime: "",
PanFolderPath: f.task.PanFolderPath,
LocalFolderPath: f.task.LocalFolderPath,
DriveId: f.task.DriveId,
DownloadBlockSize: f.fileDownloadBlockSize,
UploadBlockSize: f.fileUploadBlockSize,
2022-06-10 14:36:52 +08:00
UseInternalUrl: f.useInternalUrl,
2022-06-09 14:52:49 +08:00
},
}
f.addToSyncDb(deletePanFile)
2022-06-09 19:58:16 +08:00
} else if f.task.Mode == UploadOnly {
// 删除无用记录
f.task.panFileDb.Delete(panFile.Path)
2022-06-09 14:52:49 +08:00
}
continue
}
//
// do download / upload check
//
2022-06-04 13:20:33 +08:00
if localFile.IsFolder() {
if localFolderQueue != nil {
localFolderQueue.PushUnique(localFile)
}
if panFolderQueue != nil {
panFolderQueue.PushUnique(panFile)
}
continue
}
2022-06-01 21:55:03 +08:00
2022-06-04 13:20:33 +08:00
if localFile.Sha1Hash == "" {
// calc sha1
fileSum := localfile.NewLocalFileEntity(localFile.Path)
2022-06-05 22:19:16 +08:00
err := fileSum.OpenPath()
if err != nil {
logger.Verbosef("文件不可读, 错误信息: %s, 跳过...\n", err)
}
2022-06-04 13:20:33 +08:00
fileSum.Sum(localfile.CHECKSUM_SHA1) // block operation
localFile.Sha1Hash = fileSum.SHA1
fileSum.Close()
2022-06-01 21:55:03 +08:00
2022-06-04 13:20:33 +08:00
// save sha1
f.task.localFileDb.Update(localFile)
}
2022-06-01 21:55:03 +08:00
2022-06-04 13:20:33 +08:00
if strings.ToLower(panFile.Sha1Hash) == strings.ToLower(localFile.Sha1Hash) {
// do nothing
2022-06-12 17:44:16 +08:00
logger.Verboseln("file is the same, no need to update file: ", localFile.Path)
2022-06-04 13:20:33 +08:00
continue
}
2022-06-01 21:55:03 +08:00
2022-06-04 13:20:33 +08:00
// 本地文件和云盘文件SHA1不一样
// 不同模式同步策略不一样
if f.task.Mode == UploadOnly {
uploadLocalFile := &FileActionTask{
syncItem: &SyncFileItem{
2022-06-10 13:55:00 +08:00
Action: SyncFileActionUpload,
Status: SyncFileStatusCreate,
LocalFile: localFile,
PanFile: nil,
StatusUpdateTime: "",
PanFolderPath: f.task.PanFolderPath,
LocalFolderPath: f.task.LocalFolderPath,
DriveId: f.task.DriveId,
DownloadBlockSize: f.fileDownloadBlockSize,
UploadBlockSize: f.fileUploadBlockSize,
2022-06-10 14:36:52 +08:00
UseInternalUrl: f.useInternalUrl,
2022-06-04 13:20:33 +08:00
},
}
f.addToSyncDb(uploadLocalFile)
} else if f.task.Mode == DownloadOnly {
downloadPanFile := &FileActionTask{
syncItem: &SyncFileItem{
2022-06-10 13:55:00 +08:00
Action: SyncFileActionDownload,
Status: SyncFileStatusCreate,
LocalFile: nil,
PanFile: panFile,
StatusUpdateTime: "",
PanFolderPath: f.task.PanFolderPath,
LocalFolderPath: f.task.LocalFolderPath,
DriveId: f.task.DriveId,
DownloadBlockSize: f.fileDownloadBlockSize,
UploadBlockSize: f.fileUploadBlockSize,
2022-06-10 14:36:52 +08:00
UseInternalUrl: f.useInternalUrl,
2022-06-04 13:20:33 +08:00
},
}
f.addToSyncDb(downloadPanFile)
} else if f.task.Mode == SyncTwoWay {
if localFile.UpdateTimeUnix() > panFile.UpdateTimeUnix() { // upload file
uploadLocalFile := &FileActionTask{
syncItem: &SyncFileItem{
2022-06-10 13:55:00 +08:00
Action: SyncFileActionUpload,
Status: SyncFileStatusCreate,
LocalFile: localFile,
PanFile: nil,
StatusUpdateTime: "",
PanFolderPath: f.task.PanFolderPath,
LocalFolderPath: f.task.LocalFolderPath,
DriveId: f.task.DriveId,
DownloadBlockSize: f.fileDownloadBlockSize,
UploadBlockSize: f.fileUploadBlockSize,
2022-06-10 14:36:52 +08:00
UseInternalUrl: f.useInternalUrl,
2022-06-04 13:20:33 +08:00
},
}
f.addToSyncDb(uploadLocalFile)
} else if localFile.UpdateTimeUnix() < panFile.UpdateTimeUnix() { // download file
downloadPanFile := &FileActionTask{
syncItem: &SyncFileItem{
2022-06-10 13:55:00 +08:00
Action: SyncFileActionDownload,
Status: SyncFileStatusCreate,
LocalFile: nil,
PanFile: panFile,
StatusUpdateTime: "",
PanFolderPath: f.task.PanFolderPath,
LocalFolderPath: f.task.LocalFolderPath,
DriveId: f.task.DriveId,
DownloadBlockSize: f.fileDownloadBlockSize,
UploadBlockSize: f.fileUploadBlockSize,
2022-06-10 14:36:52 +08:00
UseInternalUrl: f.useInternalUrl,
2022-06-04 13:20:33 +08:00
},
2022-06-01 21:55:03 +08:00
}
2022-06-04 13:20:33 +08:00
f.addToSyncDb(downloadPanFile)
2022-06-01 21:55:03 +08:00
}
}
}
}
2022-06-04 13:20:33 +08:00
func (f *FileActionTaskManager) addToSyncDb(fileTask *FileActionTask) {
2022-06-01 21:55:03 +08:00
f.mutex.Lock()
defer f.mutex.Unlock()
2022-06-04 13:20:33 +08:00
// check sync db
2022-06-01 21:55:03 +08:00
if itemInDb, e := f.task.syncFileDb.Get(fileTask.syncItem.Id()); e == nil && itemInDb != nil {
if itemInDb.Status == SyncFileStatusCreate || itemInDb.Status == SyncFileStatusDownloading || itemInDb.Status == SyncFileStatusUploading {
return
}
if itemInDb.Status == SyncFileStatusSuccess {
if (time.Now().Unix() - itemInDb.StatusUpdateTimeUnix()) < TimeSecondsOf5Minute {
// 少于5分钟不同步减少同步频次
return
}
}
2022-06-04 13:20:33 +08:00
if itemInDb.Status == SyncFileStatusIllegal {
if (time.Now().Unix() - itemInDb.StatusUpdateTimeUnix()) < TimeSecondsOf60Minute {
// 非法文件少于60分钟不同步减少同步频次
return
}
}
if itemInDb.Status == SyncFileStatusNotExisted {
if itemInDb.Action == SyncFileActionDownload {
if itemInDb.PanFile.UpdatedAt == fileTask.syncItem.PanFile.UpdatedAt {
return
}
} else if itemInDb.Action == SyncFileActionUpload {
if itemInDb.LocalFile.UpdatedAt == fileTask.syncItem.LocalFile.UpdatedAt {
return
}
}
}
2022-06-01 21:55:03 +08:00
}
// 进入任务队列
f.task.syncFileDb.Add(fileTask.syncItem)
}
2022-06-04 13:20:33 +08:00
func (f *FileActionTaskManager) getFromSyncDb(act SyncFileAction) *FileActionTask {
2022-06-01 21:55:03 +08:00
f.mutex.Lock()
defer f.mutex.Unlock()
if act == SyncFileActionDownload {
if files, e := f.task.syncFileDb.GetFileList(SyncFileStatusDownloading); e == nil {
2022-06-04 13:20:33 +08:00
for _, file := range files {
if !f.fileInProcessQueue.Contains(file) {
return &FileActionTask{
2022-06-05 22:19:16 +08:00
localFileDb: f.task.localFileDb,
panFileDb: f.task.panFileDb,
syncFileDb: f.task.syncFileDb,
panClient: f.task.panClient,
syncItem: file,
2022-06-12 17:03:05 +08:00
maxDownloadRate: f.maxDownloadRate,
maxUploadRate: f.maxUploadRate,
2022-06-05 22:19:16 +08:00
panFolderCreateMutex: f.folderCreateMutex,
2022-06-04 13:20:33 +08:00
}
2022-06-01 21:55:03 +08:00
}
}
}
} else if act == SyncFileActionUpload {
if files, e := f.task.syncFileDb.GetFileList(SyncFileStatusUploading); e == nil {
2022-06-04 13:20:33 +08:00
for _, file := range files {
if !f.fileInProcessQueue.Contains(file) {
return &FileActionTask{
2022-06-05 22:19:16 +08:00
localFileDb: f.task.localFileDb,
panFileDb: f.task.panFileDb,
syncFileDb: f.task.syncFileDb,
panClient: f.task.panClient,
syncItem: file,
2022-06-12 17:03:05 +08:00
maxDownloadRate: f.maxDownloadRate,
maxUploadRate: f.maxUploadRate,
2022-06-05 22:19:16 +08:00
panFolderCreateMutex: f.folderCreateMutex,
2022-06-04 13:20:33 +08:00
}
2022-06-01 21:55:03 +08:00
}
}
}
}
if files, e := f.task.syncFileDb.GetFileList(SyncFileStatusCreate); e == nil {
if len(files) > 0 {
for _, file := range files {
2022-06-04 13:20:33 +08:00
if file.Action == act && !f.fileInProcessQueue.Contains(file) {
2022-06-01 21:55:03 +08:00
return &FileActionTask{
2022-06-05 22:19:16 +08:00
localFileDb: f.task.localFileDb,
panFileDb: f.task.panFileDb,
syncFileDb: f.task.syncFileDb,
panClient: f.task.panClient,
syncItem: file,
2022-06-12 17:03:05 +08:00
maxDownloadRate: f.maxDownloadRate,
maxUploadRate: f.maxUploadRate,
2022-06-05 22:19:16 +08:00
panFolderCreateMutex: f.folderCreateMutex,
2022-06-01 21:55:03 +08:00
}
}
}
}
}
2022-05-24 23:01:08 +08:00
return nil
}
2022-06-01 21:55:03 +08:00
2022-06-04 13:20:33 +08:00
// cleanSyncDbRecords 清楚同步数据库无用数据
func (f *FileActionTaskManager) cleanSyncDbRecords(ctx context.Context) {
// TODO: failed / success / illegal
}
2022-06-01 21:55:03 +08:00
// fileActionTaskExecutor 异步执行文件操作
func (f *FileActionTaskManager) fileActionTaskExecutor(ctx context.Context) {
f.wg.AddDelta()
defer f.wg.Done()
2022-06-04 13:20:33 +08:00
downloadWaitGroup := waitgroup.NewWaitGroup(f.fileDownloadParallel)
2022-06-05 22:19:16 +08:00
uploadWaitGroup := waitgroup.NewWaitGroup(f.fileUploadParallel)
2022-06-09 14:52:49 +08:00
deleteLocalWaitGroup := waitgroup.NewWaitGroup(1)
deletePanWaitGroup := waitgroup.NewWaitGroup(1)
2022-06-04 13:20:33 +08:00
2022-06-01 21:55:03 +08:00
for {
select {
case <-ctx.Done():
// cancel routine & done
logger.Verboseln("file executor routine done")
2022-06-04 13:20:33 +08:00
downloadWaitGroup.Wait()
2022-06-01 21:55:03 +08:00
return
default:
2022-06-12 17:44:16 +08:00
//logger.Verboseln("do file executor process")
2022-06-01 21:55:03 +08:00
// do upload
2022-06-05 22:19:16 +08:00
uploadItem := f.getFromSyncDb(SyncFileActionUpload)
if uploadItem != nil {
if uploadWaitGroup.Parallel() < f.fileUploadParallel {
uploadWaitGroup.AddDelta()
f.fileInProcessQueue.PushUnique(uploadItem.syncItem)
go func() {
if e := uploadItem.DoAction(ctx); e == nil {
// success
2022-06-09 14:52:49 +08:00
f.fileInProcessQueue.Remove(uploadItem.syncItem)
2022-06-05 22:19:16 +08:00
} else {
// retry?
2022-06-09 14:52:49 +08:00
f.fileInProcessQueue.Remove(uploadItem.syncItem)
2022-06-05 22:19:16 +08:00
}
uploadWaitGroup.Done()
}()
}
}
2022-06-01 21:55:03 +08:00
// do download
2022-06-04 13:20:33 +08:00
downloadItem := f.getFromSyncDb(SyncFileActionDownload)
2022-06-01 21:55:03 +08:00
if downloadItem != nil {
2022-06-04 13:20:33 +08:00
if downloadWaitGroup.Parallel() < f.fileDownloadParallel {
downloadWaitGroup.AddDelta()
f.fileInProcessQueue.PushUnique(downloadItem.syncItem)
go func() {
2022-06-05 00:00:28 +08:00
if e := downloadItem.DoAction(ctx); e == nil {
2022-06-04 13:20:33 +08:00
// success
2022-06-09 14:52:49 +08:00
f.fileInProcessQueue.Remove(downloadItem.syncItem)
2022-06-04 13:20:33 +08:00
} else {
// retry?
2022-06-09 14:52:49 +08:00
f.fileInProcessQueue.Remove(downloadItem.syncItem)
2022-06-04 13:20:33 +08:00
}
downloadWaitGroup.Done()
}()
}
2022-06-01 21:55:03 +08:00
}
2022-06-09 14:52:49 +08:00
// delete local
deleteLocalItem := f.getFromSyncDb(SyncFileActionDeleteLocal)
if deleteLocalItem != nil {
if deleteLocalWaitGroup.Parallel() < 1 {
deleteLocalWaitGroup.AddDelta()
f.fileInProcessQueue.PushUnique(deleteLocalItem.syncItem)
go func() {
if e := deleteLocalItem.DoAction(ctx); e == nil {
// success
f.fileInProcessQueue.Remove(deleteLocalItem.syncItem)
} else {
// retry?
f.fileInProcessQueue.Remove(deleteLocalItem.syncItem)
}
deleteLocalWaitGroup.Done()
}()
}
}
// delete pan
deletePanItem := f.getFromSyncDb(SyncFileActionDeletePan)
if deletePanItem != nil {
if deletePanWaitGroup.Parallel() < 1 {
deletePanWaitGroup.AddDelta()
f.fileInProcessQueue.PushUnique(deletePanItem.syncItem)
go func() {
if e := deletePanItem.DoAction(ctx); e == nil {
// success
f.fileInProcessQueue.Remove(deletePanItem.syncItem)
} else {
// retry?
f.fileInProcessQueue.Remove(deletePanItem.syncItem)
}
deletePanWaitGroup.Done()
}()
}
}
2022-06-01 21:55:03 +08:00
// delay
time.Sleep(500 * time.Millisecond)
}
}
}
// getRelativePath 获取文件的相对路径
func (l *localFileSet) getRelativePath(localPath string) string {
localPath = strings.ReplaceAll(localPath, "\\", "/")
localRootPath := strings.ReplaceAll(l.localFolderPath, "\\", "/")
relativePath := strings.TrimPrefix(localPath, localRootPath)
return path.Clean(relativePath)
}
// Intersection 交集
func (l *localFileSet) Intersection(other *panFileSet) (LocalFileList, PanFileList) {
localFilePathSet := mapset.NewThreadUnsafeSet()
relativePathLocalMap := map[string]*LocalFileItem{}
for _, item := range l.items {
rp := l.getRelativePath(item.Path)
relativePathLocalMap[rp] = item
localFilePathSet.Add(rp)
}
localFileList := LocalFileList{}
panFileList := PanFileList{}
for _, item := range other.items {
rp := other.getRelativePath(item.Path)
if localFilePathSet.Contains(rp) {
localFileList = append(localFileList, relativePathLocalMap[rp])
panFileList = append(panFileList, item)
}
}
return localFileList, panFileList
}
// Difference 差集
func (l *localFileSet) Difference(other *panFileSet) LocalFileList {
panFilePathSet := mapset.NewThreadUnsafeSet()
for _, item := range other.items {
rp := other.getRelativePath(item.Path)
panFilePathSet.Add(rp)
}
localFileList := LocalFileList{}
for _, item := range l.items {
rp := l.getRelativePath(item.Path)
if !panFilePathSet.Contains(rp) {
localFileList = append(localFileList, item)
}
}
return localFileList
}
// getRelativePath 获取文件的相对路径
func (p *panFileSet) getRelativePath(panPath string) string {
panPath = strings.ReplaceAll(panPath, "\\", "/")
panRootPath := strings.ReplaceAll(p.panFolderPath, "\\", "/")
relativePath := strings.TrimPrefix(panPath, panRootPath)
return path.Clean(relativePath)
}
// Intersection 交集
func (p *panFileSet) Intersection(other *localFileSet) (PanFileList, LocalFileList) {
localFilePathSet := mapset.NewThreadUnsafeSet()
relativePathLocalMap := map[string]*LocalFileItem{}
for _, item := range other.items {
rp := other.getRelativePath(item.Path)
relativePathLocalMap[rp] = item
localFilePathSet.Add(rp)
}
localFileList := LocalFileList{}
panFileList := PanFileList{}
for _, item := range p.items {
rp := p.getRelativePath(item.Path)
if localFilePathSet.Contains(rp) {
localFileList = append(localFileList, relativePathLocalMap[rp])
panFileList = append(panFileList, item)
}
}
return panFileList, localFileList
}
// Difference 差集
func (p *panFileSet) Difference(other *localFileSet) PanFileList {
localFilePathSet := mapset.NewThreadUnsafeSet()
for _, item := range other.items {
rp := other.getRelativePath(item.Path)
localFilePathSet.Add(rp)
}
panFileList := PanFileList{}
for _, item := range p.items {
rp := p.getRelativePath(item.Path)
if !localFilePathSet.Contains(rp) {
panFileList = append(panFileList, item)
}
}
return panFileList
}