package app import ( "encoding/json" "io" "net/http" trafficprofilespkg "selective-vpn-api/app/trafficprofiles" "strings" ) const ( trafficAppProfilesDefaultTTLSec = 0 // 0 = persistent runtime mark policy ) var trafficAppProfilesStore = trafficprofilespkg.NewStore( trafficAppProfilesPath, trafficprofilespkg.Deps{ CanonicalizeAppKey: canonicalizeAppKey, SanitizeID: sanitizeID, DefaultTTLSec: trafficAppProfilesDefaultTTLSec, }, ) func handleTrafficAppProfiles(w http.ResponseWriter, r *http.Request) { switch r.Method { case http.MethodGet: profiles := listTrafficAppProfiles() if profiles == nil { profiles = []TrafficAppProfile{} } writeJSON(w, http.StatusOK, TrafficAppProfilesResponse{Profiles: profiles, Message: "ok"}) case http.MethodPost: var body TrafficAppProfileUpsertRequest 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 } } prof, err := upsertTrafficAppProfile(body) if err != nil { writeJSON(w, http.StatusOK, TrafficAppProfilesResponse{Profiles: nil, Message: err.Error()}) return } events.push("traffic_profiles_changed", map[string]any{"id": prof.ID, "target": prof.Target}) writeJSON(w, http.StatusOK, TrafficAppProfilesResponse{Profiles: []TrafficAppProfile{prof}, Message: "saved"}) case http.MethodDelete: id := strings.TrimSpace(r.URL.Query().Get("id")) if id == "" { http.Error(w, "missing id", http.StatusBadRequest) return } ok, msg := deleteTrafficAppProfile(id) events.push("traffic_profiles_changed", map[string]any{"id": id, "deleted": ok}) writeJSON(w, http.StatusOK, map[string]any{"ok": ok, "message": msg}) default: http.Error(w, "method not allowed", http.StatusMethodNotAllowed) } }