github.com/0chain/gosdk@v1.17.11/zboxcore/sdk/upload_worker.go (about) 1 package sdk 2 3 import ( 4 "bytes" 5 "context" 6 "errors" 7 "io" 8 "strings" 9 10 "github.com/0chain/gosdk/constants" 11 "github.com/0chain/gosdk/core/sys" 12 "github.com/0chain/gosdk/zboxcore/allocationchange" 13 "github.com/0chain/gosdk/zboxcore/fileref" 14 l "github.com/0chain/gosdk/zboxcore/logger" 15 "github.com/0chain/gosdk/zboxcore/zboxutil" 16 "github.com/google/uuid" 17 "go.uber.org/zap" 18 ) 19 20 type UploadOperation struct { 21 refs []*fileref.FileRef 22 opCode int 23 chunkedUpload *ChunkedUpload 24 isUpdate bool 25 isDownload bool 26 } 27 28 var ErrPauseUpload = errors.New("upload paused by user") 29 30 func (uo *UploadOperation) Process(allocObj *Allocation, connectionID string) ([]fileref.RefEntity, zboxutil.Uint128, error) { 31 if uo.isDownload { 32 if f, ok := uo.chunkedUpload.fileReader.(*sys.MemChanFile); ok { 33 err := allocObj.DownloadFileToFileHandler(f, uo.chunkedUpload.fileMeta.RemotePath, false, nil, true, WithFileCallback(func() { 34 f.Close() //nolint:errcheck 35 })) 36 if err != nil { 37 l.Logger.Error("DownloadFileToFileHandler Failed", zap.String("path", uo.chunkedUpload.fileMeta.RemotePath), zap.Error(err)) 38 return nil, uo.chunkedUpload.uploadMask, err 39 } 40 } 41 } 42 err := uo.chunkedUpload.process() 43 if err != nil { 44 l.Logger.Error("UploadOperation Failed", zap.String("name", uo.chunkedUpload.fileMeta.RemoteName), zap.Error(err)) 45 return nil, uo.chunkedUpload.uploadMask, err 46 } 47 var pos uint64 48 numList := len(uo.chunkedUpload.blobbers) 49 uo.refs = make([]*fileref.FileRef, numList) 50 for i := uo.chunkedUpload.uploadMask; !i.Equals64(0); i = i.And(zboxutil.NewUint128(1).Lsh(pos).Not()) { 51 pos = uint64(i.TrailingZeros()) 52 uo.refs[pos] = uo.chunkedUpload.blobbers[pos].fileRef 53 uo.refs[pos].ChunkSize = uo.chunkedUpload.chunkSize 54 remotePath := uo.chunkedUpload.fileMeta.RemotePath 55 allocationID := allocObj.ID 56 if singleClientMode { 57 lookuphash := fileref.GetReferenceLookup(allocationID, remotePath) 58 cacheKey := fileref.GetCacheKey(lookuphash, uo.chunkedUpload.blobbers[pos].blobber.ID) 59 fileref.DeleteFileRef(cacheKey) 60 } 61 } 62 l.Logger.Info("UploadOperation Success", zap.String("name", uo.chunkedUpload.fileMeta.RemoteName)) 63 return nil, uo.chunkedUpload.uploadMask, nil 64 } 65 66 func (uo *UploadOperation) buildChange(_ []fileref.RefEntity, uid uuid.UUID) []allocationchange.AllocationChange { 67 changes := make([]allocationchange.AllocationChange, len(uo.refs)) 68 for idx, ref := range uo.refs { 69 if ref == nil { 70 change := &allocationchange.EmptyFileChange{} 71 changes[idx] = change 72 continue 73 } 74 if uo.isUpdate { 75 change := &allocationchange.UpdateFileChange{} 76 change.NewFile = ref 77 change.NumBlocks = ref.NumBlocks 78 change.Operation = constants.FileOperationUpdate 79 change.Size = ref.Size 80 changes[idx] = change 81 continue 82 } 83 newChange := &allocationchange.NewFileChange{} 84 newChange.File = ref 85 newChange.NumBlocks = ref.NumBlocks 86 newChange.Operation = constants.FileOperationInsert 87 newChange.Size = ref.Size 88 newChange.Uuid = uid 89 changes[idx] = newChange 90 } 91 return changes 92 93 } 94 95 func (uo *UploadOperation) Verify(allocationObj *Allocation) error { 96 return nil 97 } 98 99 func (uo *UploadOperation) Completed(allocObj *Allocation) { 100 if uo.chunkedUpload.progressStorer != nil { 101 uo.chunkedUpload.removeProgress() 102 } 103 cancelLock.Lock() 104 delete(CancelOpCtx, uo.chunkedUpload.fileMeta.RemotePath) 105 cancelLock.Unlock() 106 if uo.chunkedUpload.statusCallback != nil { 107 uo.chunkedUpload.statusCallback.Completed(allocObj.ID, uo.chunkedUpload.fileMeta.RemotePath, uo.chunkedUpload.fileMeta.RemoteName, uo.chunkedUpload.fileMeta.MimeType, int(uo.chunkedUpload.fileMeta.ActualSize), uo.opCode) 108 } 109 } 110 111 func (uo *UploadOperation) Error(allocObj *Allocation, consensus int, err error) { 112 if uo.chunkedUpload.progressStorer != nil && !strings.Contains(err.Error(), "context") && !errors.Is(err, ErrPauseUpload) { 113 uo.chunkedUpload.removeProgress() 114 } 115 cancelLock.Lock() 116 delete(CancelOpCtx, uo.chunkedUpload.fileMeta.RemotePath) 117 cancelLock.Unlock() 118 if uo.chunkedUpload.statusCallback != nil { 119 uo.chunkedUpload.statusCallback.Error(allocObj.ID, uo.chunkedUpload.fileMeta.RemotePath, uo.opCode, err) 120 } 121 } 122 123 func NewUploadOperation(ctx context.Context, workdir string, allocObj *Allocation, connectionID string, fileMeta FileMeta, fileReader io.Reader, isUpdate, isWebstreaming, isRepair, isMemoryDownload, isStreamUpload bool, opts ...ChunkedUploadOption) (*UploadOperation, string, error) { 124 uo := &UploadOperation{} 125 if fileMeta.ActualSize == 0 && !isStreamUpload { 126 byteReader := bytes.NewReader([]byte( 127 emptyFileDataHash)) 128 fileReader = byteReader 129 opts = append(opts, WithActualHash(emptyFileDataHash)) 130 fileMeta.ActualSize = int64(len(emptyFileDataHash)) 131 } 132 133 cu, err := CreateChunkedUpload(ctx, workdir, allocObj, fileMeta, fileReader, isUpdate, isRepair, isWebstreaming, connectionID, opts...) 134 if err != nil { 135 return nil, "", err 136 } 137 138 uo.chunkedUpload = cu 139 uo.opCode = cu.opCode 140 uo.isUpdate = isUpdate 141 uo.isDownload = isMemoryDownload 142 return uo, cu.progress.ConnectionID, nil 143 }