Permalink
Browse files

added resizing and all that

  • Loading branch information...
1 parent 13250f8 commit 57099d6fb26f0df5f4d4f7c5c8efd9f3ecf81192 @tobi committed Apr 2, 2012
Showing with 195 additions and 34 deletions.
  1. +1 −0 .gitignore
  2. +7 −4 TODO.tasks
  3. +74 −0 cache.go
  4. +11 −0 cache_test.go
  5. +96 −27 main.go
  6. +4 −1 mogrify/mogrify.go
  7. +2 −2 render.js
View
@@ -0,0 +1 @@
+browser
View
@@ -1,5 +1,8 @@
beta:
- - error messages in browser
- - caching
- - permanent db ( leveldb? )
- - resizing!
+ ✓ error messages in browser
+ ✓ allow browser to use cache
+ ✓ create cache in front of browser
+ ✓ permanent db ( leveldb? )
+ ✓ resizing!
+ - avoid mobbing the screenshotter
+ - allow screenshotter to use it's own cache
View
@@ -0,0 +1,74 @@
+package main
+
+import (
+ "crypto/sha1"
+ "flag"
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+)
+
+var cachePath *string = flag.String("cache", "/tmp/img-cache", "path for cache")
+
+type cacheEntry struct {
+ exists bool
+ filepath string
+ stat os.FileInfo
+ file *os.File
+}
+
+
+func (c *cacheEntry) OpenFile() (*os.File, error) {
+ if c.file == nil {
+ file, err := os.Open(c.filepath)
+ if err != nil {
+ return nil, err
+ }
+ c.file = file
+ }
+
+ return c.file, nil
+}
+
+
+
+func init() {
+ os.MkdirAll(*cachePath, os.ModeDir|os.ModePerm)
+}
+
+func CacheStore(key string, content []byte) error {
+ file, err := os.Create(CacheFilename(key))
+ if err != nil {
+ fmt.Printf("could not create cache: %s", err)
+ return err
+ }
+ defer file.Close()
+
+ file.Write(content)
+ return nil
+}
+
+func CacheFilename(key string) string {
+ return filepath.Join(*cachePath, sha1hash(key))
+}
+
+func CacheLookup(key string) *cacheEntry {
+ path := CacheFilename(key)
+
+ stat, err := os.Stat(path)
+ if err != nil {
+ return nil
+ }
+
+ return &cacheEntry{
+ filepath: path,
+ stat: stat,
+ }
+}
+
+func sha1hash(s string) string {
+ h := sha1.New()
+ io.WriteString(h, s)
+ return fmt.Sprintf("%x", h.Sum(nil))
+}
View
@@ -0,0 +1,11 @@
+package main
+
+import (
+ "testing"
+ "testing/quick"
+)
+
+func TestCacheFilename(t *testing.T) {
+ quick.CheckEqual(CacheFilename("blob"), "", nil)
+
+}
View
123 main.go
@@ -1,54 +1,123 @@
package main
import (
+ "browser/mogrify"
+ "browser/phantom"
+ "bytes"
+ "flag"
+ "time"
+ "io"
+ "io/ioutil"
"log"
"net/http"
- "browser/phantom"
- _ "browser/mogrify"
)
func param(r *http.Request, name string) string {
- if len(r.Form["src"]) > 0 {
- return r.Form["src"][0]
+ if len(r.Form[name]) > 0 {
+ return r.Form[name][0]
}
return ""
}
-func ServeFile(w http.ResponseWriter, r *http.Request, filename string) {
+func serveFile(w http.ResponseWriter, r *http.Request, filename string) {
http.ServeFile(w, r, filename)
}
-func main() {
- http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
- r.ParseForm()
+func servePng(w http.ResponseWriter, file io.Reader) {
+ // mime
+ w.Header().Set("Content-Type", "image/png")
+
+ // 3 hours
+ w.Header().Set("Cache-Control", "public, max-age=10800")
+
+ w.WriteHeader(http.StatusOK)
+ io.Copy(w, file)
+}
- log.Printf("%v", r.Form)
+func fresh(c *cacheEntry) bool {
+ elapsed := time.Since(c.stat.ModTime()).Minutes()
+ log.Printf("Since last mod: %v", elapsed)
- url := param(r, "src")
+ return time.Since(c.stat.ModTime()).Minutes() < 0.5
+}
+
+func httpError(w http.ResponseWriter, msg string) {
+ log.Print(msg)
+ http.Error(w, msg, http.StatusInternalServerError)
+}
+
+func Server(w http.ResponseWriter, r *http.Request) {
+ r.ParseForm()
+ url := param(r, "src")
+ size := param(r, "size")
+
+ if url == "" {
+ http.NotFound(w, r)
+ return
+ }
+
+ var buffer []byte
+ var cache *cacheEntry
+
+ // Let's just see if we may have a cache hit
+ // for the exact url + size
+ cache = CacheLookup(url + size)
+ if cache != nil && fresh(cache) {
+ png, err := ioutil.ReadFile(cache.filepath)
+
+ if err == nil {
+ servePng(w, bytes.NewBuffer(png))
+ return
+ }
+ }
- if url != "" {
- filename, err := phantom.Screenshot(r.Form["src"][0])
+ // look in the cache for this screenshot
+ cache = CacheLookup(url)
+ if cache != nil && fresh(cache) {
+ png, err := ioutil.ReadFile(cache.filepath)
+ if err == nil {
+ buffer = png
+ }
+ }
- if err != nil {
- log.Printf("Error creating screenshot: %s", err)
- http.Error(w, "Could not create screenshot", http.StatusInternalServerError)
- } else {
+ if len(buffer) == 0 {
- size := param(r, "size")
+ // make the screenshot
+ filename, err := phantom.Screenshot(url)
- if size == "" {
- ServeFile(w, r, filename)
- } else {
-
- }
+ if err != nil {
+ httpError(w, "Error creating screenshot")
+ return
+ }
-
- return
- }
+ png, err := ioutil.ReadFile(filename)
+ if err == nil {
+ buffer = png
+ CacheStore(url, buffer)
}
- http.Error(w, "missing src parameter", http.StatusInternalServerError)
+ }
+
+ if size == "" {
+ servePng(w, bytes.NewBuffer(buffer))
+ return
+ }
- })
+ var output = new(bytes.Buffer)
+
+ if err := mogrify.Resize(output, bytes.NewBuffer(buffer), size); err != nil {
+ httpError(w, "could not resize")
+ return
+ }
+
+ CacheStore(url + size, output.Bytes())
+ servePng(w, output)
+ return
+}
+
+func main() {
+ flag.Parse()
+ http.HandleFunc("/favicon.ico", http.NotFound)
+ http.HandleFunc("/", Server)
port := ":3000"
log.Printf("Running and listening to port %s", port)
View
@@ -43,7 +43,10 @@ func Resize(out io.Writer, in io.Reader, size string) error {
}
func ResizeFile(filename string, size string) error {
- cmd := exec.Command("gm", "convert", "-resize", size, "-colorspace", "RGB", filename)
+ log.Printf("resize:%s", size)
+ cmd := exec.Command("gm", "convert", "-resize", size, "-colorspace", "RGB", filename, filename)
+ cmd.Stdout = os.Stdout
+ cmd.Stderr = os.Stderr
return cmd.Run()
}
View
@@ -1,4 +1,4 @@
-var page = new WebPage(), address, output, width, height;
+var page = new WebPage(), address, output;
address = phantom.args[0];
output = phantom.args[3];
@@ -7,7 +7,7 @@ page.viewportSize = { width: phantom.args[1], height: phantom.args[2] };
page.open(address, function (status) {
if (status !== 'success') {
console.log('Unable to load the address!');
- exit(1)
+ phantom.exit(1);
} else {
window.setTimeout(function () {
page.render(output);

0 comments on commit 57099d6

Please sign in to comment.