// Package roommq defines RocketMQ payloads owned by room-service. package roommq import ( "encoding/json" "errors" "google.golang.org/protobuf/proto" roomeventsv1 "hyapp.local/api/proto/events/room/v1" ) const ( MessageTypeRoomOutboxEvent = "room_outbox_event" MessageTypeRoomTreasureOpenDue = "room_treasure_open_due" TagRoomOutboxEvent = "room_outbox_event" TagRoomTreasureOpenDue = "room_treasure_open_due" ) // RoomOutboxMessage is the MQ representation of one durable room_outbox fact. type RoomOutboxMessage struct { MessageType string `json:"message_type"` AppCode string `json:"app_code"` EventID string `json:"event_id"` EventType string `json:"event_type"` RoomID string `json:"room_id"` RoomVersion int64 `json:"room_version"` OccurredAtMS int64 `json:"occurred_at_ms"` Envelope []byte `json:"envelope"` } // RoomTreasureOpenDueMessage wakes room-service at the configured open_at_ms. type RoomTreasureOpenDueMessage struct { MessageType string `json:"message_type"` AppCode string `json:"app_code"` RoomID string `json:"room_id"` BoxID string `json:"box_id"` Level int32 `json:"level"` OpenAtMS int64 `json:"open_at_ms"` ResetAtMS int64 `json:"reset_at_ms"` CommandID string `json:"command_id"` } // EncodeRoomOutboxMessage serializes the protobuf envelope into an MQ JSON body. func EncodeRoomOutboxMessage(envelope *roomeventsv1.EventEnvelope) ([]byte, error) { if envelope == nil { return nil, errors.New("room outbox envelope is required") } envelopeBytes, err := proto.Marshal(envelope) if err != nil { return nil, err } return json.Marshal(RoomOutboxMessage{ MessageType: MessageTypeRoomOutboxEvent, AppCode: envelope.GetAppCode(), EventID: envelope.GetEventId(), EventType: envelope.GetEventType(), RoomID: envelope.GetRoomId(), RoomVersion: envelope.GetRoomVersion(), OccurredAtMS: envelope.GetOccurredAtMs(), Envelope: envelopeBytes, }) } // DecodeRoomOutboxMessage validates the MQ body and restores the protobuf fact. func DecodeRoomOutboxMessage(body []byte) (*roomeventsv1.EventEnvelope, RoomOutboxMessage, error) { var message RoomOutboxMessage if err := json.Unmarshal(body, &message); err != nil { return nil, RoomOutboxMessage{}, err } if message.MessageType != MessageTypeRoomOutboxEvent { return nil, RoomOutboxMessage{}, errors.New("unexpected room outbox message_type") } var envelope roomeventsv1.EventEnvelope if err := proto.Unmarshal(message.Envelope, &envelope); err != nil { return nil, RoomOutboxMessage{}, err } if envelope.GetEventId() == "" || envelope.GetEventType() == "" || envelope.GetRoomId() == "" { return nil, RoomOutboxMessage{}, errors.New("room outbox envelope is incomplete") } return &envelope, message, nil } // EncodeRoomTreasureOpenDueMessage serializes an open wakeup command. func EncodeRoomTreasureOpenDueMessage(message RoomTreasureOpenDueMessage) ([]byte, error) { message.MessageType = MessageTypeRoomTreasureOpenDue if message.AppCode == "" || message.RoomID == "" || message.BoxID == "" || message.Level <= 0 || message.OpenAtMS <= 0 { return nil, errors.New("room treasure open due message is incomplete") } return json.Marshal(message) } // DecodeRoomTreasureOpenDueMessage validates an open wakeup body. func DecodeRoomTreasureOpenDueMessage(body []byte) (RoomTreasureOpenDueMessage, error) { var message RoomTreasureOpenDueMessage if err := json.Unmarshal(body, &message); err != nil { return RoomTreasureOpenDueMessage{}, err } if message.MessageType != MessageTypeRoomTreasureOpenDue { return RoomTreasureOpenDueMessage{}, errors.New("unexpected room treasure message_type") } if message.AppCode == "" || message.RoomID == "" || message.BoxID == "" || message.Level <= 0 || message.OpenAtMS <= 0 { return RoomTreasureOpenDueMessage{}, errors.New("room treasure open due message is incomplete") } return message, nil }