package main import ( "encoding/json" "fmt" "net/http" "powerpod/gotool/pb" ) type tapConfigFields struct { TapSensThres uint32 `json:"tap_sens_thres"` MaxGestDur uint32 `json:"max_gest_dur"` TapShockDur uint32 `json:"tap_shock_dur"` QuiteTimeAfterGest uint32 `json:"quite_time_after_gest"` WaitForTimeout uint32 `json:"wait_for_timeout"` AxisSel uint32 `json:"axis_sel"` EnableSingle bool `json:"enable_single"` EnableDouble bool `json:"enable_double"` EnableTriple bool `json:"enable_triple"` } type tapConfigAPIResponse struct { tapConfigFields ClientID uint32 `json:"client_id"` Success bool `json:"success"` SlavesUpdated uint32 `json:"slaves_updated"` Error string `json:"error,omitempty"` } type tapConfigAPIRequest struct { Write bool `json:"write"` ClientID uint32 `json:"client_id"` AllClients bool `json:"all_clients"` // SlavesOnly: with all_clients, push to ESP-NOW slaves only (master BMA456 unchanged). SlavesOnly bool `json:"slaves_only"` tapConfigFields } func tapConfigFieldsFromPB(r *pb.TapConfigResponse) tapConfigFields { return tapConfigFields{ TapSensThres: r.GetTapSensThres(), MaxGestDur: r.GetMaxGestDur(), TapShockDur: r.GetTapShockDur(), QuiteTimeAfterGest: r.GetQuiteTimeAfterGest(), WaitForTimeout: r.GetWaitForTimeout(), AxisSel: r.GetAxisSel(), EnableSingle: r.GetEnableSingle(), EnableDouble: r.GetEnableDouble(), EnableTriple: r.GetEnableTriple(), } } func (f tapConfigFields) toPBRequest(write bool, clientID uint32, all bool) *pb.TapConfigRequest { return &pb.TapConfigRequest{ Write: write, ClientId: clientID, AllClients: all, TapSensThres: f.TapSensThres, MaxGestDur: f.MaxGestDur, TapShockDur: f.TapShockDur, QuiteTimeAfterGest: f.QuiteTimeAfterGest, WaitForTimeout: f.WaitForTimeout, AxisSel: f.AxisSel, EnableSingle: f.EnableSingle, EnableDouble: f.EnableDouble, EnableTriple: f.EnableTriple, } } func mountTapConfigAPI(mux *http.ServeMux, link *managedSerial) { mux.HandleFunc("/api/tap-config", func(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: serveTapConfigGet(w, r, link) case http.MethodPost: serveTapConfigPost(w, r, link) default: http.Error(w, "method not allowed", http.StatusMethodNotAllowed) } }) } func serveTapConfigGet(w http.ResponseWriter, r *http.Request, link *managedSerial) { clientID, err := parseUintQuery(r, "client_id", 0) if err != nil { writeJSON(w, http.StatusBadRequest, tapConfigAPIResponse{Error: err.Error()}) return } resp, err := link.TapConfig(&pb.TapConfigRequest{ Write: false, ClientId: clientID, }) if err != nil { writeJSON(w, http.StatusServiceUnavailable, tapConfigAPIResponse{ ClientID: clientID, Error: err.Error(), }) return } out := tapConfigAPIResponse{ tapConfigFields: tapConfigFieldsFromPB(resp), ClientID: resp.GetClientId(), Success: resp.GetSuccess(), } writeJSON(w, http.StatusOK, out) } func serveTapConfigPost(w http.ResponseWriter, r *http.Request, link *managedSerial) { var body tapConfigAPIRequest if err := json.NewDecoder(r.Body).Decode(&body); err != nil { writeJSON(w, http.StatusBadRequest, tapConfigAPIResponse{Error: "invalid JSON"}) return } if body.AllClients && body.SlavesOnly { updated, err := applyTapConfigToSlaves(link, body.tapConfigFields) if err != nil { writeJSON(w, http.StatusServiceUnavailable, tapConfigAPIResponse{ tapConfigFields: body.tapConfigFields, Error: err.Error(), }) return } writeJSON(w, http.StatusOK, tapConfigAPIResponse{ tapConfigFields: body.tapConfigFields, Success: updated > 0, SlavesUpdated: updated, }) return } resp, err := link.TapConfig(body.tapConfigFields.toPBRequest(true, body.ClientID, body.AllClients)) if err != nil { writeJSON(w, http.StatusServiceUnavailable, tapConfigAPIResponse{ ClientID: body.ClientID, tapConfigFields: body.tapConfigFields, Error: err.Error(), }) return } writeJSON(w, http.StatusOK, tapConfigAPIResponse{ tapConfigFields: tapConfigFieldsFromPB(resp), ClientID: resp.GetClientId(), Success: resp.GetSuccess(), SlavesUpdated: resp.GetSlavesUpdated(), }) } func applyTapConfigToSlaves(link *managedSerial, fields tapConfigFields) (uint32, error) { clients, err := link.listClients() if err != nil { return 0, err } var updated uint32 for _, c := range clients { resp, err := link.TapConfig(fields.toPBRequest(true, c.GetId(), false)) if err != nil { continue } if resp.GetSuccess() { updated++ } } if len(clients) == 0 { return 0, fmt.Errorf("no slaves registered") } if updated == 0 { return 0, fmt.Errorf("tap config not applied to any slave") } return updated, nil }