mgmt_api.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. package http
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "log/slog"
  6. "net/http"
  7. "os"
  8. "github.com/google/uuid"
  9. "github.com/mk6i/retro-aim-server/config"
  10. "github.com/mk6i/retro-aim-server/state"
  11. )
  12. type createUser struct {
  13. state.User
  14. Password string `json:"password,omitempty"`
  15. }
  16. type userSession struct {
  17. ScreenName string `json:"screen_name"`
  18. }
  19. type onlineUsers struct {
  20. Count int `json:"count"`
  21. Sessions []userSession `json:"sessions"`
  22. }
  23. type UserManager interface {
  24. AllUsers() ([]state.User, error)
  25. InsertUser(u state.User) error
  26. }
  27. type SessionRetriever interface {
  28. AllSessions() []*state.Session
  29. }
  30. func StartManagementAPI(userManager UserManager, sessionRetriever SessionRetriever, logger *slog.Logger) {
  31. mux := http.NewServeMux()
  32. mux.HandleFunc("/user", func(w http.ResponseWriter, r *http.Request) {
  33. userHandler(w, r, userManager, logger)
  34. })
  35. mux.HandleFunc("/session", func(w http.ResponseWriter, r *http.Request) {
  36. sessionHandler(w, r, sessionRetriever)
  37. })
  38. //todo make port configurable
  39. addr := config.Address("", 8080)
  40. logger.Info("starting management API server", "addr", addr)
  41. if err := http.ListenAndServe(addr, mux); err != nil {
  42. logger.Error("unable to bind management API address address", "err", err.Error())
  43. os.Exit(1)
  44. }
  45. }
  46. func userHandler(w http.ResponseWriter, r *http.Request, userManager UserManager, logger *slog.Logger) {
  47. switch r.Method {
  48. case http.MethodGet:
  49. getUserHandler(w, r, userManager, logger)
  50. case http.MethodPost:
  51. postUserHandler(w, r, userManager, logger)
  52. default:
  53. http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
  54. }
  55. }
  56. // sessionHandler handles GET /session
  57. func sessionHandler(w http.ResponseWriter, r *http.Request, sessionRetriever SessionRetriever) {
  58. w.Header().Set("Content-Type", "application/json")
  59. if r.Method != http.MethodGet {
  60. http.Error(w, "method not allowed", http.StatusMethodNotAllowed)
  61. return
  62. }
  63. allUsers := sessionRetriever.AllSessions()
  64. ou := onlineUsers{
  65. Count: len(allUsers),
  66. Sessions: make([]userSession, 0),
  67. }
  68. for _, s := range allUsers {
  69. ou.Sessions = append(ou.Sessions, userSession{
  70. ScreenName: s.ScreenName(),
  71. })
  72. }
  73. if err := json.NewEncoder(w).Encode(ou); err != nil {
  74. http.Error(w, err.Error(), http.StatusInternalServerError)
  75. return
  76. }
  77. }
  78. // getUserHandler handles the GET /user endpoint.
  79. func getUserHandler(w http.ResponseWriter, _ *http.Request, userManager UserManager, logger *slog.Logger) {
  80. w.Header().Set("Content-Type", "application/json")
  81. users, err := userManager.AllUsers()
  82. if err != nil {
  83. logger.Error("error in GET /user", "err", err.Error())
  84. http.Error(w, "internal server error", http.StatusInternalServerError)
  85. return
  86. }
  87. if err := json.NewEncoder(w).Encode(users); err != nil {
  88. http.Error(w, err.Error(), http.StatusInternalServerError)
  89. return
  90. }
  91. }
  92. // postUserHandler handles the POST /user endpoint.
  93. func postUserHandler(w http.ResponseWriter, r *http.Request, userManager UserManager, logger *slog.Logger) {
  94. var newUser createUser
  95. if err := json.NewDecoder(r.Body).Decode(&newUser); err != nil {
  96. http.Error(w, "malformed input", http.StatusBadRequest)
  97. return
  98. }
  99. newUser.AuthKey = uuid.New().String()
  100. // todo does the request contain authkey?
  101. newUser.HashPassword(newUser.Password)
  102. if err := userManager.InsertUser(newUser.User); err != nil {
  103. logger.Error("error in GET /user", "err", err.Error())
  104. http.Error(w, "internal server error", http.StatusInternalServerError)
  105. return
  106. }
  107. w.WriteHeader(http.StatusCreated)
  108. fmt.Fprintln(w, "User account created successfully.")
  109. }