Skip to content

Instantly share code, notes, and snippets.

@codegangsta
Created May 30, 2014 15:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save codegangsta/f1c2054e6c10aa239a33 to your computer and use it in GitHub Desktop.
Save codegangsta/f1c2054e6c10aa239a33 to your computer and use it in GitHub Desktop.
package main
import (
"github.com/bmizerany/mc"
"github.com/codegangsta/envy/lib"
"github.com/codegangsta/negroni"
"github.com/crowdmob/goamz/aws"
"github.com/crowdmob/goamz/s3"
"github.com/disintegration/imaging"
"bytes"
"fmt"
"image"
"image/jpeg"
_ "image/png"
"net/http"
"os"
"time"
)
type Size struct {
Width int
Height int
}
var (
bucket *s3.Bucket
sizes = map[string]Size{
"small": {64, 64},
"medium": {128, 128},
"large": {256, 256},
}
cache *mc.Conn
username = os.Getenv("MEMCACHIER_USERNAME")
password = os.Getenv("MEMCACHIER_PASSWORD")
)
func main() {
n := negroni.Classic()
auth, err := aws.EnvAuth()
if err != nil {
panic(err.Error())
}
// cache client
// cache = memcache.New(envy.MustGet("MEMCACHE_SERVER"))
cache, err = mc.Dial("tcp", envy.MustGet("MEMCACHE_SERVER"))
if err != nil {
panic(err)
}
if len(username) > 0 {
err := cache.Auth(username, password)
if err != nil {
panic(err)
}
}
// Open Bucket
s := s3.New(auth, aws.USEast)
bucket = s.Bucket(envy.MustGet("S3_BUCKET"))
n.Use(negroni.HandlerFunc(Cache))
n.UseHandler(http.HandlerFunc(RootHandler))
n.Run(fmt.Sprintf(":%s", envy.MustGet("PORT")))
}
func Cache(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
key := r.URL.String()
v, _, _, err := cache.Get(key)
if err != nil {
fmt.Println("Cache Miss", key)
next(rw, r)
return
}
fmt.Println("Cache HIT", key)
rw.Write([]byte(v))
}
func RootHandler(rw http.ResponseWriter, r *http.Request) {
rc, err := bucket.GetReader(r.URL.Path)
if err != nil {
http.NotFound(rw, r)
return
}
defer rc.Close()
// read the image
image, _, err := image.Decode(rc)
if err != nil {
panic(err)
}
size := r.URL.Query().Get("s")
if len(size) > 0 {
s := sizes[size]
if s.Width == 0 {
http.NotFound(rw, r)
return
}
image = imaging.Thumbnail(image, s.Width, s.Height, imaging.Lanczos)
}
buf := bytes.NewBuffer([]byte{})
err = jpeg.Encode(buf, image, nil)
if err != nil {
panic(err)
}
// cache filling in a goroutine so we can respond fast
go fillCache(r.URL.String(), buf.Bytes())
http.ServeContent(rw, r, "user.jpeg", time.Now(), bytes.NewReader(buf.Bytes()))
}
func fillCache(key string, value []byte) {
if err := cache.Set(key, string(value), 0, 0, 0); err != nil {
fmt.Println("ERROR: Cache failed to fill for", key)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment