package api import ( "encoding/json" "fmt" "io" "net/http" "sort" "strconv" "strings" "sync" "time" "ai-status-light/internal/database" "ai-status-light/internal/logger" mqttcli "ai-status-light/internal/mqtt" "ai-status-light/internal/web" ) type ClientStatus struct { Code string `json:"code"` Timestamp string `json:"timestamp"` } type EventRequest struct { Code string `json:"code"` Timestamp string `json:"timestamp,omitempty"` } type SSEClient struct { ch chan string closed bool mu sync.Mutex } type Server struct { db *database.DB server *http.Server sseClients map[*SSEClient]bool sseMu sync.Mutex statusMap map[int]*ClientStatus statusMu sync.RWMutex certFile string keyFile string mqttClient *mqttcli.Client bleStdin io.Writer } type Response struct { Code int `json:"code"` Message string `json:"message"` Data interface{} `json:"data,omitempty"` } func New(db *database.DB, addr string) *Server { s := &Server{ db: db, sseClients: make(map[*SSEClient]bool), statusMap: make(map[int]*ClientStatus), } mux := http.NewServeMux() mux.HandleFunc("/api/clients", s.handleClients) mux.HandleFunc("/api/event", s.handleEvent) mux.HandleFunc("/api/events", s.handleSSE) mux.HandleFunc("/api/mqtt", s.handleMQTT) mux.HandleFunc("/api/mqtt/", s.handleMQTTByID) mux.HandleFunc("/api/ble", s.handleBLE) mux.HandleFunc("/api/ble/", s.handleBLEByID) mux.HandleFunc("/api/health", s.handleHealth) mux.HandleFunc("/api/device/config", s.handleDeviceConfig) mux.HandleFunc("/api/device/config/", s.handleDeviceConfigByID) mux.HandleFunc("/api/device/config/push", s.handleDeviceConfigPush) mux.HandleFunc("/", web.Handler()) s.server = &http.Server{ Addr: addr, Handler: corsMiddleware(mux), } return s } func (s *Server) EnableTLS(certFile, keyFile string) { s.certFile = certFile s.keyFile = keyFile } func (s *Server) SetMQTTClient(client *mqttcli.Client) { s.mqttClient = client } func (s *Server) SetBLEStdin(stdin io.Writer) { s.bleStdin = stdin } func (s *Server) Start() error { if s.certFile != "" && s.keyFile != "" { logger.Info("API 服务器开始监听 (HTTPS): %s", s.server.Addr) err := s.server.ListenAndServeTLS(s.certFile, s.keyFile) if err != nil && err != http.ErrServerClosed { logger.Error("API 服务器监听失败: %v", err) } return err } logger.Info("API 服务器开始监听: %s", s.server.Addr) err := s.server.ListenAndServe() if err != nil && err != http.ErrServerClosed { logger.Error("API 服务器监听失败: %v", err) } return err } func corsMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.Header().Set("Access-Control-Allow-Origin", "*") w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS") w.Header().Set("Access-Control-Allow-Headers", "Content-Type") if r.Method == "OPTIONS" { w.WriteHeader(http.StatusOK) return } next.ServeHTTP(w, r) }) } func (s *Server) handleHealth(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, Response{Code: 0, Message: "ok"}) } func (s *Server) handleEvent(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { writeJSON(w, http.StatusMethodNotAllowed, Response{Code: -1, Message: "方法不允许"}) return } var req EventRequest if err := json.NewDecoder(r.Body).Decode(&req); err != nil { logger.Warn("事件请求体解析失败: %v", err) writeJSON(w, http.StatusBadRequest, Response{Code: -1, Message: "无效的请求体"}) return } if req.Code == "" { writeJSON(w, http.StatusBadRequest, Response{Code: -1, Message: "code 不能为空"}) return } logger.Info("收到事件: code=%s", req.Code) // 通过 MQTT 发送 if s.mqttClient != nil { payload := map[string]interface{}{ "code": req.Code, "timestamp": time.Now().Format(time.RFC3339), } if err := s.mqttClient.PublishRaw(s.mqttClient.GetTopic(), payload); err != nil { logger.Error("MQTT 发送失败: %v", err) } } // 通过 BLE 发送 if s.bleStdin != nil { msg := fmt.Sprintf(`{"code":"%s"}`+"\n", req.Code) if _, err := s.bleStdin.Write([]byte(msg)); err != nil { logger.Error("BLE 发送失败: %v", err) } } // 广播到 SSE 客户端 s.broadcastSSE(req.Code) writeJSON(w, http.StatusOK, Response{Code: 0, Message: "ok"}) } func (s *Server) handleSSE(w http.ResponseWriter, r *http.Request) { flusher, ok := w.(http.Flusher) if !ok { http.Error(w, "SSE 不支持", http.StatusInternalServerError) return } w.Header().Set("Content-Type", "text/event-stream") w.Header().Set("Cache-Control", "no-cache") w.Header().Set("Connection", "keep-alive") w.Header().Set("Access-Control-Allow-Origin", "*") client := &SSEClient{ ch: make(chan string, 10), } s.sseMu.Lock() s.sseClients[client] = true s.sseMu.Unlock() logger.Info("SSE 客户端已连接,当前连接数: %d", len(s.sseClients)) defer func() { s.sseMu.Lock() delete(s.sseClients, client) s.sseMu.Unlock() client.Close() logger.Info("SSE 客户端已断开,当前连接数: %d", len(s.sseClients)) }() // 发送初始连接消息 fmt.Fprintf(w, "event: connected\ndata: {\"status\":\"ok\"}\n\n") flusher.Flush() ctx := r.Context() for { select { case <-ctx.Done(): return case msg, ok := <-client.ch: if !ok { return } fmt.Fprintf(w, "event: status\ndata: %s\n\n", msg) flusher.Flush() } } } func (s *Server) broadcastSSE(code string) { ts := time.Now().Format(time.RFC3339) s.statusMu.Lock() s.statusMap[0] = &ClientStatus{ Code: code, Timestamp: ts, } s.statusMu.Unlock() s.sseMu.Lock() defer s.sseMu.Unlock() if len(s.sseClients) == 0 { return } payload := map[string]interface{}{ "code": code, "timestamp": ts, } data, err := json.Marshal(payload) if err != nil { logger.Error("序列化 SSE 消息失败: %v", err) return } msg := string(data) for client := range s.sseClients { client.Send(msg) } } func (c *SSEClient) Send(msg string) { c.mu.Lock() defer c.mu.Unlock() if c.closed { return } select { case c.ch <- msg: default: logger.Debug("SSE 客户端缓冲区已满,丢弃消息") } } func (c *SSEClient) Close() { c.mu.Lock() defer c.mu.Unlock() if !c.closed { c.closed = true close(c.ch) } } func (s *Server) handleClients(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodGet { writeJSON(w, http.StatusMethodNotAllowed, Response{Code: -1, Message: "方法不允许"}) return } s.statusMu.RLock() result := make([]*ClientStatus, 0, len(s.statusMap)) for _, cs := range s.statusMap { result = append(result, cs) } s.statusMu.RUnlock() sort.Slice(result, func(i, j int) bool { return result[i].Code < result[j].Code }) writeJSON(w, http.StatusOK, Response{Code: 0, Message: "success", Data: result}) } func (s *Server) handleMQTT(w http.ResponseWriter, r *http.Request) { logger.Debug("HTTP %s %s", r.Method, r.URL.Path) switch r.Method { case http.MethodGet: s.listMQTTConfigs(w, r) case http.MethodPost: s.createMQTTConfig(w, r) default: logger.Warn("不支持的 HTTP 方法: %s %s", r.Method, r.URL.Path) writeJSON(w, http.StatusMethodNotAllowed, Response{Code: -1, Message: "方法不允许"}) } } func (s *Server) handleMQTTByID(w http.ResponseWriter, r *http.Request) { logger.Debug("HTTP %s %s", r.Method, r.URL.Path) idStr := strings.TrimPrefix(r.URL.Path, "/api/mqtt/") id, err := strconv.Atoi(idStr) if err != nil { logger.Warn("无效的配置 ID: %s", idStr) writeJSON(w, http.StatusBadRequest, Response{Code: -1, Message: "无效的 ID"}) return } switch r.Method { case http.MethodGet: s.getMQTTConfig(w, id) case http.MethodPut: s.updateMQTTConfig(w, r, id) case http.MethodDelete: s.deleteMQTTConfig(w, id) default: logger.Warn("不支持的 HTTP 方法: %s %s", r.Method, r.URL.Path) writeJSON(w, http.StatusMethodNotAllowed, Response{Code: -1, Message: "方法不允许"}) } } func (s *Server) handleBLE(w http.ResponseWriter, r *http.Request) { logger.Debug("HTTP %s %s", r.Method, r.URL.Path) switch r.Method { case http.MethodGet: s.listBLEConfigs(w, r) case http.MethodPost: s.createBLEConfig(w, r) default: logger.Warn("不支持的 HTTP 方法: %s %s", r.Method, r.URL.Path) writeJSON(w, http.StatusMethodNotAllowed, Response{Code: -1, Message: "方法不允许"}) } } func (s *Server) handleBLEByID(w http.ResponseWriter, r *http.Request) { logger.Debug("HTTP %s %s", r.Method, r.URL.Path) idStr := strings.TrimPrefix(r.URL.Path, "/api/ble/") id, err := strconv.Atoi(idStr) if err != nil { logger.Warn("无效的配置 ID: %s", idStr) writeJSON(w, http.StatusBadRequest, Response{Code: -1, Message: "无效的 ID"}) return } switch r.Method { case http.MethodGet: s.getBLEConfig(w, id) case http.MethodPut: s.updateBLEConfig(w, r, id) case http.MethodDelete: s.deleteBLEConfig(w, id) default: logger.Warn("不支持的 HTTP 方法: %s %s", r.Method, r.URL.Path) writeJSON(w, http.StatusMethodNotAllowed, Response{Code: -1, Message: "方法不允许"}) } } func (s *Server) listMQTTConfigs(w http.ResponseWriter, r *http.Request) { configs, err := s.db.ListMQTTConfigs() if err != nil { logger.Error("查询 MQTT 配置列表失败: %v", err) writeJSON(w, http.StatusInternalServerError, Response{Code: -1, Message: err.Error()}) return } logger.Debug("查询 MQTT 配置列表: %d 条", len(configs)) writeJSON(w, http.StatusOK, Response{Code: 0, Message: "ok", Data: configs}) } func (s *Server) createMQTTConfig(w http.ResponseWriter, r *http.Request) { var cfg database.MQTTConfig if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil { logger.Warn("创建配置请求体解析失败: %v", err) writeJSON(w, http.StatusBadRequest, Response{Code: -1, Message: "无效的请求体"}) return } if cfg.Broker == "" { logger.Warn("创建配置: broker 为空") writeJSON(w, http.StatusBadRequest, Response{Code: -1, Message: "broker 不能为空"}) return } if cfg.ClientID == "" { cfg.ClientID = "opencode-monitor" } if cfg.Topic == "" { cfg.Topic = "opencode/status" } if err := s.db.SaveMQTTConfig(&cfg); err != nil { logger.Error("创建 MQTT 配置失败: %v", err) writeJSON(w, http.StatusInternalServerError, Response{Code: -1, Message: err.Error()}) return } logger.Info("MQTT 配置已创建: id=%d, broker=%s, topic=%s", cfg.ID, cfg.Broker, cfg.Topic) writeJSON(w, http.StatusCreated, Response{Code: 0, Message: "创建成功", Data: cfg}) } func (s *Server) getMQTTConfig(w http.ResponseWriter, id int) { configs, err := s.db.ListMQTTConfigs() if err != nil { logger.Error("查询 MQTT 配置失败: id=%d, %v", id, err) writeJSON(w, http.StatusInternalServerError, Response{Code: -1, Message: err.Error()}) return } for _, cfg := range configs { if cfg.ID == id { logger.Debug("查询 MQTT 配置: id=%d", id) writeJSON(w, http.StatusOK, Response{Code: 0, Message: "ok", Data: cfg}) return } } logger.Warn("MQTT 配置不存在: id=%d", id) writeJSON(w, http.StatusNotFound, Response{Code: -1, Message: "配置不存在"}) } func (s *Server) updateMQTTConfig(w http.ResponseWriter, r *http.Request, id int) { var cfg database.MQTTConfig if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil { logger.Warn("更新配置请求体解析失败: id=%d, %v", id, err) writeJSON(w, http.StatusBadRequest, Response{Code: -1, Message: "无效的请求体"}) return } cfg.ID = id if cfg.Broker == "" { logger.Warn("更新配置: broker 为空, id=%d", id) writeJSON(w, http.StatusBadRequest, Response{Code: -1, Message: "broker 不能为空"}) return } if cfg.ClientID == "" { cfg.ClientID = "opencode-monitor" } if cfg.Topic == "" { cfg.Topic = "opencode/status" } if err := s.db.SaveMQTTConfig(&cfg); err != nil { logger.Error("更新 MQTT 配置失败: id=%d, %v", id, err) writeJSON(w, http.StatusInternalServerError, Response{Code: -1, Message: err.Error()}) return } logger.Info("MQTT 配置已更新: id=%d, broker=%s, topic=%s", id, cfg.Broker, cfg.Topic) writeJSON(w, http.StatusOK, Response{Code: 0, Message: "更新成功", Data: cfg}) } func (s *Server) deleteMQTTConfig(w http.ResponseWriter, id int) { if err := s.db.DeleteMQTTConfig(id); err != nil { logger.Error("删除 MQTT 配置失败: id=%d, %v", id, err) writeJSON(w, http.StatusInternalServerError, Response{Code: -1, Message: err.Error()}) return } logger.Info("MQTT 配置已删除: id=%d", id) writeJSON(w, http.StatusOK, Response{Code: 0, Message: "删除成功"}) } func (s *Server) listBLEConfigs(w http.ResponseWriter, r *http.Request) { configs, err := s.db.ListBLEConfigs() if err != nil { logger.Error("查询 BLE 配置列表失败: %v", err) writeJSON(w, http.StatusInternalServerError, Response{Code: -1, Message: err.Error()}) return } logger.Debug("查询 BLE 配置列表: %d 条", len(configs)) writeJSON(w, http.StatusOK, Response{Code: 0, Message: "ok", Data: configs}) } func (s *Server) createBLEConfig(w http.ResponseWriter, r *http.Request) { var cfg database.BLEConfig if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil { logger.Warn("创建 BLE 配置请求体解析失败: %v", err) writeJSON(w, http.StatusBadRequest, Response{Code: -1, Message: "无效的请求体"}) return } if cfg.DeviceName == "" || cfg.ServiceUUID == "" || cfg.ModeCharUUID == "" || cfg.ConfigCharUUID == "" { writeJSON(w, http.StatusBadRequest, Response{Code: -1, Message: "device_name, service_uuid, mode_char_uuid, config_char_uuid 不能为空"}) return } if err := s.db.SaveBLEConfig(&cfg); err != nil { logger.Error("创建 BLE 配置失败: %v", err) writeJSON(w, http.StatusInternalServerError, Response{Code: -1, Message: err.Error()}) return } logger.Info("BLE 配置已创建: id=%d, device=%s", cfg.ID, cfg.DeviceName) writeJSON(w, http.StatusCreated, Response{Code: 0, Message: "创建成功", Data: cfg}) } func (s *Server) getBLEConfig(w http.ResponseWriter, id int) { configs, err := s.db.ListBLEConfigs() if err != nil { logger.Error("查询 BLE 配置失败: id=%d, %v", id, err) writeJSON(w, http.StatusInternalServerError, Response{Code: -1, Message: err.Error()}) return } for _, cfg := range configs { if cfg.ID == id { logger.Debug("查询 BLE 配置: id=%d", id) writeJSON(w, http.StatusOK, Response{Code: 0, Message: "ok", Data: cfg}) return } } logger.Warn("BLE 配置不存在: id=%d", id) writeJSON(w, http.StatusNotFound, Response{Code: -1, Message: "配置不存在"}) } func (s *Server) updateBLEConfig(w http.ResponseWriter, r *http.Request, id int) { var cfg database.BLEConfig if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil { logger.Warn("更新 BLE 配置请求体解析失败: id=%d, %v", id, err) writeJSON(w, http.StatusBadRequest, Response{Code: -1, Message: "无效的请求体"}) return } cfg.ID = id if cfg.DeviceName == "" || cfg.ServiceUUID == "" || cfg.ModeCharUUID == "" || cfg.ConfigCharUUID == "" { writeJSON(w, http.StatusBadRequest, Response{Code: -1, Message: "device_name, service_uuid, mode_char_uuid, config_char_uuid 不能为空"}) return } if err := s.db.SaveBLEConfig(&cfg); err != nil { logger.Error("更新 BLE 配置失败: id=%d, %v", id, err) writeJSON(w, http.StatusInternalServerError, Response{Code: -1, Message: err.Error()}) return } logger.Info("BLE 配置已更新: id=%d, device=%s", id, cfg.DeviceName) writeJSON(w, http.StatusOK, Response{Code: 0, Message: "更新成功", Data: cfg}) } func (s *Server) deleteBLEConfig(w http.ResponseWriter, id int) { if err := s.db.DeleteBLEConfig(id); err != nil { logger.Error("删除 BLE 配置失败: id=%d, %v", id, err) writeJSON(w, http.StatusInternalServerError, Response{Code: -1, Message: err.Error()}) return } logger.Info("BLE 配置已删除: id=%d", id) writeJSON(w, http.StatusOK, Response{Code: 0, Message: "删除成功"}) } func writeJSON(w http.ResponseWriter, statusCode int, data interface{}) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(statusCode) json.NewEncoder(w).Encode(data) } func (s *Server) GetAddr() string { return s.server.Addr } func (s *Server) handleDeviceConfig(w http.ResponseWriter, r *http.Request) { logger.Debug("HTTP %s %s", r.Method, r.URL.Path) switch r.Method { case http.MethodGet: s.listDeviceConfigs(w, r) case http.MethodPost: s.createDeviceConfig(w, r) default: logger.Warn("不支持的 HTTP 方法: %s %s", r.Method, r.URL.Path) writeJSON(w, http.StatusMethodNotAllowed, Response{Code: -1, Message: "方法不允许"}) } } func (s *Server) handleDeviceConfigByID(w http.ResponseWriter, r *http.Request) { logger.Debug("HTTP %s %s", r.Method, r.URL.Path) idStr := strings.TrimPrefix(r.URL.Path, "/api/device/config/") if idStr == "push" { s.handleDeviceConfigPush(w, r) return } id, err := strconv.Atoi(idStr) if err != nil { logger.Warn("无效的配置 ID: %s", idStr) writeJSON(w, http.StatusBadRequest, Response{Code: -1, Message: "无效的 ID"}) return } switch r.Method { case http.MethodGet: s.getDeviceConfig(w, id) case http.MethodPut: s.updateDeviceConfig(w, r, id) case http.MethodDelete: s.deleteDeviceConfig(w, id) default: logger.Warn("不支持的 HTTP 方法: %s %s", r.Method, r.URL.Path) writeJSON(w, http.StatusMethodNotAllowed, Response{Code: -1, Message: "方法不允许"}) } } func (s *Server) handleDeviceConfigPush(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { writeJSON(w, http.StatusMethodNotAllowed, Response{Code: -1, Message: "方法不允许"}) return } if s.mqttClient == nil { writeJSON(w, http.StatusBadRequest, Response{Code: -1, Message: "MQTT 未连接"}) return } var req struct { ID int `json:"id"` Reset bool `json:"reset,omitempty"` } if err := json.NewDecoder(r.Body).Decode(&req); err != nil { writeJSON(w, http.StatusBadRequest, Response{Code: -1, Message: "无效的请求体"}) return } configs, err := s.db.ListDeviceConfigs() if err != nil { writeJSON(w, http.StatusInternalServerError, Response{Code: -1, Message: err.Error()}) return } var targetCfg *database.DeviceConfig for _, cfg := range configs { if cfg.ID == req.ID { targetCfg = &cfg break } } if targetCfg == nil { writeJSON(w, http.StatusNotFound, Response{Code: -1, Message: "配置不存在"}) return } payload := map[string]interface{}{} if targetCfg.WifiSSID != "" { payload["wifi_ssid"] = targetCfg.WifiSSID } if targetCfg.WifiPass != "" { payload["wifi_pass"] = targetCfg.WifiPass } if targetCfg.MqttBroker != "" { payload["mqtt_broker"] = targetCfg.MqttBroker } if targetCfg.MqttPort > 0 { payload["mqtt_port"] = targetCfg.MqttPort } if targetCfg.MqttUser != "" { payload["mqtt_user"] = targetCfg.MqttUser } if targetCfg.MqttPass != "" { payload["mqtt_pass"] = targetCfg.MqttPass } if targetCfg.MqttClient != "" { payload["mqtt_client"] = targetCfg.MqttClient } if targetCfg.MqttTopic != "" { payload["mqtt_topic"] = targetCfg.MqttTopic } if targetCfg.MqttStatus != "" { payload["mqtt_status"] = targetCfg.MqttStatus } if targetCfg.PinRed > 0 { payload["pin_red"] = targetCfg.PinRed } if targetCfg.PinGreen > 0 { payload["pin_green"] = targetCfg.PinGreen } if targetCfg.PinYellow > 0 { payload["pin_yellow"] = targetCfg.PinYellow } if req.Reset { payload["factory_reset"] = true } if err := s.mqttClient.PublishRaw(targetCfg.ConfigTopic, payload); err != nil { logger.Error("推送设备配置失败: %v", err) writeJSON(w, http.StatusInternalServerError, Response{Code: -1, Message: "推送配置失败: " + err.Error()}) return } logger.Info("设备配置已推送到 topic: %s", targetCfg.ConfigTopic) writeJSON(w, http.StatusOK, Response{Code: 0, Message: "配置已推送"}) } func (s *Server) listDeviceConfigs(w http.ResponseWriter, r *http.Request) { configs, err := s.db.ListDeviceConfigs() if err != nil { logger.Error("查询设备配置列表失败: %v", err) writeJSON(w, http.StatusInternalServerError, Response{Code: -1, Message: err.Error()}) return } logger.Debug("查询设备配置列表: %d 条", len(configs)) writeJSON(w, http.StatusOK, Response{Code: 0, Message: "ok", Data: configs}) } func (s *Server) createDeviceConfig(w http.ResponseWriter, r *http.Request) { var cfg database.DeviceConfig if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil { logger.Warn("创建设备配置请求体解析失败: %v", err) writeJSON(w, http.StatusBadRequest, Response{Code: -1, Message: "无效的请求体"}) return } if cfg.DeviceName == "" { writeJSON(w, http.StatusBadRequest, Response{Code: -1, Message: "device_name 不能为空"}) return } if cfg.ConfigTopic == "" { cfg.ConfigTopic = "agent/status/config" } if err := s.db.SaveDeviceConfig(&cfg); err != nil { logger.Error("创建设备配置失败: %v", err) writeJSON(w, http.StatusInternalServerError, Response{Code: -1, Message: err.Error()}) return } logger.Info("设备配置已创建: id=%d, device=%s", cfg.ID, cfg.DeviceName) writeJSON(w, http.StatusCreated, Response{Code: 0, Message: "创建成功", Data: cfg}) } func (s *Server) getDeviceConfig(w http.ResponseWriter, id int) { configs, err := s.db.ListDeviceConfigs() if err != nil { logger.Error("查询设备配置失败: id=%d, %v", id, err) writeJSON(w, http.StatusInternalServerError, Response{Code: -1, Message: err.Error()}) return } for _, cfg := range configs { if cfg.ID == id { logger.Debug("查询设备配置: id=%d", id) writeJSON(w, http.StatusOK, Response{Code: 0, Message: "ok", Data: cfg}) return } } logger.Warn("设备配置不存在: id=%d", id) writeJSON(w, http.StatusNotFound, Response{Code: -1, Message: "配置不存在"}) } func (s *Server) updateDeviceConfig(w http.ResponseWriter, r *http.Request, id int) { var cfg database.DeviceConfig if err := json.NewDecoder(r.Body).Decode(&cfg); err != nil { logger.Warn("更新设备配置请求体解析失败: id=%d, %v", id, err) writeJSON(w, http.StatusBadRequest, Response{Code: -1, Message: "无效的请求体"}) return } cfg.ID = id if cfg.DeviceName == "" { writeJSON(w, http.StatusBadRequest, Response{Code: -1, Message: "device_name 不能为空"}) return } if cfg.ConfigTopic == "" { cfg.ConfigTopic = "agent/status/config" } if err := s.db.SaveDeviceConfig(&cfg); err != nil { logger.Error("更新设备配置失败: id=%d, %v", id, err) writeJSON(w, http.StatusInternalServerError, Response{Code: -1, Message: err.Error()}) return } logger.Info("设备配置已更新: id=%d, device=%s", id, cfg.DeviceName) writeJSON(w, http.StatusOK, Response{Code: 0, Message: "更新成功", Data: cfg}) } func (s *Server) deleteDeviceConfig(w http.ResponseWriter, id int) { if err := s.db.DeleteDeviceConfig(id); err != nil { logger.Error("删除设备配置失败: id=%d, %v", id, err) writeJSON(w, http.StatusInternalServerError, Response{Code: -1, Message: err.Error()}) return } logger.Info("设备配置已删除: id=%d", id) writeJSON(w, http.StatusOK, Response{Code: 0, Message: "删除成功"}) }