From 380f707285c1d29916259275fe9b25953743ef41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torkel=20=C3=96degaard?= Date: Sat, 9 Aug 2014 11:57:54 +0200 Subject: [PATCH] workin on png rendering --- .gitignore | 2 +- _vendor/phantomjs/render.js | 2 +- backend/components/phantom_renderer.go | 62 ++++++++++++++++++++- backend/components/phantom_renderer_test.go | 21 +++++-- backend/httpApi/api.go | 16 ++++++ grafana | 2 +- 6 files changed, 96 insertions(+), 9 deletions(-) diff --git a/.gitignore b/.gitignore index 42857a1b225..e753c73af89 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ node_modules coverage/ .aws-config.json dist - +data/png public gin-bin # locally required config files diff --git a/_vendor/phantomjs/render.js b/_vendor/phantomjs/render.js index 21c2c018460..ff11bd667c9 100644 --- a/_vendor/phantomjs/render.js +++ b/_vendor/phantomjs/render.js @@ -20,7 +20,7 @@ page.viewportSize = { }; page.open(params.url, function (status) { - console.log('Loading a web page'); + console.log('Loading a web page: ' + params.url); setTimeout(function() { console.log('rendering panel to ' + params.png); diff --git a/backend/components/phantom_renderer.go b/backend/components/phantom_renderer.go index 3d165b8fb91..346b7e07d6b 100644 --- a/backend/components/phantom_renderer.go +++ b/backend/components/phantom_renderer.go @@ -1,9 +1,67 @@ package components +import ( + "crypto/md5" + "encoding/hex" + "io" + "os" + "os/exec" + "path/filepath" + "time" + + log "github.com/alecthomas/log4go" +) + type PhantomRenderer struct { - ImagesDir string + ImagesDir string + PhantomDir string } -func (renderer *PhantomRenderer) Render(url string) { +func (self *PhantomRenderer) RenderToPng(url string) (string, error) { + log.Info("PhantomRenderer::renderToPng url %v", url) + binPath, _ := filepath.Abs(filepath.Join(self.PhantomDir, "phantomjs")) + scriptPath, _ := filepath.Abs(filepath.Join(self.PhantomDir, "render.js")) + pngPath, _ := filepath.Abs(filepath.Join(self.ImagesDir, getHash(url))) + pngPath = pngPath + ".png" + cmd := exec.Command(binPath, scriptPath, "url="+url, "width=100", "height=100", "png="+pngPath) + stdout, err := cmd.StdoutPipe() + + if err != nil { + return "", err + } + stderr, err := cmd.StderrPipe() + if err != nil { + return "", err + } + + err = cmd.Start() + if err != nil { + return "", err + } + + go io.Copy(os.Stdout, stdout) + go io.Copy(os.Stdout, stderr) + + done := make(chan error) + go func() { + cmd.Wait() + close(done) + }() + + select { + case <-time.After(10 * time.Second): + if err := cmd.Process.Kill(); err != nil { + log.Error("failed to kill: %v", err) + } + case <-done: + } + + return pngPath, nil +} + +func getHash(text string) string { + hasher := md5.New() + hasher.Write([]byte(text)) + return hex.EncodeToString(hasher.Sum(nil)) } diff --git a/backend/components/phantom_renderer_test.go b/backend/components/phantom_renderer_test.go index dbeabb1a185..ffec267bebb 100644 --- a/backend/components/phantom_renderer_test.go +++ b/backend/components/phantom_renderer_test.go @@ -2,6 +2,7 @@ package components import ( "io/ioutil" + "os" "testing" . "github.com/smartystreets/goconvey/convey" @@ -9,14 +10,26 @@ import ( func TestPhantomRender(t *testing.T) { - Convey("Can render url", func() { + Convey("Can render url", t, func() { tempDir, _ := ioutil.TempDir("", "img") - renderer := &PhantomRenderer{ImagesDir: tempDir} - renderer.Render("http://www.google.com") - //So(err, ShouldBeNil) + renderer := &PhantomRenderer{ImagesDir: tempDir, PhantomDir: "../../_vendor/phantomjs/"} + png, err := renderer.RenderToPng("http://www.google.com") + So(err, ShouldBeNil) + So(exists(png), ShouldEqual, true) //_, err = os.Stat(store.getFilePathForDashboard("hello")) //So(err, ShouldBeNil) }) } + +func exists(path string) bool { + _, err := os.Stat(path) + if err == nil { + return true + } + if os.IsNotExist(err) { + return false + } + return false +} diff --git a/backend/httpApi/api.go b/backend/httpApi/api.go index f93a0adc60c..5b609aa159e 100644 --- a/backend/httpApi/api.go +++ b/backend/httpApi/api.go @@ -5,6 +5,7 @@ import ( log "github.com/alecthomas/log4go" "github.com/gin-gonic/gin" + "github.com/torkelo/grafana-pro/backend/components" "github.com/torkelo/grafana-pro/backend/models" "github.com/torkelo/grafana-pro/backend/stores" ) @@ -13,12 +14,14 @@ type HttpServer struct { port string shutdown chan bool store stores.Store + renderer *components.PhantomRenderer } func NewHttpServer(port string, store stores.Store) *HttpServer { self := &HttpServer{} self.port = port self.store = store + self.renderer = &components.PhantomRenderer{ImagesDir: "data/png", PhantomDir: "_vendor/phantomjs"} return self } @@ -48,6 +51,8 @@ func (self *HttpServer) ListenAndServe() { r.GET("/api/search/", self.search) r.POST("/api/dashboard", self.postDashboard) + r.GET("/api/render", self.renderToPng) + r.Static("/public", "./public") r.Static("/app", "./public/app") r.Static("/img", "./public/img") @@ -79,6 +84,17 @@ func (self *HttpServer) getDashboard(c *gin.Context) { c.JSON(200, dash.Data) } +func (self *HttpServer) renderToPng(c *gin.Context) { + qs := c.Request.URL.Query() + url := qs["url"][0] + pngPath, err := self.renderer.RenderToPng(url) + if err != nil { + c.HTML(500, "error.html", nil) + } + + c.File(pngPath) +} + func (self *HttpServer) search(c *gin.Context) { query := c.Params.ByName("q") diff --git a/grafana b/grafana index f068b2c1d32..1bc277fd874 160000 --- a/grafana +++ b/grafana @@ -1 +1 @@ -Subproject commit f068b2c1d32d74af63e0b36aeed4ac0cc2bb8838 +Subproject commit 1bc277fd87469b1deb0e1b1571d7010f0f396d5a