gifs/api

Paddy 2014-10-17 Parent:b5d88d57d587

6:eb450538f079 Go to Latest

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.

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 }