2026-06-08 19:00:23 +08:00

88 lines
2.8 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/command"
"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 {
return nil
}
newCountry := normalizeRoomCountryCode(payload.NewCountry)
if meta.VisibleRegionID == payload.NewRegionID && newCountry == "" {
return nil
}
requestID := strings.TrimSpace(payload.RequestID)
if requestID == "" {
requestID = message.EventID
}
sentAtMS := payload.ChangedAtMS
if sentAtMS <= 0 {
sentAtMS = message.OccurredAtMS
}
updateMeta := &roomv1.RequestMeta{
AppCode: message.AppCode,
RequestId: requestID,
CommandId: message.EventID,
ActorUserId: payload.UserID,
RoomId: meta.RoomID,
SentAtMs: sentAtMS,
}
cmd := command.AdminUpdateRoom{
Base: baseFromMeta(updateMeta),
AdminName: "user-region-sync",
}
if meta.VisibleRegionID != payload.NewRegionID {
cmd.VisibleRegionID = &payload.NewRegionID
}
if newCountry != "" {
// UserRegionChanged 同时承载国家事实;即使区域未变,也要把房主国家投影写回房间列表。
cmd.OwnerCountryCode = &newCountry
}
_, err = s.applyAdminRoomMutation(ctx, cmd, cmd)
return err
}