web.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111
  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. func getLinks(ctx *context.Context, w http.ResponseWriter, r *http.Request) {
  47. t := template.New("links")
  48. contents, _ := linksHtmlBytes()
  49. t, err := t.Parse(string(contents))
  50. if err != nil {
  51. log.Panic(err)
  52. }
  53. routes, _ := ctx.GetAll()
  54. t.Execute(w, routes)
  55. }
  56. // ListenAndServe sets up all web routes, binds the port and handles incoming
  57. // web requests.
  58. func ListenAndServe(addr string, admin bool, version string, ctx *context.Context) error {
  59. mux := http.NewServeMux()
  60. mux.HandleFunc("/api/url/", func(w http.ResponseWriter, r *http.Request) {
  61. apiURL(ctx, w, r)
  62. })
  63. mux.HandleFunc("/api/urls/", func(w http.ResponseWriter, r *http.Request) {
  64. apiURLs(ctx, w, r)
  65. })
  66. mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
  67. getDefault(ctx, w, r)
  68. })
  69. mux.HandleFunc("/edit/", func(w http.ResponseWriter, r *http.Request) {
  70. serveAsset(w, r, "index.html")
  71. })
  72. mux.HandleFunc("/links/", func(w http.ResponseWriter, r *http.Request) {
  73. getLinks(ctx, w, r)
  74. })
  75. mux.HandleFunc("/s/", func(w http.ResponseWriter, r *http.Request) {
  76. serveAsset(w, r, r.URL.Path[len("/s/"):])
  77. })
  78. mux.HandleFunc("/:version", func(w http.ResponseWriter, r *http.Request) {
  79. fmt.Fprintln(w, version)
  80. })
  81. mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
  82. fmt.Fprintln(w, "OK")
  83. })
  84. mux.HandleFunc("/debug/", func(w http.ResponseWriter, r *http.Request) {
  85. w.Header().Set("Content-Type", "text/plain")
  86. it := ctx.List([]byte{':' + 1})
  87. for it.Next() {
  88. fmt.Fprintf(w, "%s %s\n", it.Name(), it.Route().URL)
  89. }
  90. })
  91. if admin {
  92. mux.Handle("/admin/", &adminHandler{ctx})
  93. }
  94. return http.ListenAndServe(addr, mux)
  95. }