gifs/api
gifs/api/storage.go
Remove user info from memstore. Remove all the user related methods and properties from the memstore, as those are all going to be superseded by code.secondbit.org/auth anyways.
| paddy@0 | 1 package api |
| paddy@0 | 2 |
| paddy@0 | 3 import ( |
| paddy@0 | 4 "errors" |
| paddy@0 | 5 "io" |
| paddy@0 | 6 "io/ioutil" |
| paddy@0 | 7 "log" |
| paddy@0 | 8 "net/http" |
| paddy@0 | 9 |
| paddy@0 | 10 "code.google.com/p/google-api-go-client/googleapi" |
| paddy@0 | 11 "code.google.com/p/google-api-go-client/storage/v1beta2" |
| paddy@0 | 12 ) |
| paddy@0 | 13 |
| paddy@0 | 14 var ( |
| paddy@0 | 15 BucketNotFoundError = errors.New("bucket not found") |
| paddy@0 | 16 BlobNotFoundError = errors.New("blob not found") |
| paddy@0 | 17 ) |
| paddy@0 | 18 |
| paddy@0 | 19 type Storage interface { |
| paddy@0 | 20 Upload(bucket, tmp string, r io.Reader, errs chan error, done chan struct{}) |
| paddy@0 | 21 Delete(bucket, tmp string) error |
| paddy@0 | 22 Move(srcBucket, src, dstBucket, dst string) error |
| paddy@0 | 23 Download(bucket, id string, w io.Writer) (int64, error) |
| paddy@0 | 24 } |
| paddy@0 | 25 |
| paddy@0 | 26 type GoogleCloudStorage struct { |
| paddy@0 | 27 *storage.Service |
| paddy@0 | 28 } |
| paddy@0 | 29 |
| paddy@0 | 30 func (gcs *GoogleCloudStorage) Upload(bucket, tmp string, r io.Reader, errs chan error, done chan struct{}) { |
| paddy@0 | 31 if errs != nil { |
| paddy@0 | 32 defer close(errs) |
| paddy@0 | 33 } |
| paddy@0 | 34 if done != nil { |
| paddy@0 | 35 defer close(done) |
| paddy@0 | 36 } |
| paddy@0 | 37 object := &storage.Object{Name: tmp} |
| paddy@0 | 38 _, err := gcs.Objects.Insert(bucket, object).Media(r).Do() |
| paddy@0 | 39 if err != nil && errs != nil { |
| paddy@0 | 40 errs <- err |
| paddy@0 | 41 } |
| paddy@0 | 42 } |
| paddy@0 | 43 |
| paddy@0 | 44 func (gcs *GoogleCloudStorage) Delete(bucket, tmp string) error { |
| paddy@0 | 45 return gcs.Objects.Delete(bucket, tmp).Do() |
| paddy@0 | 46 } |
| paddy@0 | 47 |
| paddy@0 | 48 func (gcs *GoogleCloudStorage) Move(srcBucket, src, dstBucket, dst string) error { |
| paddy@0 | 49 _, err := gcs.Objects.Get(dstBucket, dst).Do() |
| paddy@0 | 50 if err == nil { |
| paddy@0 | 51 go gcs.del(srcBucket, src) |
| paddy@0 | 52 return nil |
| paddy@0 | 53 } |
| paddy@0 | 54 if e, ok := err.(*googleapi.Error); !ok || e.Code != 404 { |
| paddy@0 | 55 return err |
| paddy@0 | 56 } |
| paddy@0 | 57 _, err = gcs.Objects.Copy(srcBucket, src, dstBucket, dst, nil).Do() |
| paddy@0 | 58 if err != nil { |
| paddy@0 | 59 return err |
| paddy@0 | 60 } |
| paddy@0 | 61 objectAcl := &storage.ObjectAccessControl{ |
| paddy@0 | 62 Bucket: dstBucket, Entity: "allUsers", Object: dst, Role: "READER", |
| paddy@0 | 63 } |
| paddy@0 | 64 _, err = gcs.ObjectAccessControls.Insert(dstBucket, dst, objectAcl).Do() |
| paddy@0 | 65 if err != nil { |
| paddy@0 | 66 return err |
| paddy@0 | 67 } |
| paddy@0 | 68 go gcs.del(srcBucket, src) |
| paddy@0 | 69 return nil |
| paddy@0 | 70 } |
| paddy@0 | 71 |
| paddy@0 | 72 func (gcs *GoogleCloudStorage) del(bucket, tmp string) { |
| paddy@0 | 73 err := gcs.Delete(bucket, tmp) |
| paddy@0 | 74 if err != nil { |
| paddy@0 | 75 log.Printf("Error deleting temporary upload %s in %s: %s\n", tmp, bucket, err) |
| paddy@0 | 76 } |
| paddy@0 | 77 } |
| paddy@0 | 78 |
| paddy@0 | 79 func (gcs *GoogleCloudStorage) Download(bucket, id string, w io.Writer) (int64, error) { |
| paddy@0 | 80 res, err := gcs.Objects.Get(bucket, id).Do() |
| paddy@0 | 81 if err != nil { |
| paddy@0 | 82 return 0, err |
| paddy@0 | 83 } |
| paddy@0 | 84 resp, err := http.Get(res.MediaLink) |
| paddy@0 | 85 if err != nil { |
| paddy@0 | 86 return 0, err |
| paddy@0 | 87 } |
| paddy@0 | 88 defer resp.Body.Close() |
| paddy@0 | 89 return io.Copy(w, resp.Body) |
| paddy@0 | 90 } |
| paddy@0 | 91 |
| paddy@0 | 92 type Memstorage map[string]Bucket |
| paddy@0 | 93 |
| paddy@0 | 94 type Bucket map[string][]byte |
| paddy@0 | 95 |
| paddy@0 | 96 func (m Memstorage) Upload(bucket, tmp string, r io.Reader, errs chan error, done chan struct{}) { |
| paddy@0 | 97 if errs != nil { |
| paddy@0 | 98 defer close(errs) |
| paddy@0 | 99 } |
| paddy@0 | 100 if done != nil { |
| paddy@0 | 101 defer close(done) |
| paddy@0 | 102 } |
| paddy@0 | 103 if _, ok := m[bucket]; !ok { |
| paddy@0 | 104 m[bucket] = make(Bucket) |
| paddy@0 | 105 } |
| paddy@0 | 106 bytes, err := ioutil.ReadAll(r) |
| paddy@0 | 107 if err != nil { |
| paddy@0 | 108 errs <- err |
| paddy@0 | 109 return |
| paddy@0 | 110 } |
| paddy@0 | 111 m[bucket][tmp] = bytes |
| paddy@0 | 112 } |
| paddy@0 | 113 |
| paddy@0 | 114 func (m Memstorage) Delete(bucket, tmp string) error { |
| paddy@0 | 115 delete(m[bucket], tmp) |
| paddy@0 | 116 return nil |
| paddy@0 | 117 } |
| paddy@0 | 118 |
| paddy@0 | 119 func (m Memstorage) Move(srcBucket, src, dstBucket, dst string) error { |
| paddy@0 | 120 if _, ok := m[srcBucket]; !ok { |
| paddy@0 | 121 return BucketNotFoundError |
| paddy@0 | 122 } |
| paddy@0 | 123 if _, ok := m[srcBucket][src]; !ok { |
| paddy@0 | 124 return BlobNotFoundError |
| paddy@0 | 125 } |
| paddy@0 | 126 if _, ok := m[dstBucket]; !ok { |
| paddy@0 | 127 m[dstBucket] = make(Bucket) |
| paddy@0 | 128 } |
| paddy@0 | 129 m[dstBucket][dst] = m[srcBucket][src] |
| paddy@0 | 130 return m.Delete(srcBucket, src) |
| paddy@0 | 131 } |
| paddy@0 | 132 |
| paddy@0 | 133 func (m Memstorage) Download(bucket, id string, w io.Writer) (int64, error) { |
| paddy@0 | 134 if _, ok := m[bucket]; !ok { |
| paddy@0 | 135 return 0, BucketNotFoundError |
| paddy@0 | 136 } |
| paddy@0 | 137 if _, ok := m[bucket][id]; !ok { |
| paddy@0 | 138 return 0, BlobNotFoundError |
| paddy@0 | 139 } |
| paddy@0 | 140 n, err := w.Write(m[bucket][id]) |
| paddy@0 | 141 return int64(n), err |
| paddy@0 | 142 } |