github.com/qjfoidnh/BaiduPCS-Go@v0.0.0-20231011165705-caa18a3765f3/requester/uploader/multiuploader.go (about)

     1  package uploader
     2  
     3  import (
     4  	"context"
     5  	"github.com/qjfoidnh/BaiduPCS-Go/baidupcs/pcserror"
     6  	"github.com/qjfoidnh/BaiduPCS-Go/pcsutil"
     7  	"github.com/qjfoidnh/BaiduPCS-Go/pcsutil/converter"
     8  	"github.com/qjfoidnh/BaiduPCS-Go/requester"
     9  	"github.com/qjfoidnh/BaiduPCS-Go/requester/rio"
    10  	"github.com/qjfoidnh/BaiduPCS-Go/requester/rio/speeds"
    11  	"sync"
    12  	"time"
    13  )
    14  
    15  type (
    16  	// MultiUpload 支持多线程的上传, 可用于断点续传
    17  	MultiUpload interface {
    18  		Precreate(fileSize int64, policy string) (err pcserror.Error)
    19  		TmpFile(ctx context.Context, partseq int, partOffset int64, readerlen64 rio.ReaderLen64) (checksum string, terr error)
    20  		CreateSuperFile(policy string, checksumList ...string) (cerr error)
    21  	}
    22  
    23  	// MultiUploader 多线程上传
    24  	MultiUploader struct {
    25  		onExecuteEvent      requester.Event        //开始上传事件
    26  		onSuccessEvent      requester.Event        //成功上传事件
    27  		onFinishEvent       requester.Event        //结束上传事件
    28  		onCancelEvent       requester.Event        //取消上传事件
    29  		onErrorEvent        requester.EventOnError //上传出错事件
    30  		onUploadStatusEvent UploadStatusFunc       //上传状态事件
    31  
    32  		instanceState *InstanceState
    33  
    34  		multiUpload MultiUpload       // 上传体接口
    35  		file        rio.ReaderAtLen64 // 上传
    36  		config      *MultiUploaderConfig
    37  		workers     workerList
    38  		speedsStat  *speeds.Speeds
    39  		rateLimit   *speeds.RateLimit
    40  
    41  		executeTime             time.Time
    42  		finished                chan struct{}
    43  		canceled                chan struct{}
    44  		closeCanceledOnce       sync.Once
    45  		updateInstanceStateChan chan struct{}
    46  	}
    47  
    48  	// MultiUploaderConfig 多线程上传配置
    49  	MultiUploaderConfig struct {
    50  		Parallel  int   // 上传并发量
    51  		BlockSize int64 // 上传分块
    52  		MaxRate   int64 // 限制最大上传速度
    53  		Policy    string  // 文件重名策略
    54  	}
    55  )
    56  
    57  // NewMultiUploader 初始化上传
    58  func NewMultiUploader(multiUpload MultiUpload, file rio.ReaderAtLen64, config *MultiUploaderConfig) *MultiUploader {
    59  	return &MultiUploader{
    60  		multiUpload: multiUpload,
    61  		file:        file,
    62  		config:      config,
    63  	}
    64  }
    65  
    66  // SetInstanceState 设置InstanceState, 断点续传信息
    67  func (muer *MultiUploader) SetInstanceState(is *InstanceState) {
    68  	muer.instanceState = is
    69  }
    70  
    71  func (muer *MultiUploader) lazyInit() {
    72  	if muer.finished == nil {
    73  		muer.finished = make(chan struct{}, 1)
    74  	}
    75  	if muer.canceled == nil {
    76  		muer.canceled = make(chan struct{})
    77  	}
    78  	if muer.updateInstanceStateChan == nil {
    79  		muer.updateInstanceStateChan = make(chan struct{}, 1)
    80  	}
    81  	if muer.config == nil {
    82  		muer.config = &MultiUploaderConfig{}
    83  	}
    84  	if muer.config.Parallel <= 0 {
    85  		muer.config.Parallel = 4
    86  	}
    87  	if muer.config.BlockSize <= 0 {
    88  		muer.config.BlockSize = 1 * converter.GB
    89  	}
    90  	if muer.speedsStat == nil {
    91  		muer.speedsStat = &speeds.Speeds{}
    92  	}
    93  }
    94  
    95  func (muer *MultiUploader) check() {
    96  	if muer.file == nil {
    97  		panic("file is nil")
    98  	}
    99  	if muer.multiUpload == nil {
   100  		panic("multiUpload is nil")
   101  	}
   102  }
   103  
   104  // Execute 执行上传
   105  func (muer *MultiUploader) Execute() {
   106  	muer.check()
   107  	muer.lazyInit()
   108  	// 初始化限速
   109  	if muer.config.MaxRate > 0 {
   110  		muer.rateLimit = speeds.NewRateLimit(muer.config.MaxRate)
   111  		defer muer.rateLimit.Stop()
   112  	}
   113  
   114  	// 分配任务
   115  	if muer.instanceState != nil {
   116  		muer.workers = muer.getWorkerListByInstanceState(muer.instanceState)
   117  		uploaderVerbose.Infof("upload task CREATED from instance state\n")
   118  	} else {
   119  		muer.workers = muer.getWorkerListByInstanceState(&InstanceState{
   120  			BlockList: SplitBlock(muer.file.Len(), muer.config.BlockSize),
   121  		})
   122  
   123  		uploaderVerbose.Infof("upload task CREATED: block size: %d, num: %d\n", muer.config.BlockSize, len(muer.workers))
   124  	}
   125  
   126  	// 开始上传
   127  	muer.executeTime = time.Now()
   128  	pcsutil.Trigger(muer.onExecuteEvent)
   129  
   130  	muer.uploadStatusEvent()
   131  
   132  	err := muer.upload()
   133  
   134  	// 完成
   135  	muer.finished <- struct{}{}
   136  	if err != nil {
   137  		if err == context.Canceled {
   138  			if muer.onCancelEvent != nil {
   139  				muer.onCancelEvent()
   140  			}
   141  		} else if muer.onErrorEvent != nil {
   142  			muer.onErrorEvent(err)
   143  		}
   144  	} else {
   145  		pcsutil.TriggerOnSync(muer.onSuccessEvent)
   146  	}
   147  	pcsutil.TriggerOnSync(muer.onFinishEvent)
   148  }
   149  
   150  // InstanceState 返回断点续传信息
   151  func (muer *MultiUploader) InstanceState() *InstanceState {
   152  	blockStates := make([]*BlockState, 0, len(muer.workers))
   153  	for _, wer := range muer.workers {
   154  		blockStates = append(blockStates, &BlockState{
   155  			ID:       wer.id,
   156  			Range:    wer.splitUnit.Range(),
   157  			CheckSum: wer.checksum,
   158  		})
   159  	}
   160  	return &InstanceState{
   161  		BlockList: blockStates,
   162  	}
   163  }
   164  
   165  // Cancel 取消上传
   166  func (muer *MultiUploader) Cancel() {
   167  	close(muer.canceled)
   168  }
   169  
   170  //OnExecute 设置开始上传事件
   171  func (muer *MultiUploader) OnExecute(onExecuteEvent requester.Event) {
   172  	muer.onExecuteEvent = onExecuteEvent
   173  }
   174  
   175  //OnSuccess 设置成功上传事件
   176  func (muer *MultiUploader) OnSuccess(onSuccessEvent requester.Event) {
   177  	muer.onSuccessEvent = onSuccessEvent
   178  }
   179  
   180  //OnFinish 设置结束上传事件
   181  func (muer *MultiUploader) OnFinish(onFinishEvent requester.Event) {
   182  	muer.onFinishEvent = onFinishEvent
   183  }
   184  
   185  //OnCancel 设置取消上传事件
   186  func (muer *MultiUploader) OnCancel(onCancelEvent requester.Event) {
   187  	muer.onCancelEvent = onCancelEvent
   188  }
   189  
   190  //OnError 设置上传发生错误事件
   191  func (muer *MultiUploader) OnError(onErrorEvent requester.EventOnError) {
   192  	muer.onErrorEvent = onErrorEvent
   193  }
   194  
   195  //OnUploadStatusEvent 设置上传状态事件
   196  func (muer *MultiUploader) OnUploadStatusEvent(f UploadStatusFunc) {
   197  	muer.onUploadStatusEvent = f
   198  }