Some checks failed
Build docker and publish / linux (1.24.5) (push) Failing after 41s
新增随机种子生成与验证逻辑,包括: 1. 添加随机承诺生成接口 2. 实现抽奖执行与验证流程 3. 新增批量用户创建与删除功能 4. 添加抽奖收据记录表 5. 完善配置管理与错误码 新增测试用例验证随机算法正确性
153 lines
4.3 KiB
Go
153 lines
4.3 KiB
Go
package admin
|
|
|
|
import (
|
|
"encoding/hex"
|
|
"encoding/json"
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"bindbox-game/internal/code"
|
|
"bindbox-game/internal/pkg/core"
|
|
"bindbox-game/internal/pkg/validation"
|
|
"bindbox-game/internal/repository/mysql/model"
|
|
)
|
|
|
|
type batchDrawRequest struct {
|
|
UserIDs []int64 `json:"user_ids" binding:"required,min=1,max=1000,dive,min=1"`
|
|
}
|
|
|
|
type batchDrawResponse struct {
|
|
Draws []drawResultItem `json:"draws"`
|
|
}
|
|
|
|
type drawResultItem struct {
|
|
UserID int64 `json:"user_id"`
|
|
DrawID int64 `json:"draw_id"`
|
|
RewardID int64 `json:"reward_id"`
|
|
RewardName string `json:"reward_name"`
|
|
IsWinner bool `json:"is_winner"`
|
|
Receipt interface{} `json:"receipt"`
|
|
}
|
|
|
|
func (h *handler) BatchDrawForUsers() core.HandlerFunc {
|
|
return func(ctx core.Context) {
|
|
issueIDStr := ctx.Param("issue_id")
|
|
if issueIDStr == "" {
|
|
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, "未传递期ID"))
|
|
return
|
|
}
|
|
if _, err := strconv.ParseInt(issueIDStr, 10, 64); err != nil {
|
|
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
|
|
return
|
|
}
|
|
issueID, _ := strconv.ParseInt(issueIDStr, 10, 64)
|
|
var req batchDrawRequest
|
|
if err := ctx.ShouldBindJSON(&req); err != nil {
|
|
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ParamBindError, validation.Error(err)))
|
|
return
|
|
}
|
|
rewards, err := h.activity.ListIssueRewards(ctx.RequestContext(), issueID)
|
|
if err != nil {
|
|
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ExecuteDrawError, err.Error()))
|
|
return
|
|
}
|
|
rewardMap := make(map[int64]string, len(rewards))
|
|
for _, r := range rewards {
|
|
rewardMap[r.ID] = r.Name
|
|
}
|
|
|
|
// 开始事务处理
|
|
tx := h.writeDB.Begin()
|
|
if tx.Error != nil {
|
|
ctx.AbortWithError(core.Error(http.StatusInternalServerError, code.ExecuteDrawError, "启动事务失败"))
|
|
return
|
|
}
|
|
defer func() {
|
|
if r := recover(); r != nil {
|
|
tx.Rollback()
|
|
panic(r)
|
|
}
|
|
}()
|
|
|
|
draws := make([]drawResultItem, 0, len(req.UserIDs))
|
|
for _, uid := range req.UserIDs {
|
|
// 执行抽奖
|
|
rec, err := h.activity.ExecuteDraw(ctx.RequestContext(), issueID)
|
|
if err != nil {
|
|
tx.Rollback()
|
|
ctx.AbortWithError(core.Error(http.StatusBadRequest, code.ExecuteDrawError, err.Error()))
|
|
return
|
|
}
|
|
|
|
// 创建抽奖日志
|
|
isWinner := int32(0)
|
|
if rec.SelectedItemId > 0 {
|
|
isWinner = 1
|
|
}
|
|
|
|
drawLog := &model.ActivityDrawLogs{
|
|
UserID: uid,
|
|
IssueID: issueID,
|
|
RewardID: rec.SelectedItemId,
|
|
IsWinner: isWinner,
|
|
Level: 1, // 默认等级
|
|
}
|
|
|
|
if err := tx.ActivityDrawLogs.Create(drawLog); err != nil {
|
|
tx.Rollback()
|
|
ctx.AbortWithError(core.Error(http.StatusInternalServerError, code.ExecuteDrawError, "创建抽奖日志失败"))
|
|
return
|
|
}
|
|
|
|
// 保存抽奖收据
|
|
itemsSnapshot, _ := json.Marshal(rec.Items)
|
|
receipt := &model.ActivityDrawReceipts{
|
|
DrawLogID: drawLog.ID,
|
|
AlgoVersion: rec.AlgoVersion,
|
|
RoundID: rec.RoundId,
|
|
DrawID: rec.DrawId,
|
|
ClientID: rec.ClientId,
|
|
Timestamp: rec.Timestamp,
|
|
ServerSeedHash: hex.EncodeToString(rec.ServerSeedHash),
|
|
ServerSubSeed: hex.EncodeToString(rec.ServerSubSeed),
|
|
ClientSeed: hex.EncodeToString(rec.ClientSeed),
|
|
Nonce: int64(rec.Nonce),
|
|
ItemsRoot: hex.EncodeToString(rec.ItemsRoot),
|
|
WeightsTotal: int64(rec.WeightsTotal),
|
|
SelectedIndex: int32(rec.SelectedIndex),
|
|
RandProof: hex.EncodeToString(rec.RandProof),
|
|
Signature: "", // 可以后续添加签名
|
|
ItemsSnapshot: string(itemsSnapshot),
|
|
}
|
|
|
|
if err := tx.ActivityDrawReceipts.Create(receipt); err != nil {
|
|
tx.Rollback()
|
|
ctx.AbortWithError(core.Error(http.StatusInternalServerError, code.ExecuteDrawError, "保存抽奖收据失败"))
|
|
return
|
|
}
|
|
|
|
name := ""
|
|
if rec.SelectedItemId > 0 {
|
|
name = rewardMap[rec.SelectedItemId]
|
|
}
|
|
draws = append(draws, drawResultItem{
|
|
UserID: uid,
|
|
DrawID: rec.DrawId,
|
|
RewardID: rec.SelectedItemId,
|
|
RewardName: name,
|
|
IsWinner: rec.SelectedItemId > 0,
|
|
Receipt: rec,
|
|
})
|
|
}
|
|
|
|
// 提交事务
|
|
if err := tx.Commit(); err != nil {
|
|
tx.Rollback()
|
|
ctx.AbortWithError(core.Error(http.StatusInternalServerError, code.ExecuteDrawError, "提交事务失败"))
|
|
return
|
|
}
|
|
|
|
ctx.Payload(&batchDrawResponse{Draws: draws})
|
|
}
|
|
}
|