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.
1 package api
3 import (
4 "crypto/sha1"
5 "encoding/hex"
6 "io"
8 "code.secondbit.org/uuid.hg"
9 )
11 func upload(store Storage, bucket, name string, data *io.PipeReader, done chan struct{}) {
12 err := store.Upload(bucket, name, data)
13 if err != nil {
14 data.CloseWithError(err)
15 return
16 }
17 close(done)
18 }
20 func Upload(collectionID uuid.ID, r io.Reader, c Context) (Item, int64, error) {
21 h := sha1.New()
22 var w io.Writer
23 uploadReader, uploadWriter := io.Pipe()
24 uploadChan := make(chan struct{})
25 tmp := uuid.NewID().String()
27 if c.Storage != nil {
28 w = io.MultiWriter(h, uploadWriter)
29 go upload(c.Storage, c.TmpBucket, tmp, uploadReader, uploadChan)
30 } else {
31 w = h
32 close(uploadChan)
33 }
35 size, err := io.Copy(w, r)
36 if err != nil {
37 if c.Storage != nil {
38 uploadWriter.Close()
39 }
40 return Item{}, 0, err
41 }
43 finalLocation := hex.EncodeToString(h.Sum(nil))
44 uploadWriter.Close()
45 <-uploadChan
47 if c.Storage != nil {
48 err = c.Storage.Move(c.TmpBucket, tmp, c.Bucket, finalLocation)
49 if err != nil {
50 return Item{}, 0, err
51 }
52 }
53 return Item{
54 Blob: finalLocation,
55 Bucket: c.Bucket,
56 CollectionID: collectionID,
57 }, size, nil
58 }