web.go 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. package web
  2. import (
  3. "bytes"
  4. "fmt"
  5. "html/template"
  6. "log"
  7. "net/http"
  8. "github.com/kellegous/go/context"
  9. "github.com/syndtr/goleveldb/leveldb"
  10. )
  11. // Serve a bundled asset over HTTP.
  12. func serveAsset(w http.ResponseWriter, r *http.Request, name string) {
  13. n, err := AssetInfo(name)
  14. if err != nil {
  15. http.NotFound(w, r)
  16. return
  17. }
  18. a, err := Asset(name)
  19. if err != nil {
  20. http.NotFound(w, r)
  21. return
  22. }
  23. http.ServeContent(w, r, n.Name(), n.ModTime(), bytes.NewReader(a))
  24. }
  25. // The default handler responds to most requests. It is responsible for the
  26. // shortcut redirects and for sending unmapped shortcuts to the edit page.
  27. func getDefault(ctx *context.Context, w http.ResponseWriter, r *http.Request) {
  28. p := parseName("/", r.URL.Path)
  29. if p == "" {
  30. http.Redirect(w, r, "/edit/", http.StatusTemporaryRedirect)
  31. return
  32. }
  33. rt, err := ctx.Get(p)
  34. if err == leveldb.ErrNotFound {
  35. http.Redirect(w, r,
  36. fmt.Sprintf("/edit/%s", cleanName(p)),
  37. http.StatusTemporaryRedirect)
  38. return
  39. } else if err != nil {
  40. log.Panic(err)
  41. }
  42. http.Redirect(w, r,
  43. rt.URL,
  44. http.StatusTemporaryRedirect)
  45. }
  46. type listLinksHandler struct {
  47. ctx *context.Context
  48. }
  49. func (h *listLinksHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  50. t := template.New("links")
  51. contents, _ := linksHtmlBytes()
  52. t, err := t.Parse(string(contents))
  53. if err != nil {
  54. log.Printf("no template")
  55. return
  56. }
  57. routes, _ := h.ctx.GetAll()
  58. t.Execute(w, routes)
  59. }
  60. // ListenAndServe sets up all web routes, binds the port and handles incoming
  61. // web requests.
  62. func ListenAndServe(addr string, admin bool, version string, ctx *context.Context) error {
  63. mux := http.NewServeMux()
  64. mux.HandleFunc("/api/url/", func(w http.ResponseWriter, r *http.Request) {
  65. apiURL(ctx, w, r)
  66. })
  67. mux.HandleFunc("/api/urls/", func(w http.ResponseWriter, r *http.Request) {
  68. apiURLs(ctx, w, r)
  69. })
  70. mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  71. getDefault(ctx, w, r)
  72. })
  73. mux.HandleFunc("/edit/", func(w http.ResponseWriter, r *http.Request) {
  74. serveAsset(w, r, "index.html")
  75. })
  76. mux.Handle("/links", &listLinksHandler{ctx})
  77. mux.HandleFunc("/s/", func(w http.ResponseWriter, r *http.Request) {
  78. serveAsset(w, r, r.URL.Path[len("/s/"):])
  79. })
  80. mux.HandleFunc("/:version", func(w http.ResponseWriter, r *http.Request) {
  81. fmt.Fprintln(w, version)
  82. })
  83. mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
  84. fmt.Fprintln(w, "OK")
  85. })
  86. if admin {
  87. mux.Handle("/admin/", &adminHandler{ctx})
  88. }
  89. return http.ListenAndServe(addr, mux)
  90. }