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  }