75 lines
2.3 KiB
Go

package service
import (
"context"
"encoding/json"
"errors"
"strings"
roomv1 "hyapp.local/api/proto/room/v1"
"hyapp/pkg/appcode"
"hyapp/pkg/usermq"
"hyapp/services/room-service/internal/room/state"
)
type userRegionChangedPayload struct {
UserID int64 `json:"user_id"`
OldCountry string `json:"old_country"`
NewCountry string `json:"new_country"`
OldRegionID int64 `json:"old_region_id"`
NewRegionID int64 `json:"new_region_id"`
Source string `json:"source"`
RequestID string `json:"request_id"`
ChangedAtMS int64 `json:"changed_at_ms"`
}
// HandleUserOutboxMessage 只消费 user-service 的当前区域迁移事实;历史注册、邀请或麦位事实不是 room-service 的状态输入。
func (s *Service) HandleUserOutboxMessage(ctx context.Context, message usermq.UserOutboxMessage) error {
if strings.TrimSpace(message.EventType) != "UserRegionChanged" {
return nil
}
var payload userRegionChangedPayload
if err := json.Unmarshal([]byte(message.PayloadJSON), &payload); err != nil {
return err
}
if payload.UserID <= 0 || payload.NewRegionID < 0 {
// user_outbox 已经是 owner service 提交后的事实;结构错误交给 MQ 重试和告警,不在本地猜测修复。
return errors.New("user region changed payload is invalid")
}
if payload.UserID != message.AggregateID {
// aggregate_id 是 outbox 幂等和审计键,必须和 payload 指向同一个用户,避免错误事件迁移别人的房间。
return errors.New("user region changed aggregate_id mismatch")
}
ctx = appcode.WithContext(ctx, message.AppCode)
meta, exists, err := s.repository.GetRoomMetaByOwner(ctx, payload.UserID)
if err != nil {
return err
}
if !exists || meta.Status == state.RoomStatusDeleted || meta.VisibleRegionID == payload.NewRegionID {
return nil
}
requestID := strings.TrimSpace(payload.RequestID)
if requestID == "" {
requestID = message.EventID
}
sentAtMS := payload.ChangedAtMS
if sentAtMS <= 0 {
sentAtMS = message.OccurredAtMS
}
_, err = s.AdminUpdateRoom(ctx, &roomv1.AdminUpdateRoomRequest{
Meta: &roomv1.RequestMeta{
AppCode: message.AppCode,
RequestId: requestID,
CommandId: message.EventID,
ActorUserId: payload.UserID,
RoomId: meta.RoomID,
SentAtMs: sentAtMS,
},
VisibleRegionId: &payload.NewRegionID,
AdminName: "user-region-sync",
})
return err
}