apiserv.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. package apiserv
  2. import (
  3. "net/http"
  4. "regexp"
  5. "strings"
  6. "github.com/vladimirok5959/golang-utils/utils/http/logger"
  7. )
  8. var mParam = regexp.MustCompile(`\{([^/]*)}`)
  9. var TestingMockParams func() []Param = nil
  10. var mParams = &Params{
  11. list: map[*http.Request][]Param{},
  12. }
  13. type ServeMux struct {
  14. handlers *Handlers
  15. }
  16. func NewServeMux() *ServeMux {
  17. s := ServeMux{
  18. handlers: &Handlers{
  19. list: map[*regexp.Regexp]Handler{},
  20. },
  21. }
  22. return &s
  23. }
  24. func GetParams(r *http.Request) []Param {
  25. if TestingMockParams != nil {
  26. return TestingMockParams()
  27. }
  28. mParams.Lock()
  29. defer mParams.Unlock()
  30. if v, ok := mParams.list[r]; ok {
  31. return v
  32. }
  33. return []Param{}
  34. }
  35. func (s ServeMux) regexp(pattern string) string {
  36. pattern = strings.ReplaceAll(pattern, "-", "\\-")
  37. pattern = strings.ReplaceAll(pattern, ".", "\\.")
  38. pattern = strings.ReplaceAll(pattern, "/", "\\/")
  39. pattern = mParam.ReplaceAllStringFunc(pattern, func(str string) string {
  40. if str == "{i}" {
  41. return "([\\d]+)"
  42. } else if str == "{s}" {
  43. return "([^\\/]+)"
  44. }
  45. return str
  46. })
  47. return "(?i)^" + pattern + "$"
  48. }
  49. func (s ServeMux) Delete(pattern string, handler http.Handler) {
  50. s.Handle(pattern, []string{http.MethodDelete}, handler)
  51. }
  52. func (s ServeMux) Get(pattern string, handler http.Handler) {
  53. s.Handle(pattern, []string{http.MethodGet}, handler)
  54. }
  55. func (s ServeMux) Handle(pattern string, methods []string, handler http.Handler) {
  56. s.handlers.Lock()
  57. defer s.handlers.Unlock()
  58. if pattern != "" {
  59. re := regexp.MustCompile(s.regexp(pattern))
  60. s.handlers.list[re] = Handler{
  61. handler: handler,
  62. methods: methods,
  63. }
  64. } else {
  65. s.handlers.list[nil] = Handler{
  66. handler: handler,
  67. methods: methods,
  68. }
  69. }
  70. }
  71. func (s ServeMux) NotFound(handler http.Handler) {
  72. s.Handle("", []string{http.MethodGet}, handler)
  73. }
  74. func (s ServeMux) Options(pattern string, handler http.Handler) {
  75. s.Handle(pattern, []string{http.MethodOptions}, handler)
  76. }
  77. func (s ServeMux) Patch(pattern string, handler http.Handler) {
  78. s.Handle(pattern, []string{http.MethodPatch}, handler)
  79. }
  80. func (s ServeMux) Post(pattern string, handler http.Handler) {
  81. s.Handle(pattern, []string{http.MethodPost}, handler)
  82. }
  83. func (s ServeMux) Put(pattern string, handler http.Handler) {
  84. s.Handle(pattern, []string{http.MethodPut}, handler)
  85. }
  86. func (s ServeMux) ServeHTTP(w http.ResponseWriter, r *http.Request) {
  87. s.handlers.Lock()
  88. defer s.handlers.Unlock()
  89. for re, h := range s.handlers.list {
  90. if re != nil && re.Match([]byte(r.URL.Path)) {
  91. if h.IsMethod(r.Method) {
  92. if rs := re.FindAllStringSubmatch(r.URL.Path, 1); len(rs) >= 1 {
  93. defer func() {
  94. mParams.Lock()
  95. delete(mParams.list, r)
  96. defer mParams.Unlock()
  97. }()
  98. mParams.Lock()
  99. for _, p := range rs[0] {
  100. if _, ok := mParams.list[r]; !ok {
  101. mParams.list[r] = []Param{{Value: p}}
  102. } else {
  103. mParams.list[r] = append(mParams.list[r], Param{Value: p})
  104. }
  105. select {
  106. case <-r.Context().Done():
  107. mParams.Unlock()
  108. return
  109. default:
  110. }
  111. }
  112. mParams.Unlock()
  113. }
  114. select {
  115. case <-r.Context().Done():
  116. return
  117. default:
  118. }
  119. logger.LogRequests(h.handler).ServeHTTP(w, r)
  120. return
  121. } else {
  122. w.WriteHeader(http.StatusMethodNotAllowed)
  123. return
  124. }
  125. }
  126. select {
  127. case <-r.Context().Done():
  128. return
  129. default:
  130. }
  131. }
  132. // Error 404
  133. if h, ok := s.handlers.list[nil]; ok {
  134. logger.LogRequests(h.handler).ServeHTTP(w, r)
  135. return
  136. }
  137. w.WriteHeader(http.StatusNotFound)
  138. }