restful-api.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. package restful_api
  2. import (
  3. "encoding/json"
  4. "github.com/go-chi/chi/v5"
  5. "github.com/go-chi/chi/v5/middleware"
  6. "github.com/go-playground/validator/v10"
  7. "net"
  8. "net/http"
  9. "strings"
  10. )
  11. func JSONResponse(w http.ResponseWriter, data interface{}, code int) {
  12. w.Header().Set("Content-Type", "application/json; charset=utf-8")
  13. w.Header().Set("X-Content-Type-Options", "nosniff")
  14. w.WriteHeader(code)
  15. _ = json.NewEncoder(w).Encode(data)
  16. }
  17. var validate *validator.Validate
  18. type StatsUser struct {
  19. uuid string `validate:"required_without=email,uuid4"`
  20. email string `validate:"required_without=uuid,email"`
  21. }
  22. type StatsUserResponse struct {
  23. Uplink int64 `json:"uplink"`
  24. Downlink int64 `json:"downlink"`
  25. }
  26. func (rs *restfulService) statsUser(w http.ResponseWriter, r *http.Request) {
  27. query := r.URL.Query()
  28. statsUser := &StatsUser{
  29. uuid: query.Get("uuid"),
  30. email: query.Get("email"),
  31. }
  32. if err := validate.Struct(statsUser); err != nil {
  33. JSONResponse(w, http.StatusText(422), 422)
  34. }
  35. response := &StatsUserResponse{
  36. Uplink: 0,
  37. Downlink: 0,
  38. }
  39. JSONResponse(w, response, 200)
  40. }
  41. type Stats struct {
  42. tag string `validate:"required,alpha,min=1,max=255"`
  43. }
  44. type StatsBound struct { // Better name?
  45. Uplink int64 `json:"uplink"`
  46. Downlink int64 `json:"downlink"`
  47. }
  48. type StatsResponse struct {
  49. Inbound StatsBound `json:"inbound"`
  50. Outbound StatsBound `json:"outbound"`
  51. }
  52. func (rs *restfulService) statsRequest(w http.ResponseWriter, r *http.Request) {
  53. stats := &Stats{
  54. tag: r.URL.Query().Get("tag"),
  55. }
  56. if err := validate.Struct(stats); err != nil {
  57. JSONResponse(w, http.StatusText(422), 422)
  58. }
  59. response := StatsResponse{
  60. Inbound: StatsBound{
  61. Uplink: 1,
  62. Downlink: 1,
  63. },
  64. Outbound: StatsBound{
  65. Uplink: 1,
  66. Downlink: 1,
  67. }}
  68. JSONResponse(w, response, 200)
  69. }
  70. func (rs *restfulService) TokenAuthMiddleware(next http.Handler) http.Handler {
  71. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  72. auth := r.Header.Get("Authorization")
  73. const prefix = "Bearer "
  74. if !strings.HasPrefix(auth, prefix) {
  75. JSONResponse(w, http.StatusText(403), 403)
  76. return
  77. }
  78. auth = strings.TrimPrefix(auth, prefix)
  79. if auth != rs.config.AuthToken {
  80. JSONResponse(w, http.StatusText(403), 403)
  81. return
  82. }
  83. next.ServeHTTP(w, r)
  84. })
  85. }
  86. func (rs *restfulService) start() error {
  87. r := chi.NewRouter()
  88. r.Use(rs.TokenAuthMiddleware)
  89. r.Use(middleware.Heartbeat("/ping"))
  90. r.Route("/v1", func(r chi.Router) {
  91. r.Get("/stats/user", rs.statsUser)
  92. r.Get("/stats", rs.statsRequest)
  93. })
  94. go func() {
  95. err := http.ListenAndServe(net.JoinHostPort(rs.config.ListenAddr, string(rs.config.ListenPort)), r)
  96. if err != nil {
  97. newError("unable to serve restful api").WriteToLog()
  98. }
  99. }()
  100. return nil
  101. }