0
Fork 0
mirror of https://github.com/willnorris/imageproxy.git synced 2024-12-16 21:56:43 -05:00
imageproxy/internal/gcscache/gcscache.go
Will Norris 7bf3645c10 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.
2018-02-02 09:56:25 +00:00

84 lines
1.9 KiB
Go

// 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
}