wisp.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. package wisp
  2. import (
  3. "context"
  4. "net/http"
  5. "strings"
  6. "github.com/julienschmidt/httprouter"
  7. )
  8. type Wisp struct {
  9. router *httprouter.Router
  10. errorHandler ErrorHandler
  11. middlewares []Middleware
  12. }
  13. func New() *Wisp {
  14. return &Wisp{
  15. router: httprouter.New(),
  16. errorHandler: defaultErrorHandler,
  17. middlewares: []Middleware{},
  18. }
  19. }
  20. func (w *Wisp) SetErrorHandler(errorHandler ErrorHandler) {
  21. w.errorHandler = errorHandler
  22. }
  23. func (w *Wisp) Use(m ...Middleware) {
  24. w.middlewares = append(w.middlewares, m...)
  25. }
  26. func (w *Wisp) Group(prefix string, middlewares ...Middleware) *Group {
  27. return &Group{
  28. prefix: prefix,
  29. parent: w,
  30. middlewares: middlewares,
  31. }
  32. }
  33. func (w *Wisp) GET(path string, h Handler, mws ...Middleware) {
  34. w.handle(http.MethodGet, path, h, mws...)
  35. }
  36. func (w *Wisp) POST(path string, h Handler, mws ...Middleware) {
  37. w.handle(http.MethodPost, path, h, mws...)
  38. }
  39. func (w *Wisp) PUT(path string, h Handler, mws ...Middleware) {
  40. w.handle(http.MethodPut, path, h, mws...)
  41. }
  42. func (w *Wisp) DELETE(path string, h Handler, mws ...Middleware) {
  43. w.handle(http.MethodDelete, path, h, mws...)
  44. }
  45. func (w *Wisp) PATCH(path string, h Handler, mws ...Middleware) {
  46. w.handle(http.MethodPatch, path, h, mws...)
  47. }
  48. func (w *Wisp) OPTIONS(path string, h Handler, mws ...Middleware) {
  49. w.handle(http.MethodOptions, path, h, mws...)
  50. }
  51. func (w *Wisp) HEAD(path string, h Handler, mws ...Middleware) {
  52. w.handle(http.MethodHead, path, h, mws...)
  53. }
  54. func (w *Wisp) Static(path, root string) {
  55. if !strings.HasSuffix(path, "/*filepath") {
  56. if strings.HasSuffix(path, "/") {
  57. path += "*filepath"
  58. } else {
  59. path += "/*filepath"
  60. }
  61. }
  62. fileServer := http.StripPrefix(strings.TrimSuffix(path, "/*filepath"), http.FileServer(http.Dir(root)))
  63. w.router.GET(path, func(wr http.ResponseWriter, r *http.Request, _ httprouter.Params) {
  64. fileServer.ServeHTTP(wr, r)
  65. })
  66. }
  67. func (w *Wisp) Start(addr string) error {
  68. return http.ListenAndServe(addr, w.router)
  69. }
  70. func (w *Wisp) StartWithTLS(addr, certFile, keyFile string) error {
  71. return http.ListenAndServeTLS(addr, certFile, keyFile, w.router)
  72. }
  73. func (w *Wisp) handle(method, path string, h Handler, mws ...Middleware) {
  74. all := append(w.middlewares, mws...)
  75. final := w.chainMiddlewares(h, all)
  76. w.register(method, path, w.makeHTTPRouterHandler(final))
  77. }
  78. func (w *Wisp) register(method, path string, h httprouter.Handle) {
  79. switch method {
  80. case http.MethodGet:
  81. w.router.GET(path, h)
  82. case http.MethodPost:
  83. w.router.POST(path, h)
  84. case http.MethodPut:
  85. w.router.PUT(path, h)
  86. case http.MethodDelete:
  87. w.router.DELETE(path, h)
  88. case http.MethodPatch:
  89. w.router.PATCH(path, h)
  90. case http.MethodOptions:
  91. w.router.OPTIONS(path, h)
  92. case http.MethodHead:
  93. w.router.HEAD(path, h)
  94. }
  95. }
  96. func (w *Wisp) chainMiddlewares(h Handler, mws []Middleware) Handler {
  97. for i := len(mws) - 1; i >= 0; i-- {
  98. h = mws[i](h)
  99. }
  100. return h
  101. }
  102. func (w *Wisp) makeHTTPRouterHandler(h Handler) httprouter.Handle {
  103. return func(wr http.ResponseWriter, r *http.Request, p httprouter.Params) {
  104. context := &Context{
  105. response: wr,
  106. request: r,
  107. params: p,
  108. ctx: context.Background(),
  109. }
  110. if err := h(context); err != nil {
  111. w.errorHandler(err, context)
  112. }
  113. }
  114. }