mirror of https://github.com/grafana/grafana
parent
222319d924
commit
e84f06b503
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,69 @@ |
||||
package renderer |
||||
|
||||
import ( |
||||
"crypto/md5" |
||||
"encoding/hex" |
||||
"io" |
||||
"os" |
||||
"os/exec" |
||||
"path/filepath" |
||||
"time" |
||||
|
||||
"github.com/torkelo/grafana-pro/pkg/log" |
||||
"github.com/torkelo/grafana-pro/pkg/setting" |
||||
) |
||||
|
||||
type RenderOpts struct { |
||||
Url string |
||||
Width string |
||||
Height string |
||||
} |
||||
|
||||
func RenderToPng(params *RenderOpts) (string, error) { |
||||
log.Info("PhantomRenderer::renderToPng url %v", params.Url) |
||||
binPath, _ := filepath.Abs(filepath.Join(setting.PhantomDir, "phantomjs")) |
||||
scriptPath, _ := filepath.Abs(filepath.Join(setting.PhantomDir, "render.js")) |
||||
pngPath, _ := filepath.Abs(filepath.Join(setting.ImagesDir, getHash(params.Url))) |
||||
pngPath = pngPath + ".png" |
||||
|
||||
cmd := exec.Command(binPath, scriptPath, "url="+params.Url, "width="+params.Width, "height="+params.Height, "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(4, "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)) |
||||
} |
||||
@ -0,0 +1,82 @@ |
||||
package api |
||||
|
||||
import ( |
||||
"github.com/gin-gonic/gin" |
||||
|
||||
"github.com/torkelo/grafana-pro/pkg/middleware" |
||||
"github.com/torkelo/grafana-pro/pkg/models" |
||||
"github.com/torkelo/grafana-pro/pkg/routes/apimodel" |
||||
) |
||||
|
||||
func GetDashboard(c *middleware.Context) { |
||||
slug := c.Params(":slug") |
||||
|
||||
dash, err := models.GetDashboard(slug, c.GetAccountId()) |
||||
if err != nil { |
||||
c.ApiError(404, "Dashboard not found", nil) |
||||
return |
||||
} |
||||
|
||||
dash.Data["id"] = dash.Id |
||||
|
||||
c.JSON(200, dash.Data) |
||||
} |
||||
|
||||
func DeleteDashboard(c *middleware.Context) { |
||||
slug := c.Params(":slug") |
||||
|
||||
dash, err := models.GetDashboard(slug, c.GetAccountId()) |
||||
if err != nil { |
||||
c.ApiError(404, "Dashboard not found", nil) |
||||
return |
||||
} |
||||
|
||||
err = models.DeleteDashboard(slug, c.GetAccountId()) |
||||
if err != nil { |
||||
c.ApiError(500, "Failed to delete dashboard", err) |
||||
return |
||||
} |
||||
|
||||
var resp = map[string]interface{}{"title": dash.Title} |
||||
|
||||
c.JSON(200, resp) |
||||
} |
||||
|
||||
func Search(c *middleware.Context) { |
||||
query := c.Query("q") |
||||
|
||||
results, err := models.SearchQuery(query, c.GetAccountId()) |
||||
if err != nil { |
||||
c.ApiError(500, "Search failed", err) |
||||
return |
||||
} |
||||
|
||||
c.JSON(200, results) |
||||
} |
||||
|
||||
func PostDashboard(c *middleware.Context) { |
||||
var command apimodel.SaveDashboardCommand |
||||
|
||||
if !c.JsonBody(&command) { |
||||
c.ApiError(400, "bad request", nil) |
||||
return |
||||
} |
||||
|
||||
dashboard := models.NewDashboard("test") |
||||
dashboard.Data = command.Dashboard |
||||
dashboard.Title = dashboard.Data["title"].(string) |
||||
dashboard.AccountId = c.GetAccountId() |
||||
dashboard.UpdateSlug() |
||||
|
||||
if dashboard.Data["id"] != nil { |
||||
dashboard.Id = dashboard.Data["id"].(string) |
||||
} |
||||
|
||||
err := models.SaveDashboard(dashboard) |
||||
if err != nil { |
||||
c.ApiError(500, "Failed to save dashboard", err) |
||||
return |
||||
} |
||||
|
||||
c.JSON(200, gin.H{"status": "success", "slug": dashboard.Slug}) |
||||
} |
||||
@ -0,0 +1,30 @@ |
||||
package api |
||||
|
||||
import ( |
||||
"strconv" |
||||
|
||||
"github.com/torkelo/grafana-pro/pkg/components/renderer" |
||||
"github.com/torkelo/grafana-pro/pkg/middleware" |
||||
"github.com/torkelo/grafana-pro/pkg/utils" |
||||
) |
||||
|
||||
func RenderToPng(c *middleware.Context) { |
||||
accountId := c.GetAccountId() |
||||
queryReader := utils.NewUrlQueryReader(c.Req.URL) |
||||
queryParams := "?render&accountId=" + strconv.Itoa(accountId) + "&" + c.Req.URL.RawQuery |
||||
|
||||
renderOpts := &renderer.RenderOpts{ |
||||
Url: c.Params("url") + queryParams, |
||||
Width: queryReader.Get("width", "800"), |
||||
Height: queryReader.Get("height", "400"), |
||||
} |
||||
|
||||
renderOpts.Url = "http://localhost:3000" + renderOpts.Url |
||||
|
||||
pngPath, err := renderer.RenderToPng(renderOpts) |
||||
if err != nil { |
||||
c.HTML(500, "error.html", nil) |
||||
} |
||||
|
||||
c.ServeFile(pngPath) |
||||
} |
||||
@ -0,0 +1,80 @@ |
||||
package rethink |
||||
|
||||
import ( |
||||
"errors" |
||||
|
||||
r "github.com/dancannon/gorethink" |
||||
|
||||
"github.com/torkelo/grafana-pro/pkg/log" |
||||
"github.com/torkelo/grafana-pro/pkg/models" |
||||
) |
||||
|
||||
func SaveDashboard(dash *models.Dashboard) error { |
||||
resp, err := r.Table("dashboards").Insert(dash, r.InsertOpts{Conflict: "update"}).RunWrite(session) |
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
log.Info("Inserted: %v, Errors: %v, Updated: %v", resp.Inserted, resp.Errors, resp.Updated) |
||||
log.Info("First error:", resp.FirstError) |
||||
if len(resp.GeneratedKeys) > 0 { |
||||
dash.Id = resp.GeneratedKeys[0] |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
func GetDashboard(slug string, accountId int) (*models.Dashboard, error) { |
||||
resp, err := r.Table("dashboards"). |
||||
GetAllByIndex("AccountIdSlug", []interface{}{accountId, slug}). |
||||
Run(session) |
||||
|
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
var dashboard models.Dashboard |
||||
err = resp.One(&dashboard) |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
return &dashboard, nil |
||||
} |
||||
|
||||
func DeleteDashboard(slug string, accountId int) error { |
||||
resp, err := r.Table("dashboards"). |
||||
GetAllByIndex("AccountIdSlug", []interface{}{accountId, slug}). |
||||
Delete().RunWrite(session) |
||||
|
||||
if err != nil { |
||||
return err |
||||
} |
||||
|
||||
if resp.Deleted != 1 { |
||||
return errors.New("Did not find dashboard to delete") |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
func SearchQuery(query string, accountId int) ([]*models.SearchResult, error) { |
||||
docs, err := r.Table("dashboards"). |
||||
GetAllByIndex("AccountId", []interface{}{accountId}). |
||||
Filter(r.Row.Field("Title").Match(".*")).Run(session) |
||||
|
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
results := make([]*models.SearchResult, 0, 50) |
||||
var dashboard models.Dashboard |
||||
for docs.Next(&dashboard) { |
||||
results = append(results, &models.SearchResult{ |
||||
Title: dashboard.Title, |
||||
Id: dashboard.Slug, |
||||
}) |
||||
} |
||||
|
||||
return results, nil |
||||
} |
||||
Loading…
Reference in new issue