diff --git a/internal/config/config.go b/internal/config/config.go index 81125d3..be51079 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -217,7 +217,7 @@ func Load() Config { AccessSecret: getEnvAny([]string{"CHATAPP_WEEK_STAR_ROCKETMQ_ACCESS_SECRET", "WEEK_STAR_ROCKETMQ_ACCESS_SECRET"}, ""), SecurityToken: getEnvAny([]string{"CHATAPP_WEEK_STAR_ROCKETMQ_SECURITY_TOKEN", "WEEK_STAR_ROCKETMQ_SECURITY_TOKEN"}, ""), ConsumerGroup: getEnvAny([]string{"CHATAPP_WEEK_STAR_ROCKETMQ_CONSUMER_GROUP", "WEEK_STAR_ROCKETMQ_CONSUMER_GROUP"}, "week-star-activity"), - Topic: getEnvAny([]string{"CHATAPP_WEEK_STAR_ROCKETMQ_TOPIC", "WEEK_STAR_ROCKETMQ_TOPIC"}, "GIVE_GIFTS"), + Topic: getEnvAny([]string{"CHATAPP_WEEK_STAR_ROCKETMQ_TOPIC", "WEEK_STAR_ROCKETMQ_TOPIC"}, "RC_DEFAULT_APP_ORDINARY"), Tag: getEnvAny([]string{"CHATAPP_WEEK_STAR_ROCKETMQ_TAG", "WEEK_STAR_ROCKETMQ_TAG"}, "give_gift_v3"), }, }, diff --git a/internal/service/weekstar/event.go b/internal/service/weekstar/event.go index 0fd4cb3..3d960b2 100644 --- a/internal/service/weekstar/event.go +++ b/internal/service/weekstar/event.go @@ -97,9 +97,64 @@ func (s *WeekStarService) ProcessGiftPayload(ctx context.Context, payload string if payload == "" { return nil } - var event weekStarGiftEvent - if err := json.Unmarshal([]byte(payload), &event); err != nil { + event, err := decodeWeekStarGiftEventPayload(payload, s.cfg.WeekStar.RocketMQ.Tag) + if err != nil { return err } return s.ProcessGiftEvent(ctx, event, payload) } + +func decodeWeekStarGiftEventPayload(payload string, expectedTag string) (weekStarGiftEvent, error) { + var event weekStarGiftEvent + if err := json.Unmarshal([]byte(payload), &event); err != nil { + return event, err + } + if event.hasBusinessFields() { + return event, nil + } + + var envelope weekStarMessageEventEnvelope + if err := json.Unmarshal([]byte(payload), &envelope); err != nil { + return event, err + } + if strings.TrimSpace(expectedTag) != "" && + strings.TrimSpace(envelope.Tag) != "" && + strings.TrimSpace(envelope.Tag) != strings.TrimSpace(expectedTag) { + return weekStarGiftEvent{}, nil + } + bodyPayload, ok, err := envelope.bodyPayload() + if err != nil || !ok { + return event, err + } + if err := json.Unmarshal([]byte(bodyPayload), &event); err != nil { + return event, err + } + return event, nil +} + +type weekStarMessageEventEnvelope struct { + Tag string `json:"tag"` + Body json.RawMessage `json:"body"` +} + +func (e weekStarMessageEventEnvelope) bodyPayload() (string, bool, error) { + raw := strings.TrimSpace(string(e.Body)) + if raw == "" || raw == "null" { + return "", false, nil + } + if strings.HasPrefix(raw, "\"") { + var body string + if err := json.Unmarshal(e.Body, &body); err != nil { + return "", false, err + } + body = strings.TrimSpace(body) + return body, body != "", nil + } + return raw, true, nil +} + +func (e weekStarGiftEvent) hasBusinessFields() bool { + return strings.TrimSpace(e.TrackID) != "" || + int64(e.SendUserID) > 0 || + int64(e.GiftConfig.ID) > 0 +} diff --git a/internal/service/weekstar/lifecycle_test.go b/internal/service/weekstar/lifecycle_test.go index b730436..fed170b 100644 --- a/internal/service/weekstar/lifecycle_test.go +++ b/internal/service/weekstar/lifecycle_test.go @@ -17,7 +17,7 @@ func TestStartMessageConsumerDoesNotBlockAPIStartup(t *testing.T) { AccessKey: "test-access-key", AccessSecret: "test-access-secret", ConsumerGroup: "week-star-activity-test", - Topic: "GIVE_GIFTS", + Topic: "RC_DEFAULT_APP_ORDINARY", Tag: "give_gift_v3", }, }, diff --git a/internal/service/weekstar/page_test.go b/internal/service/weekstar/page_test.go index 67a1b87..611b814 100644 --- a/internal/service/weekstar/page_test.go +++ b/internal/service/weekstar/page_test.go @@ -2,6 +2,7 @@ package weekstar import ( "context" + "encoding/json" "testing" "time" @@ -225,6 +226,93 @@ func TestProcessGiftEventCountsConfiguredNonDefaultSysOrigin(t *testing.T) { } } +func TestProcessGiftPayloadUnwrapsJavaMessageEventEnvelope(t *testing.T) { + ctx := context.Background() + service, db := newTestWeekStarService(t) + service.cfg.WeekStar.RocketMQ.Tag = "give_gift_v3" + if err := db.AutoMigrate(&model.WeekStarGiftLog{}); err != nil { + t.Fatalf("auto migrate gift log: %v", err) + } + redisServer := miniredis.RunT(t) + redisClient := redis.NewClient(&redis.Options{Addr: redisServer.Addr()}) + defer redisClient.Close() + service.repo.Redis = redisClient + + now := time.Now().In(service.location) + cycleStart, cycleEnd := service.cycleBounds(now) + configRow := model.WeekStarActivityConfig{ + ID: 104, + SysOrigin: "LIKEI", + Enabled: true, + StartAt: service.toStorageWallClock(cycleStart.Add(-time.Hour)), + EndAt: service.toStorageWallClock(cycleEnd.Add(time.Hour)), + Timezone: "Asia/Riyadh", + CreateTime: now, + UpdateTime: now, + } + if err := db.Create(&configRow).Error; err != nil { + t.Fatalf("create config: %v", err) + } + if err := db.Create(&model.WeekStarActivityGiftConfig{ + ConfigID: configRow.ID, + GiftID: 2044977670327955458, + GiftName: "Like", + GiftCandy: 100, + Sort: 1, + }).Error; err != nil { + t.Fatalf("create gift config: %v", err) + } + + body, err := json.Marshal(map[string]any{ + "trackId": "2049831533035974657", + "sysOrigin": "LIKEI", + "sendUserId": "2042274349343506434", + "quantity": 4, + "createTime": now.UnixMilli(), + "accepts": []map[string]any{ + {"acceptUserId": "2042274349343506434"}, + }, + "giftConfig": map[string]any{ + "id": "2044977670327955458", + "giftCandy": "100.00", + "giftName": "Like", + }, + }) + if err != nil { + t.Fatalf("marshal body: %v", err) + } + payload, err := json.Marshal(map[string]any{ + "consumeId": "2049831533035974657", + "topic": "RC_DEFAULT_APP_ORDINARY", + "tag": "give_gift_v3", + "body": string(body), + }) + if err != nil { + t.Fatalf("marshal payload: %v", err) + } + + if err := service.ProcessGiftPayload(ctx, string(payload)); err != nil { + t.Fatalf("ProcessGiftPayload() error = %v", err) + } + + score, err := redisClient.ZScore(ctx, service.rankRedisKey(configRow.ID, service.cycleKey(cycleStart)), "2042274349343506434").Result() + if err != nil { + t.Fatalf("ZScore() error = %v", err) + } + if score != 400 { + t.Fatalf("score = %v, want 400", score) + } + var count int64 + if err := db.Model(&model.WeekStarGiftLog{}). + Where("config_id = ? AND send_user_id = ? AND status = ?", configRow.ID, int64(2042274349343506434), weekStarGiftLogStatusSuccess). + Count(&count).Error; err != nil { + t.Fatalf("count gift log: %v", err) + } + if count != 1 { + t.Fatalf("success gift log count = %d, want 1", count) + } +} + func TestCurrentRankingReturnsDisabledWhenNoActiveConfig(t *testing.T) { service, _ := newTestWeekStarService(t)