2026-05-16 06:18:31 +08:00

289 lines
8.7 KiB
Go

package voiceroomrocket
import (
"context"
"encoding/json"
"errors"
"strconv"
"strings"
"chatapp3-golang/internal/model"
"github.com/redis/go-redis/v9"
"gorm.io/gorm"
)
func (s *Service) notifyStatusUpdate(ctx context.Context, sysOrigin string, roomID int64, senderUserIDs ...int64) error {
data := map[string]any{
"roomId": strconv.FormatInt(roomID, 10),
}
if status, err := s.GetStatus(ctx, AuthUser{SysOrigin: sysOrigin}, roomID); err == nil && status != nil {
payload, _ := json.Marshal(status)
_ = json.Unmarshal(payload, &data)
}
senderUserID := int64(0)
if len(senderUserIDs) > 0 {
senderUserID = senderUserIDs[0]
}
if senderUserID > 0 {
data["senderUserId"] = strconv.FormatInt(senderUserID, 10)
}
if s.repo.Redis != nil {
body, _ := json.Marshal(map[string]any{
"type": imTypeStatusUpdate,
"sysOrigin": sysOrigin,
"roomId": strconv.FormatInt(roomID, 10),
"data": data,
})
streamKey := strings.TrimSpace(s.cfg.VoiceRoomRocket.BroadcastStreamKey)
if streamKey == "" {
streamKey = "voice_room:rocket:broadcast"
}
_ = s.repo.Redis.XAdd(ctx, &redis.XAddArgs{
Stream: streamKey,
Values: map[string]any{
"type": imTypeStatusUpdate,
"roomId": strconv.FormatInt(roomID, 10),
"body": string(body),
},
}).Err()
}
_ = s.notifyRegionStatusUpdate(ctx, sysOrigin, senderUserID, data)
if s.im == nil {
return nil
}
groupID := s.resolveRoomAccount(ctx, roomID)
return s.im.SendCustomGroupMessage(ctx, groupID, map[string]any{
"type": imTypeStatusUpdate,
"data": data,
})
}
func (s *Service) notifyRegionStatusUpdate(ctx context.Context, sysOrigin string, senderUserID int64, data map[string]any) error {
if s.regionBroadcast == nil || s.regionResolver == nil || s.userProfiles == nil || senderUserID <= 0 {
return nil
}
profile, err := s.userProfiles.GetUserProfile(ctx, senderUserID)
if err != nil {
return err
}
countryCode := strings.TrimSpace(profile.CountryCode)
if countryCode == "" {
return nil
}
regionCode, err := s.regionResolver.ResolveRegionCodeByCountryCode(ctx, sysOrigin, countryCode)
if err != nil {
return err
}
regionCode = strings.TrimSpace(regionCode)
if regionCode == "" {
return nil
}
body := map[string]any{
"type": imTypeStatusUpdate,
"data": data,
}
_, err = s.regionBroadcast.SendRegionCustomMessage(ctx, sysOrigin, regionCode, body)
return err
}
func (s *Service) notifyLaunch(ctx context.Context, launch model.VoiceRoomRocketLaunch) error {
triggerUser := map[string]any{}
if launch.IgniteUserID != nil && s.userProfiles != nil {
if profile, err := s.userProfiles.GetUserProfile(ctx, *launch.IgniteUserID); err == nil {
triggerUser = map[string]any{
"userId": strconv.FormatInt(*launch.IgniteUserID, 10),
"nickname": profile.UserNickname,
"avatar": profile.UserAvatar,
"account": profile.Account,
"countryCode": profile.CountryCode,
"countryName": profile.CountryName,
}
}
}
roomName := ""
if s.roomProfiles != nil {
if profiles, err := s.roomProfiles.MapRoomProfiles(ctx, []int64{launch.RoomID}); err == nil {
if profile, ok := profiles[launch.RoomID]; ok {
roomName = profile.RoomName
if strings.TrimSpace(launch.RoomAccount) == "" && strings.TrimSpace(profile.RoomAccount) != "" {
launch.RoomAccount = strings.TrimSpace(profile.RoomAccount)
}
}
}
}
durationSeconds := defaultBroadcastDurationSeconds
if snapshot, err := s.loadConfig(ctx, launch.SysOrigin); err == nil && snapshot.BroadcastDurationSeconds > 0 {
durationSeconds = snapshot.BroadcastDurationSeconds
}
triggerUserID := ""
if launch.IgniteUserID != nil {
triggerUserID = strconv.FormatInt(*launch.IgniteUserID, 10)
}
previewRocketURL := ""
rocketIconURL := ""
rocketAnimationURL := ""
if levelConfig, err := s.loadLevelConfig(ctx, launch.SysOrigin, launch.Level); err == nil {
previewRocketURL = levelConfig.PreviewRocketURL
rocketIconURL = levelConfig.RocketIconURL
rocketAnimationURL = levelConfig.RocketAnimationURL
}
body := map[string]any{
"type": imTypeLaunchBroadcast,
"data": map[string]any{
"roomId": strconv.FormatInt(launch.RoomID, 10),
"roomAccount": launch.RoomAccount,
"roomName": roomName,
"roundNo": launch.RoundNo,
"level": launch.Level,
"durationSeconds": durationSeconds,
"previewRocketUrl": previewRocketURL,
"rocketIconUrl": rocketIconURL,
"rocketAnimationUrl": rocketAnimationURL,
"triggerUser": triggerUser,
"triggerUserId": triggerUserID,
"launchNo": launch.LaunchNo,
},
}
if s.repo.Redis != nil {
payload, _ := json.Marshal(body)
streamKey := strings.TrimSpace(s.cfg.VoiceRoomRocket.BroadcastStreamKey)
if streamKey == "" {
streamKey = "voice_room:rocket:broadcast"
}
_ = s.repo.Redis.XAdd(ctx, &redis.XAddArgs{
Stream: streamKey,
Values: map[string]any{
"type": imTypeLaunchBroadcast,
"roomId": strconv.FormatInt(launch.RoomID, 10),
"launchNo": launch.LaunchNo,
"body": string(payload),
},
}).Err()
}
if s.im == nil {
return nil
}
groupID := launch.RoomAccount
if strings.TrimSpace(groupID) == "" {
groupID = s.resolveRoomAccount(ctx, launch.RoomID)
}
return s.im.SendCustomGroupMessage(ctx, groupID, body)
}
func (s *Service) notifyRewardRecords(ctx context.Context, launch model.VoiceRoomRocketLaunch, records []model.VoiceRoomRocketRewardRecord) error {
if len(records) == 0 {
return nil
}
users := make([]string, 0, len(records))
seen := map[int64]struct{}{}
for _, record := range records {
if record.UserID <= 0 {
continue
}
if _, exists := seen[record.UserID]; exists {
continue
}
seen[record.UserID] = struct{}{}
users = append(users, strconv.FormatInt(record.UserID, 10))
}
if len(users) == 0 {
return nil
}
body := map[string]any{
"type": imTypeRewardPopup,
"data": map[string]any{
"roomId": strconv.FormatInt(launch.RoomID, 10),
"launchNo": launch.LaunchNo,
"level": launch.Level,
"userIds": users,
},
}
s.publishRewardMessage(ctx, launch.RoomID, launch.LaunchNo, body)
if s.im == nil {
return nil
}
groupID := launch.RoomAccount
if strings.TrimSpace(groupID) == "" {
groupID = s.resolveRoomAccount(ctx, launch.RoomID)
}
return s.im.SendCustomGroupMessage(ctx, groupID, body)
}
func (s *Service) notifyRewardRecord(ctx context.Context, record model.VoiceRoomRocketRewardRecord) error {
profile := s.mapUserProfiles(ctx, []int64{record.UserID})[record.UserID]
body := map[string]any{
"type": imTypeRewardUser,
"data": map[string]any{
"roomId": strconv.FormatInt(record.RoomID, 10),
"launchNo": record.LaunchNo,
"level": record.Level,
"userId": strconv.FormatInt(record.UserID, 10),
"userAvatar": profile.UserAvatar,
"userNickname": profile.UserNickname,
"account": profile.Account,
"rewardScene": record.RewardScene,
"rewardType": record.RewardType,
"rewardName": record.RewardName,
"rewardAmount": record.RewardAmount,
"rewardRecordId": strconv.FormatInt(record.ID, 10),
},
}
s.publishRewardMessage(ctx, record.RoomID, record.LaunchNo, body)
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) {
if s.repo.Redis == nil {
return
}
payload, _ := json.Marshal(body)
streamKey := strings.TrimSpace(s.cfg.VoiceRoomRocket.BroadcastStreamKey)
if streamKey == "" {
streamKey = "voice_room:rocket:broadcast"
}
_ = s.repo.Redis.XAdd(ctx, &redis.XAddArgs{
Stream: streamKey,
Values: map[string]any{
"type": body["type"],
"roomId": strconv.FormatInt(roomID, 10),
"launchNo": launchNo,
"body": string(payload),
},
}).Err()
}
func (s *Service) resolveRoomAccount(ctx context.Context, roomID int64) string {
if roomID <= 0 {
return ""
}
if s.roomProfiles != nil {
profiles, err := s.roomProfiles.MapRoomProfiles(ctx, []int64{roomID})
if err == nil {
if profile, ok := profiles[roomID]; ok && strings.TrimSpace(profile.RoomAccount) != "" {
return strings.TrimSpace(profile.RoomAccount)
}
for _, profile := range profiles {
if int64(profile.ID) == roomID && strings.TrimSpace(profile.RoomAccount) != "" {
return strings.TrimSpace(profile.RoomAccount)
}
}
}
}
var room model.RoomLiveBroadcastVIP
err := s.repo.DB.WithContext(ctx).
Where("room_id = ? OR id = ?", roomID, roomID).
Order("update_time DESC").
First(&room).Error
if err == nil && room.RoomAccount > 0 {
return strconv.FormatInt(room.RoomAccount, 10)
}
if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) {
return strconv.FormatInt(roomID, 10)
}
return strconv.FormatInt(roomID, 10)
}