-
Notifications
You must be signed in to change notification settings - Fork 2
/
storage.go
136 lines (110 loc) · 3.06 KB
/
storage.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
package infra
import (
"context"
"errors"
"fmt"
"io"
"google.golang.org/api/storage/v1"
"github.com/orijtech/otils"
)
type UploadParams struct {
Project string `json:"project"`
Public bool `json:"public"`
Bucket string `json:"bucket"`
Name string `json:"path"`
Reader func() io.Reader `json:"-"`
}
var (
errBlankReaderFunc = errors.New("expecting a non-blank reader function")
errEmptyName = errors.New("expecting a non-empty name")
errEmptyBucket = errors.New("expecting a non-empty bucket")
)
func (params *UploadParams) Validate() error {
if params == nil || params.Reader == nil {
return errBlankReaderFunc
}
if params.Name == "" {
return errEmptyName
}
if params.Bucket == "" {
return errEmptyBucket
}
return nil
}
type BucketCheck struct {
Project string `json:"project"`
Bucket string `json:"bucket"`
Public bool `json:"public"`
}
func (c *Client) EnsureBucketExists(ctx context.Context, bc *BucketCheck) (*storage.Bucket, error) {
foundBucket, err := c.bucketsService().Get(bc.Bucket).Context(ctx).Do()
if err != nil {
// TODO: Handle the respective error cases e.g:
// + failure to authenticate
// + rate limits exceeded
}
if foundBucket != nil {
return foundBucket, nil
}
// Otherwise it is time to create that bucket.
bIns := c.bucketsService().Insert(bc.Project, &storage.Bucket{Name: bc.Bucket}).Context(ctx)
var acl = "private"
if bc.Public {
acl = "publicRead"
}
bIns = bIns.PredefinedDefaultObjectAcl(acl)
return bIns.Do()
}
func (c *Client) objectsService() *storage.ObjectsService {
return storage.NewObjectsService(c.storageSrvc)
}
func (c *Client) bucketsService() *storage.BucketsService {
return storage.NewBucketsService(c.storageSrvc)
}
func (c *Client) Download(ctx context.Context, bucket, path string) (io.ReadCloser, error) {
objGetCall := c.objectsService().Get(bucket, path).Context(ctx)
res, err := objGetCall.Download()
if err != nil {
return nil, err
}
if otils.StatusOK(res.StatusCode) {
return res.Body, nil
}
// Otherwise we are now dealing with non-2XX codes.
if res.Body != nil {
// TODO: Document this weird case
return res.Body, nil
}
return nil, errors.New(res.Status)
}
func (c *Client) Object(ctx context.Context, bucket, path string) (*storage.Object, error) {
objGetCall := c.objectsService().Get(bucket, path)
return objGetCall.Do()
}
func (c *Client) UploadWithParams(ctx context.Context, params *UploadParams) (*storage.Object, error) {
if err := params.Validate(); err != nil {
return nil, err
}
bucket, err := c.EnsureBucketExists(ctx, &BucketCheck{
Project: params.Project,
Bucket: params.Bucket,
})
if err != nil {
return nil, err
}
obj := &storage.Object{
Name: params.Name,
Bucket: bucket.Name,
}
oIns := c.objectsService().Insert(params.Bucket, obj).Context(ctx)
var acl = "private"
if params.Public {
acl = "publicRead"
}
oIns = oIns.PredefinedAcl(acl)
oIns = oIns.Media(params.Reader())
return oIns.Do()
}
func ObjectURL(obj *storage.Object) string {
return fmt.Sprintf("https://storage.googleapis.com/%s/%s", obj.Bucket, obj.Name)
}