phantom_renderer.go 1.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. package components
  2. import (
  3. "crypto/md5"
  4. "encoding/hex"
  5. "io"
  6. "os"
  7. "os/exec"
  8. "path/filepath"
  9. "time"
  10. log "github.com/alecthomas/log4go"
  11. )
  12. type PhantomRenderer struct {
  13. ImagesDir string
  14. PhantomDir string
  15. }
  16. type RenderOpts struct {
  17. Url string
  18. Width string
  19. Height string
  20. }
  21. func (self *PhantomRenderer) RenderToPng(params *RenderOpts) (string, error) {
  22. log.Info("PhantomRenderer::renderToPng url %v", params.Url)
  23. binPath, _ := filepath.Abs(filepath.Join(self.PhantomDir, "phantomjs"))
  24. scriptPath, _ := filepath.Abs(filepath.Join(self.PhantomDir, "render.js"))
  25. pngPath, _ := filepath.Abs(filepath.Join(self.ImagesDir, getHash(params.Url)))
  26. pngPath = pngPath + ".png"
  27. cmd := exec.Command(binPath, scriptPath, "url="+params.Url, "width="+params.Width, "height="+params.Height, "png="+pngPath)
  28. stdout, err := cmd.StdoutPipe()
  29. if err != nil {
  30. return "", err
  31. }
  32. stderr, err := cmd.StderrPipe()
  33. if err != nil {
  34. return "", err
  35. }
  36. err = cmd.Start()
  37. if err != nil {
  38. return "", err
  39. }
  40. go io.Copy(os.Stdout, stdout)
  41. go io.Copy(os.Stdout, stderr)
  42. done := make(chan error)
  43. go func() {
  44. cmd.Wait()
  45. close(done)
  46. }()
  47. select {
  48. case <-time.After(10 * time.Second):
  49. if err := cmd.Process.Kill(); err != nil {
  50. log.Error("failed to kill: %v", err)
  51. }
  52. case <-done:
  53. }
  54. return pngPath, nil
  55. }
  56. func getHash(text string) string {
  57. hasher := md5.New()
  58. hasher.Write([]byte(text))
  59. return hex.EncodeToString(hasher.Sum(nil))
  60. }