github.com/fzfile/BaiduPCS-Go@v0.0.0-20200606205115-4408961cf336/requester/uploader/multiuploader.go (about) 1 package uploader 2 3 import ( 4 "context" 5 "github.com/fzfile/BaiduPCS-Go/pcsutil" 6 "github.com/fzfile/BaiduPCS-Go/pcsutil/converter" 7 "github.com/fzfile/BaiduPCS-Go/requester" 8 "github.com/fzfile/BaiduPCS-Go/requester/rio" 9 "github.com/fzfile/BaiduPCS-Go/requester/rio/speeds" 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 pcsutil.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 pcsutil.TriggerOnSync(muer.onSuccessEvent) 145 } 146 pcsutil.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 }