package wallet import ( "context" "github.com/bytedance/sonic" "gorm.io/gorm" walletapp "github.com/break/junhong_cmp_fiber/internal/application/wallet" "github.com/break/junhong_cmp_fiber/internal/infrastructure/messaging/outbox" "github.com/break/junhong_cmp_fiber/internal/model" "github.com/break/junhong_cmp_fiber/pkg/constants" "github.com/break/junhong_cmp_fiber/pkg/errors" ) // ReservationEventConsumer 校验预占事件与本地权威事实一致。 type ReservationEventConsumer struct { db *gorm.DB } // NewReservationEventConsumer 创建代理主钱包预占事件消费者。 func NewReservationEventConsumer(db *gorm.DB) *ReservationEventConsumer { return &ReservationEventConsumer{db: db} } // Consume 只确认具有匹配权威预占事实的事件。 func (c *ReservationEventConsumer) Consume(ctx context.Context, envelope outbox.DeliveryEnvelope) error { if c == nil || c.db == nil { return errors.New(errors.CodeInternalError, "代理主钱包预占事件消费者未配置") } if envelope.EventType != constants.OutboxEventTypeAgentMainWalletReservationChanged || envelope.PayloadVersion != constants.AgentMainWalletReservationPayloadVersionV1 { return errors.New(errors.CodeInvalidParam, "代理主钱包预占事件类型或版本不受支持") } var event walletapp.ReservationEvent if err := sonic.Unmarshal(envelope.Payload, &event); err != nil { return errors.Wrap(errors.CodeInvalidParam, err, "代理主钱包预占事件载荷无法解析") } if event.EventID != envelope.EventID || event.ReservationID == 0 || event.WalletID == 0 || event.Amount <= 0 || event.ReferenceType == "" || event.ReferenceID == 0 { return errors.New(errors.CodeInvalidParam, "代理主钱包预占事件载荷不完整") } var reservation model.AgentWalletReservation if err := c.db.WithContext(ctx).Where("id = ?", event.ReservationID).First(&reservation).Error; err != nil { if err == gorm.ErrRecordNotFound { return errors.New(errors.CodeInternalError, "代理主钱包预占事件缺少权威事实") } return errors.Wrap(errors.CodeDatabaseError, err, "查询代理主钱包预占事实失败") } if reservation.AgentWalletID != event.WalletID || reservation.Amount != event.Amount || reservation.ReferenceType != event.ReferenceType || reservation.ReferenceID != event.ReferenceID || !reservationStatusContainsEvent(reservation.Status, event.Status) { return errors.New(errors.CodeInternalError, "代理主钱包预占事件与权威事实不一致") } return nil } func reservationStatusContainsEvent(current, event int) bool { if current == event { return true } return event == constants.AgentWalletReservationStatusFrozen && (current == constants.AgentWalletReservationStatusReleased || current == constants.AgentWalletReservationStatusCompleted) }