This repository was archived by the owner on May 29, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 7
/
Copy paths3cache.go
127 lines (115 loc) · 2.92 KB
/
s3cache.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
// Package s3cache provides an implementation of httpcache.Cache that stores and
// retrieves data using Amazon S3.
package s3cache // import "sourcegraph.com/sourcegraph/s3cache"
import (
"compress/gzip"
"crypto/md5"
"encoding/hex"
"io"
"io/ioutil"
"log"
"os"
"strconv"
"strings"
"github.com/sqs/s3"
"github.com/sqs/s3/s3util"
)
// Cache objects store and retrieve data using Amazon S3.
type Cache struct {
// Config is the Amazon S3 configuration.
Config s3util.Config
// BucketURL is the URL to the bucket on Amazon S3, which includes the
// bucket name and the AWS region. Example:
// "https://s3-us-west-2.amazonaws.com/mybucket".
BucketURL string
// Gzip indicates whether cache entries should be gzipped in Set and
// gunzipped in Get. If true, cache entry keys will have the suffix ".gz"
// appended.
Gzip bool
}
var noLogErrors, _ = strconv.ParseBool(os.Getenv("NO_LOG_S3CACHE_ERRORS"))
func (c *Cache) Get(key string) (resp []byte, ok bool) {
rdr, err := s3util.Open(c.url(key), &c.Config)
if err != nil {
return []byte{}, false
}
defer rdr.Close()
if c.Gzip {
rdr, err = gzip.NewReader(rdr)
if err != nil {
return nil, false
}
defer rdr.Close()
}
resp, err = ioutil.ReadAll(rdr)
if err != nil {
if !noLogErrors {
log.Printf("s3cache.Get failed: %s", err)
}
}
return resp, err == nil
}
func (c *Cache) Set(key string, resp []byte) {
w, err := s3util.Create(c.url(key), nil, &c.Config)
if err != nil {
if !noLogErrors {
log.Printf("s3util.Create failed: %s", err)
}
return
}
defer w.Close()
if c.Gzip {
w = gzip.NewWriter(w)
defer w.Close()
}
_, err = w.Write(resp)
if err != nil {
if !noLogErrors {
log.Printf("s3cache.Set failed: %s", err)
}
}
}
func (c *Cache) Delete(key string) {
rdr, err := s3util.Delete(c.url(key), &c.Config)
if err != nil {
if !noLogErrors {
log.Printf("s3cache.Delete failed: %s", err)
}
return
}
defer rdr.Close()
}
func (c *Cache) url(key string) string {
key = cacheKeyToObjectKey(key)
if c.Gzip {
key += ".gz"
}
if strings.HasSuffix(c.BucketURL, "/") {
return c.BucketURL + key
}
return c.BucketURL + "/" + key
}
func cacheKeyToObjectKey(key string) string {
h := md5.New()
io.WriteString(h, key)
return hex.EncodeToString(h.Sum(nil))
}
// New returns a new Cache with underlying storage in Amazon S3. The bucketURL
// is the full URL to the bucket on Amazon S3, including the bucket name and AWS
// region (e.g., "https://s3-us-west-2.amazonaws.com/mybucket").
//
// The environment variables AWS_ACCESS_KEY_ID and AWS_SECRET_KEY are used as the AWS
// credentials. To use different credentials, modify the returned Cache object
// or construct a Cache object manually.
func New(bucketURL string) *Cache {
return &Cache{
Config: s3util.Config{
Keys: &s3.Keys{
AccessKey: os.Getenv("AWS_ACCESS_KEY_ID"),
SecretKey: os.Getenv("AWS_SECRET_KEY"),
},
Service: s3.DefaultService,
},
BucketURL: bucketURL,
}
}