A web blog and personal homepage engine written in Go.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

122 line
2.9 KiB

  1. package responses
  2. import (
  3. "errors"
  4. "fmt"
  5. "html/template"
  6. "io/ioutil"
  7. "log"
  8. "net/http"
  9. "os"
  10. "strings"
  11. "git.kirsle.net/apps/gophertype/pkg/bundled"
  12. )
  13. // GetTemplate returns the template file's data, wherever it is.
  14. // Checks the embedded bindata, then the user root on disk, then error.
  15. // If it can be found, returns the contents or error.
  16. func GetFile(path string) ([]byte, error) {
  17. // Check bindata.
  18. if b, err := bundled.Asset(path); err == nil {
  19. return b, nil
  20. }
  21. // Check the filesystem. TODO
  22. if b, err := ioutil.ReadFile("./pvt-www/" + path); err == nil {
  23. return b, nil
  24. } else {
  25. return []byte{}, err
  26. }
  27. }
  28. // GetFileExists checks if the file exists but doesn't return its data.
  29. func GetFileExists(path string) bool {
  30. // Check bindata.
  31. if _, err := bundled.AssetInfo(path); err == nil {
  32. return true
  33. }
  34. // Check the filesystem. TODO
  35. if _, err := os.Stat(path); err == nil {
  36. return true
  37. }
  38. return false
  39. }
  40. /*
  41. ResolveFile searches for the existence of a file from a fuzzy URL path.
  42. `path` is a request path like "/about"
  43. This function would return e.g. "about.gohtml" as being a file path that is
  44. sure to return data in GetFile().
  45. Path finding rules follow expected behavior from dominant web servers:
  46. - If the exact path is found, return it immediately.
  47. - Try assuming a ".gohtml" or ".md" file extension for the path.
  48. - Try checking if the path is a directory with an "index.gohtml" inside it, etc.
  49. */
  50. func ResolveFile(path string) (string, error) {
  51. // Ensure the path doesn't begin with a slash.
  52. path = strings.TrimLeft(path, "/")
  53. // Try the exact path.
  54. if GetFileExists(path) {
  55. return path, nil
  56. }
  57. // Try fuzzy file matches.
  58. var tries = []string{
  59. path + ".gohtml",
  60. path + ".md",
  61. path + "/index.gohtml",
  62. path + "/index.html",
  63. }
  64. for _, try := range tries {
  65. path = strings.TrimLeft(try, "/")
  66. if GetFileExists(path) {
  67. return path, nil
  68. }
  69. }
  70. return "", errors.New("not found")
  71. }
  72. // RenderTemplate renders a Go HTML template.
  73. // The io.Writer can be an http.ResponseWriter.
  74. func RenderTemplate(w http.ResponseWriter, tmpl string, vars interface{}) error {
  75. w.Header().Set("Content-Type", "text/html; charset=utf-8")
  76. // Look for the built-in template.
  77. if b, err := GetFile(tmpl); err == nil {
  78. t, err := template.New(tmpl).Parse(string(b))
  79. if err != nil {
  80. return fmt.Errorf("bundled template '%s': %s", tmpl, err)
  81. }
  82. // We found the template. Can we find the layout html?
  83. if layout, err := GetFile(".layout.gohtml"); err == nil {
  84. _, err := t.New("layout").Parse(string(layout))
  85. if err != nil {
  86. fmt.Errorf("RenderTemplate(.layout.gohtml): %s", err)
  87. }
  88. } else {
  89. log.Printf("RenderTemplate: .layout.gohtml not found to wrap %s", tmpl)
  90. }
  91. fmt.Printf("Render Templ: %s", tmpl)
  92. if err := t.ExecuteTemplate(w, "layout", vars); err != nil {
  93. log.Printf("RenderTemplate(%s): %s", tmpl, err)
  94. }
  95. log.Println("Done")
  96. return nil
  97. } else {
  98. Panic(w, http.StatusInternalServerError, err.Error())
  99. }
  100. return nil
  101. }