api.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. package api
  2. import (
  3. "encoding/json"
  4. "net/http"
  5. "strconv"
  6. "strings"
  7. "AI-Status-Light/internal/database"
  8. )
  9. type Server struct {
  10. db *database.DB
  11. server *http.Server
  12. }
  13. type Response struct {
  14. Code int `json:"code"`
  15. Message string `json:"message"`
  16. Data interface{} `json:"data,omitempty"`
  17. }
  18. func New(db *database.DB, addr string) *Server {
  19. s := &Server{db: db}
  20. mux := http.NewServeMux()
  21. mux.HandleFunc("/api/mqtt", s.handleMQTT)
  22. mux.HandleFunc("/api/mqtt/", s.handleMQTTByID)
  23. mux.HandleFunc("/api/health", s.handleHealth)
  24. s.server = &http.Server{
  25. Addr: addr,
  26. Handler: corsMiddleware(mux),
  27. }
  28. return s
  29. }
  30. func (s *Server) Start() error {
  31. return s.server.ListenAndServe()
  32. }
  33. func corsMiddleware(next http.Handler) http.Handler {
  34. return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
  35. w.Header().Set("Access-Control-Allow-Origin", "*")
  36. w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
  37. w.Header().Set("Access-Control-Allow-Headers", "Content-Type")
  38. if r.Method == "OPTIONS" {
  39. w.WriteHeader(http.StatusOK)
  40. return
  41. }
  42. next.ServeHTTP(w, r)
  43. })
  44. }
  45. func (s *Server) handleHealth(w http.ResponseWriter, r *http.Request) {
  46. writeJSON(w, http.StatusOK, Response{Code: 0, Message: "ok"})
  47. }
  48. func (s *Server) handleMQTT(w http.ResponseWriter, r *http.Request) {
  49. switch r.Method {
  50. case http.MethodGet:
  51. s.listMQTTConfigs(w, r)
  52. case http.MethodPost:
  53. s.createMQTTConfig(w, r)
  54. default:
  55. writeJSON(w, http.StatusMethodNotAllowed, Response{Code: -1, Message: "方法不允许"})
  56. }
  57. }
  58. func (s *Server) handleMQTTByID(w http.ResponseWriter, r *http.Request) {
  59. idStr := strings.TrimPrefix(r.URL.Path, "/api/mqtt/")
  60. id, err := strconv.Atoi(idStr)
  61. if err != nil {
  62. writeJSON(w, http.StatusBadRequest, Response{Code: -1, Message: "无效的 ID"})
  63. return
  64. }
  65. switch r.Method {
  66. case http.MethodGet:
  67. s.getMQTTConfig(w, id)
  68. case http.MethodPut:
  69. s.updateMQTTConfig(w, r, id)
  70. case http.MethodDelete:
  71. s.deleteMQTTConfig(w, id)
  72. default:
  73. writeJSON(w, http.StatusMethodNotAllowed, Response{Code: -1, Message: "方法不允许"})
  74. }
  75. }
  76. func (s *Server) listMQTTConfigs(w http.ResponseWriter, r *http.Request) {
  77. configs, err := s.db.ListMQTTConfigs()
  78. if err != nil {
  79. writeJSON(w, http.StatusInternalServerError, Response{Code: -1, Message: err.Error()})
  80. return
  81. }
  82. writeJSON(w, http.StatusOK, Response{Code: 0, Message: "ok", Data: configs})
  83. }
  84. func (s *Server) createMQTTConfig(w http.ResponseWriter, r *http.Request) {
  85. var cfg database.MQTTConfig
  86. if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil {
  87. writeJSON(w, http.StatusBadRequest, Response{Code: -1, Message: "无效的请求体"})
  88. return
  89. }
  90. if cfg.Broker == "" {
  91. writeJSON(w, http.StatusBadRequest, Response{Code: -1, Message: "broker 不能为空"})
  92. return
  93. }
  94. if cfg.ClientID == "" {
  95. cfg.ClientID = "opencode-monitor"
  96. }
  97. if cfg.Topic == "" {
  98. cfg.Topic = "opencode/status"
  99. }
  100. if err := s.db.SaveMQTTConfig(&cfg); err != nil {
  101. writeJSON(w, http.StatusInternalServerError, Response{Code: -1, Message: err.Error()})
  102. return
  103. }
  104. writeJSON(w, http.StatusCreated, Response{Code: 0, Message: "创建成功", Data: cfg})
  105. }
  106. func (s *Server) getMQTTConfig(w http.ResponseWriter, id int) {
  107. configs, err := s.db.ListMQTTConfigs()
  108. if err != nil {
  109. writeJSON(w, http.StatusInternalServerError, Response{Code: -1, Message: err.Error()})
  110. return
  111. }
  112. for _, cfg := range configs {
  113. if cfg.ID == id {
  114. writeJSON(w, http.StatusOK, Response{Code: 0, Message: "ok", Data: cfg})
  115. return
  116. }
  117. }
  118. writeJSON(w, http.StatusNotFound, Response{Code: -1, Message: "配置不存在"})
  119. }
  120. func (s *Server) updateMQTTConfig(w http.ResponseWriter, r *http.Request, id int) {
  121. var cfg database.MQTTConfig
  122. if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil {
  123. writeJSON(w, http.StatusBadRequest, Response{Code: -1, Message: "无效的请求体"})
  124. return
  125. }
  126. cfg.ID = id
  127. if cfg.Broker == "" {
  128. writeJSON(w, http.StatusBadRequest, Response{Code: -1, Message: "broker 不能为空"})
  129. return
  130. }
  131. if cfg.ClientID == "" {
  132. cfg.ClientID = "opencode-monitor"
  133. }
  134. if cfg.Topic == "" {
  135. cfg.Topic = "opencode/status"
  136. }
  137. if err := s.db.SaveMQTTConfig(&cfg); err != nil {
  138. writeJSON(w, http.StatusInternalServerError, Response{Code: -1, Message: err.Error()})
  139. return
  140. }
  141. writeJSON(w, http.StatusOK, Response{Code: 0, Message: "更新成功", Data: cfg})
  142. }
  143. func (s *Server) deleteMQTTConfig(w http.ResponseWriter, id int) {
  144. if err := s.db.DeleteMQTTConfig(id); err != nil {
  145. writeJSON(w, http.StatusInternalServerError, Response{Code: -1, Message: err.Error()})
  146. return
  147. }
  148. writeJSON(w, http.StatusOK, Response{Code: 0, Message: "删除成功"})
  149. }
  150. func writeJSON(w http.ResponseWriter, statusCode int, data interface{}) {
  151. w.Header().Set("Content-Type", "application/json")
  152. w.WriteHeader(statusCode)
  153. json.NewEncoder(w).Encode(data)
  154. }
  155. func (s *Server) GetAddr() string {
  156. return s.server.Addr
  157. }