2026-06-01 14:06:31 +08:00

174 lines
5.4 KiB
Go

package broadcast
import (
"context"
"encoding/json"
"strconv"
"strings"
"hyapp/pkg/appcode"
broadcastdomain "hyapp/services/activity-service/internal/domain/broadcast"
)
// ConsumeRedPacketWalletEvent converts one MQ-delivered wallet red-packet fact into IM outbox records.
func (s *Service) ConsumeRedPacketWalletEvent(ctx context.Context, event broadcastdomain.RedPacketWalletEvent) error {
if s == nil {
return nil
}
ctx = appcode.WithContext(ctx, event.AppCode)
switch event.EventType {
case "WalletRedPacketCreated":
return s.consumeRedPacketCreated(ctx, event)
case "WalletRedPacketClaimed":
if strings.EqualFold(event.Status, "finished") {
return s.publishRedPacketRoomEvent(ctx, event, "STATUS_CHANGED", event.CreatedAtMS)
}
case "WalletRedPacketRefunded":
return s.publishRedPacketRoomEvent(ctx, event, "STATUS_CHANGED", event.CreatedAtMS)
}
return nil
}
func (s *Service) ConsumeRedPacketCreatedEvent(ctx context.Context, event broadcastdomain.RedPacketWalletEvent) error {
if event.EventType == "" {
event.EventType = "WalletRedPacketCreated"
}
return s.ConsumeRedPacketWalletEvent(ctx, event)
}
func (s *Service) consumeRedPacketCreated(ctx context.Context, event broadcastdomain.RedPacketWalletEvent) error {
if event.RoomID == "" {
return nil
}
enriched, err := s.withRedPacketSenderProfile(ctx, event)
if err != nil {
return err
}
event = enriched
if err := s.publishRedPacketRoomEvent(ctx, event, "CREATED", event.CreatedAtMS); err != nil {
return err
}
if strings.EqualFold(event.PacketType, "delayed") && event.RegionID > 0 {
if _, err := s.PublishRegionBroadcast(ctx, PublishInput{
EventID: event.EventID + ":region_created",
BroadcastType: broadcastdomain.TypeRedPacket,
RegionID: event.RegionID,
PayloadJSON: redPacketIMPayload(event, "CREATED", "REGION"),
}); err != nil {
return err
}
}
if strings.EqualFold(event.PacketType, "delayed") && event.OpenAtMS > 0 {
_, err := s.PublishRoomBroadcast(ctx, event.RoomID, PublishInput{
EventID: event.EventID + ":open_due",
BroadcastType: broadcastdomain.TypeRedPacket,
RegionID: event.RegionID,
PayloadJSON: redPacketIMPayload(event, "OPEN_DUE", "ROOM"),
DeliverAtMS: event.OpenAtMS,
})
return err
}
return nil
}
func (s *Service) withRedPacketSenderProfile(ctx context.Context, event broadcastdomain.RedPacketWalletEvent) (broadcastdomain.RedPacketWalletEvent, error) {
if event.SenderUserID <= 0 || s == nil || s.senderProfileSource == nil {
return event, nil
}
profile, err := s.senderProfileSource.GetSenderProfile(ctx, event.SenderUserID)
if err != nil {
return event, err
}
if event.SenderAccount == "" {
event.SenderAccount = profile.Account
}
if event.SenderNickname == "" {
event.SenderNickname = profile.Nickname
}
if event.SenderAvatar == "" {
event.SenderAvatar = profile.Avatar
}
if event.RegionCode == "" {
event.RegionCode = profile.RegionCode
}
return event, nil
}
func (s *Service) publishRedPacketRoomEvent(ctx context.Context, event broadcastdomain.RedPacketWalletEvent, eventName string, fallbackDeliverAtMS int64) error {
if event.RoomID == "" {
return nil
}
_, err := s.PublishRoomBroadcast(ctx, event.RoomID, PublishInput{
EventID: event.EventID,
BroadcastType: broadcastdomain.TypeRedPacket,
RegionID: event.RegionID,
PayloadJSON: redPacketIMPayload(event, eventName, "ROOM"),
DeliverAtMS: fallbackDeliverAtMS,
})
return err
}
func redPacketIMPayload(event broadcastdomain.RedPacketWalletEvent, eventName string, scope string) string {
packetMode := "IMMEDIATE"
if strings.EqualFold(event.PacketType, "delayed") {
packetMode = "DELAYED"
}
status := strings.ToUpper(strings.TrimSpace(event.Status))
if status == "" {
status = "ACTIVE"
}
payload := map[string]any{
"type": "ROOM_RED_PACKET",
"data": map[string]any{
"event": eventName,
"scope": scope,
"packetNo": event.PacketID,
"packetId": event.PacketID,
"roomId": event.RoomID,
"regionId": event.RegionID,
"regionCode": event.RegionCode,
"packetMode": packetMode,
"senderUserId": redPacketUserIDString(event.SenderUserID),
"actualAccount": redPacketSenderAccount(event),
"userNickname": event.SenderNickname,
"userAvatar": event.SenderAvatar,
"totalAmount": event.TotalAmount,
"totalCount": event.TotalCount,
"remainAmount": event.RemainingAmount,
"remainCount": event.RemainingCount,
"status": status,
"delaySeconds": redPacketDelaySeconds(event),
"refundedAmount": event.RefundedAmount,
"claimStartTime": event.OpenAtMS,
"expireTime": event.ExpiresAtMS,
"serverTime": event.CreatedAtMS,
},
}
encoded, err := json.Marshal(payload)
if err != nil {
return `{"type":"ROOM_RED_PACKET","data":{}}`
}
return string(encoded)
}
func redPacketUserIDString(userID int64) string {
if userID <= 0 {
return ""
}
return strconv.FormatInt(userID, 10)
}
func redPacketSenderAccount(event broadcastdomain.RedPacketWalletEvent) string {
if strings.TrimSpace(event.SenderAccount) != "" {
return event.SenderAccount
}
return redPacketUserIDString(event.SenderUserID)
}
func redPacketDelaySeconds(event broadcastdomain.RedPacketWalletEvent) int64 {
if !strings.EqualFold(event.PacketType, "delayed") || event.OpenAtMS <= event.CreatedAtMS {
return 0
}
return (event.OpenAtMS - event.CreatedAtMS) / 1000
}