gifs/api

Paddy 2014-10-17 Parent:08ec88016e2f

5:b5d88d57d587 Go to Latest

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.

History
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 }