diff --git a/internal/service/voiceroomrocket/config_test.go b/internal/service/voiceroomrocket/config_test.go index abd19b1..784bf95 100644 --- a/internal/service/voiceroomrocket/config_test.go +++ b/internal/service/voiceroomrocket/config_test.go @@ -47,6 +47,12 @@ func TestGetStatusReturnsRocketResourcesToApp(t *testing.T) { service, _ := newTestService(t) ctx := context.Background() + if _, err := service.SaveAdminConfig(ctx, SaveConfigRequest{ + SysOrigin: "LIKEI", + Enabled: true, + }); err != nil { + t.Fatalf("SaveAdminConfig error = %v", err) + } _, err := service.SaveLevelConfigs(ctx, SaveLevelConfigsRequest{ SysOrigin: "LIKEI", Levels: []LevelConfigPayload{ diff --git a/internal/service/voiceroomrocket/event_test.go b/internal/service/voiceroomrocket/event_test.go index f0a18dc..39917b1 100644 --- a/internal/service/voiceroomrocket/event_test.go +++ b/internal/service/voiceroomrocket/event_test.go @@ -639,6 +639,53 @@ func TestNotifyLaunchPublishesIMAndRedisStream(t *testing.T) { } } +func TestNotifyRewardRecordPublishesIMAndRedisStream(t *testing.T) { + gateway := newFakeRocketGateway() + service, _, rdb, mr := newTestServiceWithRedis(t, gateway) + defer mr.Close() + fakeIM := &fakeRocketIM{} + service.SetIMGateway(fakeIM) + + record := model.VoiceRoomRocketRewardRecord{ + ID: 9901, + LaunchNo: "VRR-reward", + RoomID: 9001, + UserID: 1001, + Level: 2, + RewardScene: rewardSceneTop1, + RewardType: rewardTypeGold, + RewardName: "gold", + RewardAmount: 100, + } + if err := service.notifyRewardRecord(context.Background(), record); err != nil { + t.Fatalf("notifyRewardRecord() error = %v", err) + } + if len(fakeIM.messages) != 1 || fakeIM.messages[0].groupID != "9001" { + t.Fatalf("im messages = %+v", fakeIM.messages) + } + body, ok := fakeIM.messages[0].body.(map[string]any) + if !ok { + t.Fatalf("im body = %#v", fakeIM.messages[0].body) + } + if body["type"] != imTypeRewardUser { + t.Fatalf("im type = %#v, want %s", body["type"], imTypeRewardUser) + } + data, ok := body["data"].(map[string]any) + if !ok { + t.Fatalf("im data = %#v", body["data"]) + } + if data["userId"] != "1001" || data["rewardRecordId"] != "9901" { + t.Fatalf("im data = %#v", data) + } + count, err := rdb.XLen(context.Background(), "voice_room:rocket:broadcast").Result() + if err != nil { + t.Fatalf("xlen broadcast: %v", err) + } + if count != 1 { + t.Fatalf("broadcast stream count = %d, want 1", count) + } +} + func TestStatusUpdatePublishesRegionIM(t *testing.T) { gateway := newFakeRocketGateway() service, db, _, mr := newTestServiceWithRedis(t, gateway) diff --git a/internal/service/voiceroomrocket/notify.go b/internal/service/voiceroomrocket/notify.go index bf92a7f..275bb35 100644 --- a/internal/service/voiceroomrocket/notify.go +++ b/internal/service/voiceroomrocket/notify.go @@ -226,7 +226,10 @@ func (s *Service) notifyRewardRecord(ctx context.Context, record model.VoiceRoom }, } s.publishRewardMessage(ctx, record.RoomID, record.LaunchNo, body) - return nil + if s.im == nil { + return nil + } + return s.im.SendCustomGroupMessage(ctx, s.resolveRoomAccount(ctx, record.RoomID), body) } func (s *Service) publishRewardMessage(ctx context.Context, roomID int64, launchNo string, body map[string]any) { diff --git a/internal/service/voiceroomrocket/status.go b/internal/service/voiceroomrocket/status.go index 9a2e319..2bdaec8 100644 --- a/internal/service/voiceroomrocket/status.go +++ b/internal/service/voiceroomrocket/status.go @@ -22,6 +22,9 @@ func (s *Service) GetStatus(ctx context.Context, user AuthUser, roomID int64) (* if err != nil { return nil, err } + if !snapshot.Enabled { + return disabledStatusResponse(snapshot, roomID), nil + } local := resolveLocation(snapshot.Timezone) now := time.Now().In(local) status, err := s.loadOrInitStatus(ctx, nil, snapshot.SysOrigin, roomID, dayKey(now, local), now) @@ -46,6 +49,10 @@ func (s *Service) GetStatus(ctx context.Context, user AuthUser, roomID int64) (* kings, _ := s.topKingRecords(ctx, snapshot.SysOrigin, roomID, status.DayKey, status.RoundNo, status.CurrentLevel, 3) countdownSeconds := s.launchCountdownSeconds(ctx, status, time.Now()) return &StatusResponse{ + Configured: snapshot.Configured, + SysOrigin: snapshot.SysOrigin, + Enabled: snapshot.Enabled, + Timezone: snapshot.Timezone, RoomID: roomID, DayKey: status.DayKey, RoundNo: status.RoundNo, @@ -67,6 +74,20 @@ func (s *Service) GetStatus(ctx context.Context, user AuthUser, roomID int64) (* }, nil } +func disabledStatusResponse(snapshot configSnapshot, roomID int64) *StatusResponse { + return &StatusResponse{ + Configured: snapshot.Configured, + SysOrigin: snapshot.SysOrigin, + Enabled: false, + Timezone: snapshot.Timezone, + RoomID: roomID, + Status: statusDisabled, + Levels: []LevelConfigPayload{}, + RewardPreview: RewardPreviewResponse{}, + RocketKings: []KingRecord{}, + } +} + func (s *Service) loadOrInitStatus(ctx context.Context, tx *gorm.DB, sysOrigin string, roomID int64, day string, now time.Time) (model.VoiceRoomRocketStatus, error) { db := s.repo.DB.WithContext(ctx) if tx != nil { diff --git a/internal/service/voiceroomrocket/status_test.go b/internal/service/voiceroomrocket/status_test.go new file mode 100644 index 0000000..c31b98d --- /dev/null +++ b/internal/service/voiceroomrocket/status_test.go @@ -0,0 +1,55 @@ +package voiceroomrocket + +import ( + "context" + "testing" + "time" + + "chatapp3-golang/internal/model" +) + +func TestGetStatusDisabledDoesNotInitRoomStatus(t *testing.T) { + service, db := newTestService(t) + ctx := context.Background() + now := time.Now() + if err := db.Create(&model.VoiceRoomRocketConfig{ + ID: 1, + SysOrigin: "LIKEI", + Enabled: false, + Timezone: "Asia/Riyadh", + MaxLevel: 6, + RankingTopLimit: 100, + RewardRecordKeepDays: 35, + BroadcastDurationSeconds: 7, + InRoomRewardDelaySeconds: 10, + CreateTime: now, + UpdateTime: now, + }).Error; err != nil { + t.Fatalf("create config: %v", err) + } + + resp, err := service.GetStatus(ctx, AuthUser{SysOrigin: "LIKEI"}, 9001) + if err != nil { + t.Fatalf("GetStatus error = %v", err) + } + if resp.Enabled { + t.Fatalf("enabled = true, want false") + } + if !resp.Configured { + t.Fatalf("configured = false, want true") + } + if resp.Status != statusDisabled { + t.Fatalf("status = %q, want %q", resp.Status, statusDisabled) + } + if len(resp.Levels) != 0 { + t.Fatalf("levels len = %d, want 0", len(resp.Levels)) + } + + var statusCount int64 + if err := db.Model(&model.VoiceRoomRocketStatus{}).Count(&statusCount).Error; err != nil { + t.Fatalf("count status: %v", err) + } + if statusCount != 0 { + t.Fatalf("status rows = %d, want 0", statusCount) + } +} diff --git a/internal/service/voiceroomrocket/types.go b/internal/service/voiceroomrocket/types.go index 1ff622d..189f692 100644 --- a/internal/service/voiceroomrocket/types.go +++ b/internal/service/voiceroomrocket/types.go @@ -35,6 +35,7 @@ const ( statusCharging = "CHARGING" statusLaunching = "LAUNCHING" + statusDisabled = "DISABLED" levelRoundStatusCharging = "CHARGING" levelRoundStatusReached = "REACHED" @@ -407,6 +408,10 @@ type SaveRewardConfigsRequest struct { } type StatusResponse struct { + Configured bool `json:"configured"` + SysOrigin string `json:"sysOrigin"` + Enabled bool `json:"enabled"` + Timezone string `json:"timezone"` RoomID int64 `json:"roomId,string"` DayKey string `json:"dayKey"` RoundNo int `json:"roundNo"`