github.com/iikira/iikira-go-utils@v0.0.0-20230610031953-f2cb11cde33a/requester/uploader/multiuploader.go (about)

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