routes.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. package web
  2. import (
  3. _ "embed"
  4. "fmt"
  5. "html/template"
  6. "net/http"
  7. "path/filepath"
  8. "time"
  9. "github.com/Masterminds/sprig/v3"
  10. "github.com/davecgh/go-spew/spew"
  11. "github.com/fgm/izidic"
  12. "github.com/gin-contrib/sessions"
  13. "github.com/gin-contrib/sessions/cookie"
  14. "github.com/gin-gonic/gin"
  15. "github.com/utrack/gin-csrf"
  16. "code.osinet.fr/fgm/sqs_demo/back/services"
  17. "code.osinet.fr/fgm/sqs_demo/back/services/redriver"
  18. "code.osinet.fr/fgm/sqs_demo/front"
  19. )
  20. func SetupPreviewerRoutes(renderer *template.Template, secret []byte) *gin.Engine {
  21. r := gin.Default()
  22. r.SetHTMLTemplate(renderer)
  23. r.SetTrustedProxies(nil)
  24. r.NoRoute(makePreviewer(renderer))
  25. return r
  26. }
  27. func SetupRedriverRoutes(rd redriver.Redriver, ms redriver.MessageStore, renderer *template.Template, storeSecret, csrfSecret []byte, prefix string) *gin.Engine {
  28. const assetsPrefix = "/assets/"
  29. r := gin.Default()
  30. r.SetHTMLTemplate(renderer)
  31. _ = r.SetTrustedProxies(nil)
  32. store := cookie.NewStore(storeSecret)
  33. r.Use(sessions.Sessions("defaultsession", store))
  34. mw := csrf.Middleware(csrf.Options{
  35. Secret: string(csrfSecret),
  36. ErrorFunc: func(c *gin.Context) {
  37. c.String(http.StatusBadRequest, "CSRF token does not match")
  38. c.Abort()
  39. },
  40. TokenGetter: nil,
  41. })
  42. // Done
  43. r.StaticFS(assetsPrefix, PrefixFileSystem(assetsPrefix, http.FS(front.Assets)))
  44. r.GET("/queue", gin.WrapH(http.RedirectHandler("/", http.StatusMovedPermanently)))
  45. r.GET("/queue/:name/confirm", mw, makeConfirmHandler()) // Needs mw to set token.
  46. // Back done, front WIP
  47. r.GET("/queue/:name", makeQueueHandler(rd, ms))
  48. // JSON done
  49. r.GET("/", makeHomeHandler(rd, prefix))
  50. // TODO
  51. r.POST("/queue/:name/delete", mw, makeDeleteHandler(rd)) // Needs mw to check token.
  52. r.POST("/queue/:name/purge", mw, makePurgeHandler(rd)) // Needs mw to check token.
  53. r.POST("/queue/:name/redrive", mw, makeRedriveHandler(rd, ms)) // Needs mw to check token.
  54. return r
  55. }
  56. func HttpPreviewerService(dic *izidic.Container) (any, error) {
  57. secret := dic.MustParam(services.PStoreSecret).([]byte)
  58. re := dic.MustService(services.SvcRenderer).(*template.Template)
  59. return SetupPreviewerRoutes(re, secret), nil
  60. }
  61. func HttpRedriverService(dic *izidic.Container) (any, error) {
  62. csrfSecret := dic.MustParam(services.PCSRFSecret).([]byte)
  63. prefix := dic.MustParam(services.PPrefix).(string)
  64. storeSecret := dic.MustParam(services.PStoreSecret).([]byte)
  65. rd := dic.MustService(services.SvcRedriver).(redriver.Redriver)
  66. re := dic.MustService(services.SvcRenderer).(*template.Template)
  67. ms := dic.MustService(services.SvcMessageStore).(redriver.MessageStore)
  68. return SetupRedriverRoutes(rd, ms, re, storeSecret, csrfSecret, prefix), nil
  69. }
  70. func RendererService(_ *izidic.Container) (any, error) {
  71. var err error
  72. renderer := template.New("redriver").Funcs(template.FuncMap{
  73. "dump": func(args ...any) template.HTML {
  74. return "<pre>" + template.HTML(spew.Sdump(args...)) + "</pre>\n"
  75. },
  76. "timestamp": func(ts int64) time.Time {
  77. return time.Unix(ts, 0)
  78. },
  79. "nameFromARN": redriver.NameFromARNString,
  80. }).Funcs(sprig.FuncMap())
  81. for _, tpl := range []struct {
  82. name string
  83. value string
  84. }{
  85. {"confirm", front.Confirm},
  86. {"flashes", front.Flashes},
  87. {"home", front.Home},
  88. {"queue-get", front.QueueGet}, // Includes queue-item.
  89. {"500", front.Err500},
  90. } {
  91. renderer, err = renderer.New(tpl.name).Parse(tpl.value)
  92. if err != nil {
  93. return nil, fmt.Errorf("failed parsing %q template: %w", tpl.name, err)
  94. }
  95. }
  96. return renderer, nil
  97. }
  98. // PrefixFileSystem converts a http.FileSystem by serving it requests prefixed
  99. // by the passed prefix, allowing rooted static directories matching the name
  100. // of an embed.FS.
  101. func PrefixFileSystem(prefix string, ifs http.FileSystem) http.FileSystem {
  102. return &prefixedFS{
  103. prefix: prefix,
  104. ifs: ifs,
  105. }
  106. }
  107. type prefixedFS struct {
  108. prefix string
  109. ifs http.FileSystem
  110. }
  111. // Open implements http.FileSystem
  112. func (pfs *prefixedFS) Open(name string) (http.File, error) {
  113. return pfs.ifs.Open(filepath.Join(pfs.prefix, name))
  114. }