github.com/fzfile/BaiduPCS-Go@v0.0.0-20200606205115-4408961cf336/internal/pcscommand/upload.go (about)

     1  package pcscommand
     2  
     3  import (
     4  	"fmt"
     5  	"github.com/fzfile/BaiduPCS-Go/baidupcs"
     6  	"github.com/fzfile/BaiduPCS-Go/internal/pcsconfig"
     7  	"github.com/fzfile/BaiduPCS-Go/internal/pcsfunctions/pcsupload"
     8  	"github.com/fzfile/BaiduPCS-Go/pcstable"
     9  	"github.com/fzfile/BaiduPCS-Go/pcsutil"
    10  	"github.com/fzfile/BaiduPCS-Go/pcsutil/checksum"
    11  	"github.com/fzfile/BaiduPCS-Go/pcsutil/converter"
    12  	"github.com/fzfile/BaiduPCS-Go/pcsutil/taskframework"
    13  	"os"
    14  	"path"
    15  	"path/filepath"
    16  	"strings"
    17  )
    18  
    19  const (
    20  	// DefaultUploadMaxRetry 默认上传失败最大重试次数
    21  	DefaultUploadMaxRetry = 3
    22  )
    23  
    24  type (
    25  	// UploadOptions 上传可选项
    26  	UploadOptions struct {
    27  		Parallel      int
    28  		MaxRetry      int
    29  		NoRapidUpload bool
    30  		NoSplitFile   bool // 禁用分片上传
    31  	}
    32  )
    33  
    34  // RunRapidUpload 执行秒传文件, 前提是知道文件的大小, md5, 前256KB切片的 md5, crc32
    35  func RunRapidUpload(targetPath, contentMD5, sliceMD5, crc32 string, length int64) {
    36  	err := matchPathByShellPatternOnce(&targetPath)
    37  	if err != nil {
    38  		fmt.Printf("警告: %s, 获取网盘路径 %s 错误, %s\n", baidupcs.OperationRapidUpload, targetPath, err)
    39  	}
    40  
    41  	err = GetBaiduPCS().RapidUpload(targetPath, contentMD5, sliceMD5, crc32, length)
    42  	if err != nil {
    43  		fmt.Printf("%s失败, 消息: %s\n", baidupcs.OperationRapidUpload, err)
    44  		return
    45  	}
    46  
    47  	fmt.Printf("%s成功, 保存到网盘路径: %s\n", baidupcs.OperationRapidUpload, targetPath)
    48  	return
    49  }
    50  
    51  // RunCreateSuperFile 执行分片上传—合并分片文件
    52  func RunCreateSuperFile(targetPath string, blockList ...string) {
    53  	err := matchPathByShellPatternOnce(&targetPath)
    54  	if err != nil {
    55  		fmt.Printf("警告: %s, 获取网盘路径 %s 错误, %s\n", baidupcs.OperationUploadCreateSuperFile, targetPath, err)
    56  	}
    57  
    58  	err = GetBaiduPCS().UploadCreateSuperFile(true, targetPath, blockList...)
    59  	if err != nil {
    60  		fmt.Printf("%s失败, 消息: %s\n", baidupcs.OperationUploadCreateSuperFile, err)
    61  		return
    62  	}
    63  
    64  	fmt.Printf("%s成功, 保存到网盘路径: %s\n", baidupcs.OperationUploadCreateSuperFile, targetPath)
    65  	return
    66  }
    67  
    68  // RunUpload 执行文件上传
    69  func RunUpload(localPaths []string, savePath string, opt *UploadOptions) {
    70  	if opt == nil {
    71  		opt = &UploadOptions{}
    72  	}
    73  
    74  	// 检测opt
    75  	if opt.Parallel <= 0 {
    76  		opt.Parallel = pcsconfig.Config.MaxUploadParallel
    77  	}
    78  
    79  	if opt.MaxRetry < 0 {
    80  		opt.MaxRetry = DefaultUploadMaxRetry
    81  	}
    82  
    83  	err := matchPathByShellPatternOnce(&savePath)
    84  	if err != nil {
    85  		fmt.Printf("警告: 上传文件, 获取网盘路径 %s 错误, %s\n", savePath, err)
    86  	}
    87  
    88  	switch len(localPaths) {
    89  	case 0:
    90  		fmt.Printf("本地路径为空\n")
    91  		return
    92  	}
    93  
    94  	// 打开上传状态
    95  	uploadDatabase, err := pcsupload.NewUploadingDatabase()
    96  	if err != nil {
    97  		fmt.Printf("打开上传未完成数据库错误: %s\n", err)
    98  		return
    99  	}
   100  	defer uploadDatabase.Close()
   101  
   102  	var (
   103  		pcs = GetBaiduPCS()
   104  		// 使用 task framework
   105  		executor = &taskframework.TaskExecutor{
   106  			IsFailedDeque: true, // 失败统计
   107  		}
   108  		subSavePath string
   109  		// 统计
   110  		statistic = &pcsupload.UploadStatistic{}
   111  	)
   112  
   113  	statistic.StartTimer() // 开始计时
   114  
   115  	for k := range localPaths {
   116  		walkedFiles, err := pcsutil.WalkDir(localPaths[k], "")
   117  		if err != nil {
   118  			fmt.Printf("警告: 遍历错误: %s\n", err)
   119  			continue
   120  		}
   121  
   122  		for k3 := range walkedFiles {
   123  			var localPathDir string
   124  			// 针对 windows 的目录处理
   125  			if os.PathSeparator == '\\' {
   126  				walkedFiles[k3] = pcsutil.ConvertToUnixPathSeparator(walkedFiles[k3])
   127  				localPathDir = pcsutil.ConvertToUnixPathSeparator(filepath.Dir(localPaths[k]))
   128  			} else {
   129  				localPathDir = filepath.Dir(localPaths[k])
   130  			}
   131  
   132  			// 避免去除文件名开头的"."
   133  			if localPathDir == "." {
   134  				localPathDir = ""
   135  			}
   136  
   137  			subSavePath = strings.TrimPrefix(walkedFiles[k3], localPathDir)
   138  
   139  			info := executor.Append(&pcsupload.UploadTaskUnit{
   140  				LocalFileChecksum: checksum.NewLocalFileChecksum(walkedFiles[k3], int(baidupcs.SliceMD5Size)),
   141  				SavePath:          path.Clean(savePath + baidupcs.PathSeparator + subSavePath),
   142  				PCS:               pcs,
   143  				UploadingDatabase: uploadDatabase,
   144  				Parallel:          opt.Parallel,
   145  				NoRapidUpload:     opt.NoRapidUpload,
   146  				NoSplitFile:       opt.NoSplitFile,
   147  				UploadStatistic:   statistic,
   148  			}, opt.MaxRetry)
   149  			fmt.Printf("[%s] 加入上传队列: %s\n", info.Id(), walkedFiles[k3])
   150  		}
   151  	}
   152  
   153  	// 没有添加任何任务
   154  	if executor.Count() == 0 {
   155  		fmt.Printf("未检测到上传的文件.\n")
   156  		return
   157  	}
   158  
   159  	// 执行上传任务
   160  	executor.Execute()
   161  
   162  	fmt.Printf("\n")
   163  	fmt.Printf("上传结束, 时间: %s, 总大小: %s\n", statistic.Elapsed()/1e6*1e6, converter.ConvertFileSize(statistic.TotalSize()))
   164  
   165  	// 输出上传失败的文件列表
   166  	failedList := executor.FailedDeque()
   167  	if failedList.Size() != 0 {
   168  		fmt.Printf("以下文件上传失败: \n")
   169  		tb := pcstable.NewTable(os.Stdout)
   170  		for e := failedList.Shift(); e != nil; e = failedList.Shift() {
   171  			item := e.(*taskframework.TaskInfoItem)
   172  			tb.Append([]string{item.Info.Id(), item.Unit.(*pcsupload.UploadTaskUnit).LocalFileChecksum.Path})
   173  		}
   174  		tb.Render()
   175  	}
   176  }