server.go 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. package rest
  2. import (
  3. "context"
  4. "errors"
  5. "fmt"
  6. "net/http"
  7. "sync/atomic"
  8. "time"
  9. "git.ali33.ru/fcg-xvii/go-tools/json"
  10. "github.com/dgrijalva/jwt-go"
  11. )
  12. // IServer реализует интерфейс сервера для рест апи
  13. type IServer interface {
  14. // Addr возвращеат адрес, который сервер слушает
  15. Addr() string
  16. // Secret возвращает секретный ключ, при помощи которого генерируются токены авторизации пользователей
  17. Secret() []byte
  18. // HandleFunc устанавливает функцию обработчик, которая будет вызвана по обращению к URL, удовлетворяющему pattern
  19. HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request))
  20. // Listen запускает прослушивание сервера. Если не удалось успешно запустить прослушивание через
  21. // заданный временной интервал (timeout), будет возвращена ошибка
  22. Listen(timeout time.Duration, ctxParent context.Context) error
  23. // TokenGenerate - функция генерации токена авторизации
  24. TokenGenerate(m json.Map, expire int64) (string, error)
  25. // TokenParse - функция для расшифровки токена в карту значений
  26. TokenParse(token string) (json.Map, error)
  27. // Close останавливает прослушивание
  28. Close() error
  29. // Context возвращает контекст сервера
  30. Context() context.Context
  31. }
  32. // NewServer создает сервер для реализации рест апи
  33. func NewServer(addr string, secret []byte) IServer {
  34. return &Server{
  35. secret: secret,
  36. server: &http.Server{
  37. Addr: addr,
  38. Handler: http.NewServeMux(),
  39. },
  40. }
  41. }
  42. func NewServerTLS(addr string, secret []byte, tlsKey, tlsCert string) IServer {
  43. serv := NewServer(addr, secret).(*Server)
  44. serv.tlsEnabled = true
  45. serv.tlsKey = tlsKey
  46. serv.tlsCert = tlsCert
  47. return serv
  48. }
  49. // Server реализует сервер для рест апи
  50. type Server struct {
  51. secret []byte
  52. server *http.Server
  53. opened atomic.Bool
  54. ctx context.Context
  55. cancel context.CancelFunc
  56. tlsEnabled bool
  57. tlsKey string
  58. tlsCert string
  59. }
  60. // Context возвращает контекст сервера
  61. func (s *Server) Context() context.Context {
  62. return s.ctx
  63. }
  64. // Close останавливает прослушивание
  65. func (s *Server) Close() error {
  66. if !s.opened.Load() {
  67. return errors.New("ErrNotOpened")
  68. }
  69. s.cancel()
  70. return nil
  71. }
  72. // Listen запускает прослушивание сервера. Если не удалось успешно запустить прослушивание через
  73. // заданный временной интервал (timeout), будет возвращена ошибка
  74. func (s *Server) Listen(timeout time.Duration, ctxParent context.Context) (err error) {
  75. if s.opened.Swap(true) {
  76. return errors.New("ErrAlreadyOpened")
  77. }
  78. ctx, _ := context.WithTimeout(ctxParent, timeout)
  79. go func() {
  80. var cancel context.CancelFunc
  81. s.ctx, cancel = context.WithCancel(ctxParent)
  82. if !s.tlsEnabled {
  83. err = s.server.ListenAndServe()
  84. } else {
  85. err = s.server.ListenAndServeTLS(s.tlsCert, s.tlsKey)
  86. }
  87. s.opened.Store(false)
  88. cancel()
  89. }()
  90. <-ctx.Done()
  91. if err == nil {
  92. go func() {
  93. <-s.ctx.Done()
  94. s.server.Close()
  95. }()
  96. }
  97. return
  98. }
  99. // TokenGenerate - функция генерации токена авторизации
  100. func (s *Server) TokenGenerate(m json.Map, expire int64) (string, error) {
  101. token := jwt.New(jwt.SigningMethodHS256)
  102. claims := token.Claims.(jwt.MapClaims)
  103. for key, val := range m {
  104. claims[key] = val
  105. }
  106. if expire > 0 {
  107. //claims["exp"] = time.Now().UTC().Add(time.Minute * 30).Unix()
  108. claims["exp"] = expire
  109. }
  110. tokenString, err := token.SignedString(s.Secret())
  111. return tokenString, err
  112. }
  113. func (s *Server) TokenParse(tokenString string) (json.Map, error) {
  114. token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
  115. if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
  116. return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
  117. }
  118. return s.Secret(), nil
  119. })
  120. if err != nil {
  121. return nil, err
  122. }
  123. if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
  124. return json.Map(claims), nil
  125. }
  126. return nil, errors.New("invalid token")
  127. }
  128. // Addr возвращеат адрес, который сервер слушает
  129. func (s *Server) Addr() string {
  130. return s.server.Addr
  131. }
  132. // Secret возвращает секретный ключ, при помощи которого генерируются токены авторизации пользователей
  133. func (s *Server) Secret() []byte {
  134. return s.secret
  135. }
  136. // HandleFunc устанавливает функцию обработчик, которая будет вызвана по обращению к URL, удовлетворяющему pattern
  137. func (s *Server) HandleFunc(pattern string, handler func(http.ResponseWriter, *http.Request)) {
  138. s.server.Handler.(*http.ServeMux).HandleFunc(pattern, handler)
  139. }