storj.io/uplink@v1.13.0/private/storage/streams/upload.go (about) 1 // Copyright (C) 2023 Storj Labs, Inc. 2 // See LICENSE for copying information. 3 4 package streams 5 6 import ( 7 "sync" 8 9 "github.com/zeebo/errs" 10 11 "storj.io/uplink/private/storage/streams/splitter" 12 "storj.io/uplink/private/storage/streams/streamupload" 13 ) 14 15 type uploadResult struct { 16 info streamupload.Info 17 err error 18 } 19 20 // Upload represents an object or part upload and is returned by PutWriter or 21 // PutWriterPart. Data to be uploaded is written using the Write call. Either 22 // Commit or Abort must be called to either complete the upload or otherwise 23 // free up resources related to the upload. 24 type Upload struct { 25 mu sync.Mutex 26 split *splitter.Splitter 27 done chan uploadResult 28 info streamupload.Info 29 cancel func() 30 } 31 32 // Write uploads the object or part data. 33 func (u *Upload) Write(p []byte) (int, error) { 34 u.mu.Lock() 35 defer u.mu.Unlock() 36 37 if u.done == nil { 38 return 0, errs.New("upload already done") 39 } 40 41 return u.split.Write(p) 42 } 43 44 // Abort aborts the upload. If called more than once, or after Commit, it will 45 // return an error. 46 func (u *Upload) Abort() error { 47 u.split.Finish(errs.New("aborted")) 48 u.cancel() 49 50 u.mu.Lock() 51 defer u.mu.Unlock() 52 53 if u.done == nil { 54 return errs.New("upload already done") 55 } 56 <-u.done 57 u.done = nil 58 59 return nil 60 } 61 62 // Commit commits the upload and must be called for the upload to complete 63 // successfully. It should only be called after all of the data has been 64 // written. 65 func (u *Upload) Commit() error { 66 u.split.Finish(nil) 67 68 u.mu.Lock() 69 defer u.mu.Unlock() 70 71 if u.done == nil { 72 return errs.New("upload already done") 73 } 74 result := <-u.done 75 u.info = result.info 76 u.done = nil 77 78 u.cancel() 79 return result.err 80 } 81 82 // Meta returns the upload metadata. It should only be called after a 83 // successful Commit and will return nil otherwise. 84 func (u *Upload) Meta() *Meta { 85 u.mu.Lock() 86 defer u.mu.Unlock() 87 88 if u.done != nil { 89 return nil 90 } 91 92 return &Meta{ 93 Modified: u.info.CreationDate, 94 Size: u.info.PlainSize, 95 Version: u.info.Version, 96 } 97 }