gifs/api
2014-10-17
Parent:b5d88d57d587
gifs/api/upload.go
Make UsageTracker an interface, ditch the channel interface. Stop using channels to track usage. Just call functions. Make UsageTracker an interface, so there can be multiple implementations, and create the in-memory implementation.
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 }