package main import ( "encoding/json" "net/http" "strconv" "powerpod/gotool/pb" ) type deadzoneAPIResponse struct { Deadzone uint32 `json:"deadzone"` ClientID uint32 `json:"client_id"` Success bool `json:"success"` SlavesUpdated uint32 `json:"slaves_updated"` Error string `json:"error,omitempty"` } type deadzoneAPIRequest struct { Write bool `json:"write"` Deadzone uint32 `json:"deadzone"` ClientID uint32 `json:"client_id"` AllClients bool `json:"all_clients"` } type unicastAPIRequest struct { ClientID uint32 `json:"client_id"` Seq uint32 `json:"seq"` } type unicastAPIResponse struct { Success bool `json:"success"` Seq uint32 `json:"seq"` Error string `json:"error,omitempty"` } func mountServeAPI(mux *http.ServeMux, link *managedSerial) { mux.HandleFunc("/api/deadzone", func(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: serveDeadzoneGet(w, r, link) case http.MethodPost: serveDeadzonePost(w, r, link) default: http.Error(w, "method not allowed", http.StatusMethodNotAllowed) } }) mux.HandleFunc("/api/unicast-test", func(w http.ResponseWriter, r *http.Request) { if r.Method != http.MethodPost { http.Error(w, "method not allowed", http.StatusMethodNotAllowed) return } serveUnicastTest(w, r, link) }) } func serveDeadzoneGet(w http.ResponseWriter, r *http.Request, link *managedSerial) { clientID, err := parseUintQuery(r, "client_id", 0) if err != nil { writeJSON(w, http.StatusBadRequest, deadzoneAPIResponse{Error: err.Error()}) return } resp, err := link.AccelDeadzone(&pb.AccelDeadzoneRequest{ Write: false, ClientId: clientID, }) if err != nil { writeJSON(w, http.StatusServiceUnavailable, deadzoneAPIResponse{ ClientID: clientID, Error: err.Error(), }) return } writeJSON(w, http.StatusOK, deadzoneAPIResponse{ Deadzone: resp.GetDeadzone(), ClientID: resp.GetClientId(), Success: resp.GetSuccess(), }) } func serveDeadzonePost(w http.ResponseWriter, r *http.Request, link *managedSerial) { var body deadzoneAPIRequest if err := json.NewDecoder(r.Body).Decode(&body); err != nil { writeJSON(w, http.StatusBadRequest, deadzoneAPIResponse{Error: "invalid JSON"}) return } resp, err := link.AccelDeadzone(&pb.AccelDeadzoneRequest{ Write: true, Deadzone: body.Deadzone, ClientId: body.ClientID, AllClients: body.AllClients, }) if err != nil { writeJSON(w, http.StatusServiceUnavailable, deadzoneAPIResponse{ ClientID: body.ClientID, Error: err.Error(), }) return } writeJSON(w, http.StatusOK, deadzoneAPIResponse{ Deadzone: resp.GetDeadzone(), ClientID: resp.GetClientId(), Success: resp.GetSuccess(), SlavesUpdated: resp.GetSlavesUpdated(), }) } func serveUnicastTest(w http.ResponseWriter, r *http.Request, link *managedSerial) { var body unicastAPIRequest if err := json.NewDecoder(r.Body).Decode(&body); err != nil { writeJSON(w, http.StatusBadRequest, unicastAPIResponse{Error: "invalid JSON"}) return } if body.ClientID == 0 { writeJSON(w, http.StatusBadRequest, unicastAPIResponse{Error: "client_id required"}) return } if body.Seq == 0 { body.Seq = 1 } resp, err := link.EspnowUnicastTest(body.ClientID, body.Seq) if err != nil { writeJSON(w, http.StatusServiceUnavailable, unicastAPIResponse{Error: err.Error()}) return } writeJSON(w, http.StatusOK, unicastAPIResponse{ Success: resp.GetSuccess(), Seq: resp.GetSeq(), }) } func parseUintQuery(r *http.Request, key string, def uint32) (uint32, error) { s := r.URL.Query().Get(key) if s == "" { return def, nil } v, err := strconv.ParseUint(s, 10, 32) if err != nil { return 0, err } return uint32(v), nil } func writeJSON(w http.ResponseWriter, status int, v any) { w.Header().Set("Content-Type", "application/json") w.WriteHeader(status) _ = json.NewEncoder(w).Encode(v) }