package handler import ( "errors" "net/http" "strconv" "backend/sdk/abtest/model" "backend/sdk/abtest/service" "github.com/gin-gonic/gin" ) type Handler struct { svc *service.Service } func New(svc *service.Service) *Handler { return &Handler{svc: svc} } func ok(c *gin.Context, data interface{}) { c.JSON(http.StatusOK, model.Response{Code: 0, Msg: "ok", Data: data}) } func fail(c *gin.Context, httpCode int, msg string) { c.JSON(httpCode, model.Response{Code: -1, Msg: msg}) } func paramID(c *gin.Context, key string) (int64, bool) { v, err := strconv.ParseInt(c.Param(key), 10, 64) if err != nil { fail(c, http.StatusBadRequest, "invalid "+key) return 0, false } return v, true } func handleServiceErr(c *gin.Context, err error) { switch { case errors.Is(err, service.ErrExperimentNotFound), errors.Is(err, service.ErrVariantNotFound): fail(c, http.StatusNotFound, err.Error()) case errors.Is(err, service.ErrNotRunning), errors.Is(err, service.ErrNoVariants): fail(c, http.StatusBadRequest, err.Error()) default: fail(c, http.StatusInternalServerError, err.Error()) } } // ==================== Experiment ==================== func (h *Handler) CreateExperiment(c *gin.Context) { var req model.CreateExperimentReq if err := c.ShouldBindJSON(&req); err != nil { fail(c, http.StatusBadRequest, err.Error()) return } exp, err := h.svc.CreateExperiment(&req) if err != nil { handleServiceErr(c, err) return } ok(c, exp) } func (h *Handler) GetExperiment(c *gin.Context) { id, valid := paramID(c, "id") if !valid { return } exp, err := h.svc.GetExperiment(id) if err != nil { handleServiceErr(c, err) return } ok(c, exp) } func (h *Handler) ListExperiments(c *gin.Context) { page, _ := strconv.Atoi(c.DefaultQuery("page", "1")) pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20")) var statusPtr *int if s := c.Query("status"); s != "" { v, err := strconv.Atoi(s) if err != nil { fail(c, http.StatusBadRequest, "invalid status") return } statusPtr = &v } list, total, err := h.svc.ListExperiments(statusPtr, page, pageSize) if err != nil { handleServiceErr(c, err) return } ok(c, gin.H{"list": list, "total": total, "page": page, "page_size": pageSize}) } func (h *Handler) UpdateExperiment(c *gin.Context) { id, valid := paramID(c, "id") if !valid { return } var req model.UpdateExperimentReq if err := c.ShouldBindJSON(&req); err != nil { fail(c, http.StatusBadRequest, err.Error()) return } exp, err := h.svc.UpdateExperiment(id, &req) if err != nil { handleServiceErr(c, err) return } ok(c, exp) } func (h *Handler) DeleteExperiment(c *gin.Context) { id, valid := paramID(c, "id") if !valid { return } if err := h.svc.DeleteExperiment(id); err != nil { handleServiceErr(c, err) return } ok(c, nil) } // ==================== Variant ==================== func (h *Handler) CreateVariant(c *gin.Context) { expID, valid := paramID(c, "id") if !valid { return } var req model.CreateVariantReq if err := c.ShouldBindJSON(&req); err != nil { fail(c, http.StatusBadRequest, err.Error()) return } v, err := h.svc.CreateVariant(expID, &req) if err != nil { handleServiceErr(c, err) return } ok(c, v) } func (h *Handler) ListVariants(c *gin.Context) { expID, valid := paramID(c, "id") if !valid { return } list, err := h.svc.ListVariants(expID) if err != nil { handleServiceErr(c, err) return } ok(c, list) } func (h *Handler) UpdateVariant(c *gin.Context) { variantID, valid := paramID(c, "variantId") if !valid { return } var req model.UpdateVariantReq if err := c.ShouldBindJSON(&req); err != nil { fail(c, http.StatusBadRequest, err.Error()) return } v, err := h.svc.UpdateVariant(variantID, &req) if err != nil { handleServiceErr(c, err) return } ok(c, v) } func (h *Handler) DeleteVariant(c *gin.Context) { variantID, valid := paramID(c, "variantId") if !valid { return } if err := h.svc.DeleteVariant(variantID); err != nil { handleServiceErr(c, err) return } ok(c, nil) } // ==================== 用户分流 ==================== func (h *Handler) AssignUser(c *gin.Context) { expID, valid := paramID(c, "id") if !valid { return } var req model.AssignUserReq if err := c.ShouldBindJSON(&req); err != nil { fail(c, http.StatusBadRequest, err.Error()) return } variant, err := h.svc.AssignUser(expID, req.UserID) if err != nil { handleServiceErr(c, err) return } ok(c, variant) } // ==================== 事件追踪 ==================== func (h *Handler) TrackEvent(c *gin.Context) { expID, valid := paramID(c, "id") if !valid { return } var req model.TrackEventReq if err := c.ShouldBindJSON(&req); err != nil { fail(c, http.StatusBadRequest, err.Error()) return } if err := h.svc.TrackEvent(expID, &req); err != nil { handleServiceErr(c, err) return } ok(c, nil) } // ==================== 实验结果 ==================== func (h *Handler) GetExperimentResult(c *gin.Context) { expID, valid := paramID(c, "id") if !valid { return } result, err := h.svc.GetExperimentResult(expID) if err != nil { handleServiceErr(c, err) return } ok(c, result) } // ==================== 批量查询玩家分组 ==================== func (h *Handler) GetUserGroups(c *gin.Context) { userID := c.Param("userId") if userID == "" { fail(c, http.StatusBadRequest, "invalid userId") return } groups, err := h.svc.GetUserGroups(userID) if err != nil { handleServiceErr(c, err) return } ok(c, groups) } // ==================== 白名单管理 ==================== func (h *Handler) AddWhitelist(c *gin.Context) { expID, valid := paramID(c, "id") if !valid { return } var req model.CreateWhitelistReq if err := c.ShouldBindJSON(&req); err != nil { fail(c, http.StatusBadRequest, err.Error()) return } w, err := h.svc.AddWhitelist(expID, &req) if err != nil { handleServiceErr(c, err) return } ok(c, w) } func (h *Handler) BatchAddWhitelist(c *gin.Context) { expID, valid := paramID(c, "id") if !valid { return } var req model.BatchCreateWhitelistReq if err := c.ShouldBindJSON(&req); err != nil { fail(c, http.StatusBadRequest, err.Error()) return } list, err := h.svc.BatchAddWhitelist(expID, &req) if err != nil { handleServiceErr(c, err) return } ok(c, list) } func (h *Handler) RemoveWhitelist(c *gin.Context) { expID, valid := paramID(c, "id") if !valid { return } userID := c.Param("userId") if userID == "" { fail(c, http.StatusBadRequest, "invalid userId") return } if err := h.svc.RemoveWhitelist(expID, userID); err != nil { handleServiceErr(c, err) return } ok(c, nil) } func (h *Handler) ListWhitelist(c *gin.Context) { expID, valid := paramID(c, "id") if !valid { return } list, err := h.svc.ListWhitelist(expID) if err != nil { handleServiceErr(c, err) return } ok(c, list) }