package app import ( "encoding/json" "io" "net/http" ) func handleTransportSingBoxProfileCardPatch(w http.ResponseWriter, r *http.Request, id string) { var body SingBoxProfilePatchRequest if r.Body != nil { defer r.Body.Close() if err := json.NewDecoder(io.LimitReader(r.Body, 1<<20)).Decode(&body); err != nil && err != io.EOF { http.Error(w, "bad json", http.StatusBadRequest) return } } singBoxProfilesMu.Lock() defer singBoxProfilesMu.Unlock() st := loadSingBoxProfilesState() idx := findSingBoxProfileIndex(st.Items, id) if idx < 0 { writeJSON(w, http.StatusNotFound, SingBoxProfilesResponse{ OK: false, Code: singBoxProfileCodeNotFound, Message: "not found", }) return } cur := st.Items[idx] if body.BaseRevision > 0 && body.BaseRevision != cur.ProfileRevision { writeJSON(w, http.StatusConflict, SingBoxProfilesResponse{ OK: false, Code: singBoxProfileCodeRevisionMismatch, Message: "base_revision mismatch", Item: &cur, }) return } next, secretRes, changed, code, err := patchSingBoxProfile(cur, body) if err != nil { status := http.StatusBadRequest if code == singBoxProfileCodeSecretsFailed { status = http.StatusInternalServerError } writeJSON(w, status, SingBoxProfilesResponse{ OK: false, Code: code, Message: err.Error(), Item: &cur, }) return } if !changed { writeJSON(w, http.StatusOK, SingBoxProfilesResponse{ OK: true, Message: "noop", ActiveProfileID: st.ActiveProfileID, Item: &cur, }) return } st.Items[idx] = next ensureSingBoxProfilesActiveID(&st) st.Revision++ if err := saveSingBoxProfilesState(st); err != nil { if secretRes.Rollback != nil { secretRes.Rollback() } writeJSON(w, http.StatusInternalServerError, SingBoxProfilesResponse{ OK: false, Code: singBoxProfileCodeSaveFailed, Message: "save failed: " + err.Error(), Item: &cur, }) return } events.push("singbox_profile_saved", map[string]any{ "id": next.ID, "revision": next.ProfileRevision, }) writeJSON(w, http.StatusOK, SingBoxProfilesResponse{ OK: true, Message: "updated", ActiveProfileID: st.ActiveProfileID, Item: &next, }) }