package httpapi import ( "encoding/json" "net/http" "github.com/wangjia/pangolin/server/internal/apierr" "github.com/wangjia/pangolin/server/internal/auth" "github.com/wangjia/pangolin/server/internal/routing" ) // RoutingAPI serves /v1/me/routing: the user's configurable routing profile // (可配置分流). GET returns the stored profile or routing.Default() when the // user hasn't customized one yet; POST validates and upserts. type RoutingAPI struct { store *routing.Store } // NewRoutingAPI creates a RoutingAPI backed by the given routing.Store. func NewRoutingAPI(store *routing.Store) *RoutingAPI { return &RoutingAPI{store: store} } // GetProfile handles GET /v1/me/routing. func (a *RoutingAPI) GetProfile(w http.ResponseWriter, r *http.Request) { uid, ok := auth.UserIDFromContext(r.Context()) if !ok { apierr.WriteJSON(w, http.StatusUnauthorized, apierr.ErrUnauthorized) return } p, err := a.store.Get(r.Context(), uid) if err != nil { apierr.WriteJSON(w, http.StatusInternalServerError, apierr.ErrInternal) return } if p == nil { p = routing.Default() } writeJSON(w, http.StatusOK, p) } // SaveProfile handles POST /v1/me/routing. On validation failure it returns // 400 with every offending field reported at once (no partial save). func (a *RoutingAPI) SaveProfile(w http.ResponseWriter, r *http.Request) { uid, ok := auth.UserIDFromContext(r.Context()) if !ok { apierr.WriteJSON(w, http.StatusUnauthorized, apierr.ErrUnauthorized) return } var p routing.Profile if err := json.NewDecoder(http.MaxBytesReader(w, r.Body, 64*1024)).Decode(&p); err != nil { apierr.WriteJSON(w, http.StatusBadRequest, apierr.ErrBadRequest) return } p.Normalize() if errs := p.Validate(); len(errs) > 0 { w.Header().Set("Content-Type", "application/json; charset=utf-8") w.WriteHeader(http.StatusBadRequest) _ = json.NewEncoder(w).Encode(map[string]any{ "code": "routing_invalid", "message_zh": "规则校验未通过", "message_en": "Rule validation failed", "errors": errs, }) return } if err := a.store.Upsert(r.Context(), uid, &p); err != nil { apierr.WriteJSON(w, http.StatusInternalServerError, apierr.ErrInternal) return } writeJSON(w, http.StatusOK, &p) }