mirror of
https://github.com/willnorris/imageproxy.git
synced 2024-12-16 21:56:43 -05:00
7bf3645c10
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.
84 lines
1.9 KiB
Go
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
|
|
}
|