gifs/api
2014-10-17
Parent:08ec88016e2f
gifs/api/upload.go
Simplify upload. Simplify the upload code by not running the hashing async, which requires fewer copy operations and less channel synchronization. Also, take advantage of the fact that PipeWriters and PipeReaders will return an error to the PipeReaders/PipeWriters (respectively) when read/write is called (respectively) to avoid passing back errors through channels.
| paddy@0 | 1 package api |
| paddy@0 | 2 |
| paddy@0 | 3 import ( |
| paddy@0 | 4 "crypto/sha1" |
| paddy@0 | 5 "encoding/hex" |
| paddy@0 | 6 "io" |
| paddy@0 | 7 |
| paddy@5 | 8 "code.secondbit.org/uuid.hg" |
| paddy@0 | 9 ) |
| paddy@0 | 10 |
| paddy@5 | 11 func upload(store Storage, bucket, name string, data *io.PipeReader, done chan struct{}) { |
| paddy@5 | 12 err := store.Upload(bucket, name, data) |
| paddy@5 | 13 if err != nil { |
| paddy@5 | 14 data.CloseWithError(err) |
| paddy@5 | 15 return |
| paddy@5 | 16 } |
| paddy@5 | 17 close(done) |
| paddy@5 | 18 } |
| paddy@5 | 19 |
| paddy@0 | 20 func Upload(collectionID uuid.ID, r io.Reader, c Context) (Item, int64, error) { |
| paddy@5 | 21 h := sha1.New() |
| paddy@5 | 22 var w io.Writer |
| paddy@0 | 23 uploadReader, uploadWriter := io.Pipe() |
| paddy@5 | 24 uploadChan := make(chan struct{}) |
| paddy@5 | 25 tmp := uuid.NewID().String() |
| paddy@0 | 26 |
| paddy@0 | 27 if c.Storage != nil { |
| paddy@5 | 28 w = io.MultiWriter(h, uploadWriter) |
| paddy@5 | 29 go upload(c.Storage, c.TmpBucket, tmp, uploadReader, uploadChan) |
| paddy@5 | 30 } else { |
| paddy@5 | 31 w = h |
| paddy@5 | 32 close(uploadChan) |
| paddy@0 | 33 } |
| paddy@0 | 34 |
| paddy@5 | 35 size, err := io.Copy(w, r) |
| paddy@5 | 36 if err != nil { |
| paddy@5 | 37 if c.Storage != nil { |
| paddy@0 | 38 uploadWriter.Close() |
| paddy@0 | 39 } |
| paddy@5 | 40 return Item{}, 0, err |
| paddy@0 | 41 } |
| paddy@5 | 42 |
| paddy@5 | 43 finalLocation := hex.EncodeToString(h.Sum(nil)) |
| paddy@5 | 44 uploadWriter.Close() |
| paddy@5 | 45 <-uploadChan |
| paddy@5 | 46 |
| paddy@0 | 47 if c.Storage != nil { |
| paddy@5 | 48 err = c.Storage.Move(c.TmpBucket, tmp, c.Bucket, finalLocation) |
| paddy@0 | 49 if err != nil { |
| paddy@0 | 50 return Item{}, 0, err |
| paddy@0 | 51 } |
| paddy@0 | 52 } |
| paddy@0 | 53 return Item{ |
| paddy@0 | 54 Blob: finalLocation, |
| paddy@0 | 55 Bucket: c.Bucket, |
| paddy@0 | 56 CollectionID: collectionID, |
| paddy@5 | 57 }, size, nil |
| paddy@0 | 58 } |