mirror of
https://github.com/willnorris/imageproxy.git
synced 2024-12-16 21:56:43 -05:00
add custom cache for google cloud storage
This is a bit cleaner than the gcs cache that was vendored in, is properly licensed, and uses Google's application default credentials, which just magically works when run from AppEngine and GCE.
This commit is contained in:
parent
e7f9017674
commit
7bf3645c10
1 changed files with 84 additions and 0 deletions
84
internal/gcscache/gcscache.go
Normal file
84
internal/gcscache/gcscache.go
Normal file
|
@ -0,0 +1,84 @@
|
|||
// Package s3cache provides an httpcache.Cache implementation that stores
|
||||
// cached values on Google Cloud Storage.
|
||||
package gcscache
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"path"
|
||||
|
||||
"cloud.google.com/go/storage"
|
||||
)
|
||||
|
||||
var ctx = context.Background()
|
||||
|
||||
type cache struct {
|
||||
bucket *storage.BucketHandle
|
||||
prefix string
|
||||
}
|
||||
|
||||
func (c *cache) Get(key string) ([]byte, bool) {
|
||||
r, err := c.object(key).NewReader(ctx)
|
||||
if err != nil {
|
||||
if err != storage.ErrObjectNotExist {
|
||||
log.Printf("error reading from gcs: %v", err)
|
||||
}
|
||||
return nil, false
|
||||
}
|
||||
defer r.Close()
|
||||
|
||||
value, err := ioutil.ReadAll(r)
|
||||
if err != nil {
|
||||
log.Printf("error reading from gcs: %v", err)
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return value, true
|
||||
}
|
||||
|
||||
func (c *cache) Set(key string, value []byte) {
|
||||
w := c.object(key).NewWriter(ctx)
|
||||
if _, err := w.Write(value); err != nil {
|
||||
log.Printf("error writing to gcs: %v", err)
|
||||
}
|
||||
if err := w.Close(); err != nil {
|
||||
log.Printf("error closing gcs object writer: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cache) Delete(key string) {
|
||||
if err := c.object(key).Delete(ctx); err != nil {
|
||||
log.Printf("error deleting gcs object: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *cache) object(key string) *storage.ObjectHandle {
|
||||
name := path.Join(c.prefix, keyToFilename(key))
|
||||
return c.bucket.Object(name)
|
||||
}
|
||||
|
||||
func keyToFilename(key string) string {
|
||||
h := md5.New()
|
||||
io.WriteString(h, key)
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
|
||||
// New constructs a Cache storing files in the specified GCS bucket. If prefix
|
||||
// is not empty, objects will be prefixed with that path. Credentials should
|
||||
// be specified using one of the mechanisms supported for Application Default
|
||||
// Credentials (see https://cloud.google.com/docs/authentication/production)
|
||||
func New(bucket, prefix string) (*cache, error) {
|
||||
client, err := storage.NewClient(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &cache{
|
||||
prefix: prefix,
|
||||
bucket: client.Bucket(bucket),
|
||||
}, nil
|
||||
}
|
Loading…
Reference in a new issue