aliyunpan/internal/command/sync.go

327 lines
12 KiB
Go
Raw Normal View History

2022-06-09 19:58:16 +08:00
// Copyright (c) 2020 tickstep.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package command
import (
"fmt"
2022-06-10 13:55:00 +08:00
"github.com/tickstep/aliyunpan-api/aliyunpan"
2022-06-09 19:58:16 +08:00
"github.com/tickstep/aliyunpan/cmder"
"github.com/tickstep/aliyunpan/internal/config"
"github.com/tickstep/aliyunpan/internal/syncdrive"
"github.com/tickstep/aliyunpan/internal/utils"
2022-06-10 14:36:52 +08:00
"github.com/tickstep/library-go/converter"
2022-06-09 19:58:16 +08:00
"github.com/tickstep/library-go/logger"
"github.com/urfave/cli"
"os"
2022-06-17 10:27:53 +08:00
"path"
2022-06-09 19:58:16 +08:00
"strings"
"time"
)
func CmdSync() cli.Command {
return cli.Command{
Name: "sync",
Usage: "同步备份功能(Beta)",
UsageText: cmder.App().Name + " sync",
Description: `
2022-06-17 10:27:53 +08:00
备份功能支持备份本地文件到云盘备份云盘文件到本地双向同步备份三种模式支持JavaScript插件对备份文件进行过滤
指定本地目录和对应的一个网盘目录以备份文件网盘目录必须和本地目录独占使用不要用作其他用途不然备份可能会有问题
2022-06-17 10:27:53 +08:00
2022-06-10 22:39:54 +08:00
备份功能支持以下三种模式
2022-06-09 20:05:30 +08:00
1. upload
备份本地文件即上传本地文件到网盘始终保持本地文件有一个完整的备份在网盘
2. download
备份云盘文件即下载网盘文件到本地始终保持网盘的文件有一个完整的备份在本地
2022-06-12 17:44:16 +08:00
3. sync慎用双向备份过程会删除文件
2022-06-09 20:05:30 +08:00
双向备份保持网盘文件和本地文件严格一致
2022-06-09 19:58:16 +08:00
2022-06-10 22:39:54 +08:00
请输入以下命令查看如何配置和启动
aliyunpan sync start -h
2022-06-09 19:58:16 +08:00
`,
Category: "阿里云盘",
Before: cmder.ReloadConfigFunc,
Action: func(c *cli.Context) error {
2022-06-10 22:39:54 +08:00
cli.ShowCommandHelp(c, c.Command.Name)
return nil
},
Subcommands: []cli.Command{
{
Name: "start",
Usage: "启动sync同步备份任务",
UsageText: cmder.App().Name + " sync start [arguments...]",
Description: `
2022-06-17 10:27:53 +08:00
备份本地文件到文件网盘或者备份文件网盘的文件到本地支持命令行配置启动或者使用备份配置文件启动同步备份任务
配置文件保存在(配置目录)/sync_drive/sync_drive_config.json样例如下
2022-06-10 22:39:54 +08:00
{
"configVer": "1.0",
"syncTaskList": [
{
"name": "设计文档备份",
"localFolderPath": "D:/tickstep/Documents/设计文档",
2022-06-10 22:39:54 +08:00
"panFolderPath": "/sync_drive/我的文档",
"mode": "upload"
}
]
}
相关字段说明如下
name - 任务名称
localFolderPath - 本地目录
panFolderPath - 网盘目录
mode - 模式支持三种: upload(备份本地文件到云盘),download(备份云盘文件到本地),sync(双向同步备份)
2022-06-17 10:27:53 +08:00
2022-06-10 22:39:54 +08:00
例子:
1. 查看帮助
aliyunpan sync start -h
2022-06-17 10:27:53 +08:00
2. 使用命令行配置启动同步备份服务将本地目录 D:\tickstep\Documents\设计文档 中的文件备份上传到云盘目录 /sync_drive/我的文档
aliyunpan sync start -ldir "D:\tickstep\Documents\设计文档" -pdir "/sync_drive/我的文档" -mode "upload"
3. 使用命令行配置启动同步备份服务将云盘目录 /sync_drive/我的文档 中的文件备份下载到本地目录 D:\tickstep\Documents\设计文档
aliyunpan sync start -ldir "D:\tickstep\Documents\设计文档" -pdir "/sync_drive/我的文档" -mode "download"
2022-06-10 13:55:00 +08:00
4. 使用命令行配置启动同步备份服务将云盘目录 /sync_drive/我的文档 和本地目录 D:\tickstep\Documents\设计文档 的文件进行双向同步
同时配置同步优先选项为本地文件优先
aliyunpan sync start -ldir "D:\tickstep\Documents\设计文档" -pdir "/sync_drive/我的文档" -mode "sync" -pri "local"
5. 使用命令行配置启动同步备份服务将本地目录 D:\tickstep\Documents\设计文档 中的文件备份到云盘目录 /sync_drive/我的文档
2022-06-17 10:27:53 +08:00
同时配置下载并发为2上传并发为1下载分片大小为256KB上传分片大小为1MB
aliyunpan sync start -ldir "D:\tickstep\Documents\设计文档" -pdir "/sync_drive/我的文档" -mode "upload" -dp 2 -up 1 -dbs 256 -ubs 1024
6. 使用配置文件启动同步备份服务使用配置文件可以支持同时启动多个备份任务配置文件必须存在否则启动失败
2022-06-10 22:39:54 +08:00
aliyunpan sync start
2022-06-10 13:55:00 +08:00
7. 使用配置文件启动同步备份服务并配置下载并发为2上传并发为1下载分片大小为256KB上传分片大小为1MB
aliyunpan sync start -dp 2 -up 1 -dbs 256 -ubs 1024
2022-06-10 13:55:00 +08:00
2022-06-10 22:39:54 +08:00
`,
Action: func(c *cli.Context) error {
if config.Config.ActiveUser() == nil {
fmt.Println("未登录账号")
return nil
}
activeUser := GetActiveUser()
2022-06-10 22:39:54 +08:00
dp := c.Int("dp")
if dp == 0 {
dp = config.Config.MaxDownloadParallel
}
if dp == 0 {
dp = 2
}
up := c.Int("up")
if up == 0 {
up = config.Config.MaxUploadParallel
}
if up == 0 {
up = 2
}
downloadBlockSize := int64(c.Int("dbs") * 1024)
if downloadBlockSize == 0 {
downloadBlockSize = int64(config.Config.CacheSize)
}
2022-06-10 22:39:54 +08:00
if downloadBlockSize == 0 {
downloadBlockSize = int64(256 * 1024)
}
uploadBlockSize := int64(c.Int("ubs") * 1024)
if uploadBlockSize == 0 {
uploadBlockSize = aliyunpan.DefaultChunkSize
}
2022-06-17 10:27:53 +08:00
var task *syncdrive.SyncTask
localDir := c.String("ldir")
panDir := c.String("pdir")
2022-06-17 23:37:32 +08:00
mode := c.String("mode")
// make path absolute
if !utils.IsAbsPath(localDir) {
pwd, _ := os.Getwd()
2022-08-09 20:33:46 +08:00
localDir = path.Join(pwd, path.Clean(localDir))
}
panDir = activeUser.PathJoin(activeUser.ActiveDriveId, panDir)
2022-06-17 10:27:53 +08:00
if localDir != "" && panDir != "" {
if !utils.IsAbsPath(localDir) {
fmt.Println("本地目录请指定绝对路径")
return nil
}
if !path.IsAbs(panDir) {
fmt.Println("网盘目录请指定绝对路径")
return nil
}
2022-06-17 23:37:32 +08:00
//if b, e := utils.PathExists(localDir); e == nil {
// if !b {
// fmt.Println("本地文件夹不存在:", localDir)
// return nil
// }
//} else {
// fmt.Println("本地文件夹不存在:", localDir)
// return nil
//}
2022-06-17 10:27:53 +08:00
task = &syncdrive.SyncTask{}
task.LocalFolderPath = path.Clean(strings.ReplaceAll(localDir, "\\", "/"))
task.PanFolderPath = panDir
2022-06-17 23:37:32 +08:00
task.Mode = syncdrive.UploadOnly
if mode == string(syncdrive.UploadOnly) {
task.Mode = syncdrive.UploadOnly
} else if mode == string(syncdrive.DownloadOnly) {
task.Mode = syncdrive.DownloadOnly
} else if mode == string(syncdrive.SyncTwoWay) {
task.Mode = syncdrive.SyncTwoWay
} else {
2022-06-17 10:27:53 +08:00
task.Mode = syncdrive.UploadOnly
}
task.Name = path.Base(task.LocalFolderPath)
task.Id = utils.Md5Str(task.LocalFolderPath)
}
opt := c.String("pri")
var syncOpt syncdrive.SyncPriorityOption = syncdrive.SyncPriorityTimestampFirst
if opt == "local" {
syncOpt = syncdrive.SyncPriorityLocalFirst
} else if opt == "pan" {
syncOpt = syncdrive.SyncPriorityPanFirst
} else {
syncOpt = syncdrive.SyncPriorityTimestampFirst
}
2022-06-17 10:27:53 +08:00
RunSync(task, dp, up, downloadBlockSize, uploadBlockSize, syncOpt)
2022-06-10 22:39:54 +08:00
return nil
},
Flags: []cli.Flag{
2022-06-17 10:27:53 +08:00
cli.StringFlag{
Name: "ldir",
Usage: "local dir, 本地文件夹完整路径",
},
cli.StringFlag{
Name: "pdir",
Usage: "pan dir, 云盘文件夹完整路径",
},
cli.StringFlag{
Name: "mode",
Usage: "备份模式, 支持三种: upload(备份本地文件到云盘),download(备份云盘文件到本地),sync(双向同步备份)",
Value: "upload",
},
cli.StringFlag{
Name: "pri",
Usage: "优先级priority只对双向同步备份模式有效。当网盘和本地存在同名文件优先使用哪个选项支持三种: time-时间优先local-本地优先pan-网盘优先",
Value: "time",
},
2022-06-10 22:39:54 +08:00
cli.IntFlag{
Name: "dp",
Usage: "download parallel, 下载并发数量即可以同时并发下载多少个文件。0代表跟从配置文件设置取值范围:1 ~ 10",
Value: 0,
},
cli.IntFlag{
Name: "up",
Usage: "upload parallel, 上传并发数量即可以同时并发上传多少个文件。0代表跟从配置文件设置取值范围:1 ~ 10",
Value: 0,
},
cli.IntFlag{
Name: "dbs",
2022-06-12 17:03:05 +08:00
Usage: "download block size下载分片大小单位KB。推荐值1024 ~ 10240",
Value: 1024,
},
2022-06-10 22:39:54 +08:00
cli.IntFlag{
Name: "ubs",
Usage: "upload block size上传分片大小单位KB。推荐值1024 ~ 10240",
Value: 10240,
},
},
2022-06-09 19:58:16 +08:00
},
},
}
}
func RunSync(defaultTask *syncdrive.SyncTask, fileDownloadParallel, fileUploadParallel int, downloadBlockSize, uploadBlockSize int64,
flag syncdrive.SyncPriorityOption) {
2022-06-10 14:36:52 +08:00
useInternalUrl := config.Config.TransferUrlType == 2
2022-06-12 17:03:05 +08:00
maxDownloadRate := config.Config.MaxDownloadRate
maxUploadRate := config.Config.MaxUploadRate
2022-06-09 19:58:16 +08:00
activeUser := GetActiveUser()
panClient := activeUser.PanClient()
2022-08-13 16:54:42 +08:00
panClient.DisableCache()
2022-06-09 19:58:16 +08:00
// pan token expired checker
go func() {
for {
time.Sleep(time.Duration(1) * time.Minute)
if RefreshTokenInNeed(activeUser) {
logger.Verboseln("update access token for sync task")
panClient.UpdateToken(activeUser.WebToken)
}
}
}()
syncFolderRootPath := config.GetSyncDriveDir()
if b, e := utils.PathExists(syncFolderRootPath); e == nil {
if !b {
2022-06-16 22:30:12 +08:00
os.MkdirAll(syncFolderRootPath, 0755)
2022-06-09 19:58:16 +08:00
}
}
2022-06-17 10:27:53 +08:00
var tasks []*syncdrive.SyncTask
if defaultTask != nil {
tasks = []*syncdrive.SyncTask{}
tasks = append(tasks, defaultTask)
}
2022-06-09 19:58:16 +08:00
fmt.Println("启动同步备份进程")
typeUrlStr := "默认链接"
2022-06-10 14:36:52 +08:00
if useInternalUrl {
typeUrlStr = "阿里ECS内部链接"
}
2022-08-13 16:54:42 +08:00
option := syncdrive.SyncOption{
FileDownloadParallel: fileDownloadParallel,
FileUploadParallel: fileUploadParallel,
FileDownloadBlockSize: downloadBlockSize,
FileUploadBlockSize: uploadBlockSize,
UseInternalUrl: useInternalUrl,
MaxDownloadRate: maxDownloadRate,
MaxUploadRate: maxUploadRate,
SyncPriority: flag,
2022-08-13 16:54:42 +08:00
}
syncMgr := syncdrive.NewSyncTaskManager(activeUser, activeUser.DriveList.GetFileDriveId(), panClient, syncFolderRootPath, option)
2022-06-17 10:27:53 +08:00
syncConfigFile := syncMgr.ConfigFilePath()
if tasks != nil {
syncConfigFile = "(使用命令行配置)"
}
2022-06-10 22:48:29 +08:00
fmt.Printf("备份配置文件:%s\n链接类型%s\n下载并发%d\n上传并发%d\n下载分片大小%s\n上传分片大小%s\n",
2022-06-17 10:27:53 +08:00
syncConfigFile, typeUrlStr, fileDownloadParallel, fileUploadParallel, converter.ConvertFileSize(downloadBlockSize, 2),
2022-06-10 22:48:29 +08:00
converter.ConvertFileSize(uploadBlockSize, 2))
2022-06-17 10:27:53 +08:00
if _, e := syncMgr.Start(tasks); e != nil {
2022-06-09 19:58:16 +08:00
fmt.Println("启动任务失败:", e)
return
}
_, ok := os.LookupEnv("ALIYUNPAN_DOCKER")
if ok {
// in docker container
// 使用休眠以节省CPU资源
for {
time.Sleep(60 * time.Second)
}
} else {
// in cmd mode
c := ""
fmt.Print("本命令不会退出如需要结束同步备份进程请输入y然后按Enter键进行停止")
for strings.ToLower(c) != "y" {
fmt.Scan(&c)
}
2022-06-09 19:58:16 +08:00
}
2022-06-09 19:58:16 +08:00
fmt.Println("正在停止同步备份任务,请稍等...")
syncMgr.Stop()
}