184 lines
6.0 KiB
Go
184 lines
6.0 KiB
Go
package integration
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
|
||
"google.golang.org/protobuf/proto"
|
||
roomeventsv1 "hyapp/api/proto/events/room/v1"
|
||
"hyapp/pkg/tencentim"
|
||
)
|
||
|
||
// TencentIMPublisher 是 room-service 到腾讯云 IM 的生产路径发布器。
|
||
type TencentIMPublisher struct {
|
||
// client 持有腾讯云 IM REST API、UserSig 和管理员账号配置。
|
||
client *tencentim.RESTClient
|
||
}
|
||
|
||
// NewTencentIMPublisher 创建腾讯云 IM 房间消息发布器。
|
||
func NewTencentIMPublisher(client *tencentim.RESTClient) *TencentIMPublisher {
|
||
return &TencentIMPublisher{client: client}
|
||
}
|
||
|
||
// EnsureRoomGroup 确保每个 Room Cell 都有对应腾讯云 IM 群组。
|
||
func (p *TencentIMPublisher) EnsureRoomGroup(ctx context.Context, roomID string, ownerUserID int64) error {
|
||
if p == nil || p.client == nil {
|
||
// 未启用腾讯云 IM 时保持无副作用,便于本地测试只跑 room-service。
|
||
return nil
|
||
}
|
||
|
||
return p.client.EnsureRoomGroup(ctx, roomID, ownerUserID)
|
||
}
|
||
|
||
// PublishRoomEvent 把房间系统事件发送到腾讯云 IM 群。
|
||
func (p *TencentIMPublisher) PublishRoomEvent(ctx context.Context, event tencentim.RoomEvent) error {
|
||
if p == nil || p.client == nil {
|
||
// 未启用腾讯云 IM 时不阻断房间状态提交。
|
||
return nil
|
||
}
|
||
|
||
return p.client.PublishRoomEvent(ctx, event)
|
||
}
|
||
|
||
// PublishOutboxEvent 补偿投递 room_outbox 中可转成房间系统消息的事件。
|
||
func (p *TencentIMPublisher) PublishOutboxEvent(ctx context.Context, envelope *roomeventsv1.EventEnvelope) error {
|
||
if p == nil || p.client == nil || envelope == nil {
|
||
return nil
|
||
}
|
||
|
||
event, publish, err := roomEventFromEnvelope(envelope)
|
||
if err != nil || !publish {
|
||
return err
|
||
}
|
||
|
||
return p.client.PublishRoomEvent(ctx, event)
|
||
}
|
||
|
||
// noopRoomEventPublisher 是本地和测试路径的房间消息发布占位实现。
|
||
type noopRoomEventPublisher struct{}
|
||
|
||
// NewNoopRoomEventPublisher 返回无外部副作用的房间消息发布器。
|
||
func NewNoopRoomEventPublisher() RoomEventPublisher {
|
||
return noopRoomEventPublisher{}
|
||
}
|
||
|
||
// EnsureRoomGroup 在 noop 实现中不做外部调用。
|
||
func (noopRoomEventPublisher) EnsureRoomGroup(context.Context, string, int64) error {
|
||
return nil
|
||
}
|
||
|
||
// PublishRoomEvent 在 noop 实现中不做外部调用。
|
||
func (noopRoomEventPublisher) PublishRoomEvent(context.Context, tencentim.RoomEvent) error {
|
||
return nil
|
||
}
|
||
|
||
// noopOutboxPublisher 是首版异步 outbox 消费占位实现。
|
||
type noopOutboxPublisher struct{}
|
||
|
||
// NewNoopOutboxPublisher 返回一个占位 outbox 发布器。
|
||
// 当前版本保留 outbox 表和 worker 语义,activity/audit 投递后续替换该实现。
|
||
func NewNoopOutboxPublisher() OutboxPublisher {
|
||
return noopOutboxPublisher{}
|
||
}
|
||
|
||
// PublishOutboxEvent 直接吞掉 outbox 事件。
|
||
func (noopOutboxPublisher) PublishOutboxEvent(context.Context, *roomeventsv1.EventEnvelope) error {
|
||
// 腾讯云 IM 同步广播不依赖该 outbox;activity/audit 仍会复用同一事件源。
|
||
return nil
|
||
}
|
||
|
||
func roomEventFromEnvelope(envelope *roomeventsv1.EventEnvelope) (tencentim.RoomEvent, bool, error) {
|
||
base := tencentim.RoomEvent{
|
||
EventID: envelope.GetEventId(),
|
||
RoomID: envelope.GetRoomId(),
|
||
EventType: eventTypeForClient(envelope.GetEventType()),
|
||
RoomVersion: envelope.GetRoomVersion(),
|
||
}
|
||
|
||
switch envelope.GetEventType() {
|
||
case "RoomUserJoined":
|
||
var body roomeventsv1.RoomUserJoined
|
||
if err := proto.Unmarshal(envelope.GetBody(), &body); err != nil {
|
||
return tencentim.RoomEvent{}, false, err
|
||
}
|
||
base.ActorUserID = body.GetUserId()
|
||
base.TargetUserID = body.GetUserId()
|
||
base.Attributes = map[string]string{"role": body.GetRole()}
|
||
return base, true, nil
|
||
case "RoomUserLeft":
|
||
var body roomeventsv1.RoomUserLeft
|
||
if err := proto.Unmarshal(envelope.GetBody(), &body); err != nil {
|
||
return tencentim.RoomEvent{}, false, err
|
||
}
|
||
base.ActorUserID = body.GetUserId()
|
||
base.TargetUserID = body.GetUserId()
|
||
return base, true, nil
|
||
case "RoomMicChanged":
|
||
var body roomeventsv1.RoomMicChanged
|
||
if err := proto.Unmarshal(envelope.GetBody(), &body); err != nil {
|
||
return tencentim.RoomEvent{}, false, err
|
||
}
|
||
base.ActorUserID = body.GetActorUserId()
|
||
base.TargetUserID = body.GetTargetUserId()
|
||
base.SeatNo = body.GetToSeat()
|
||
if base.SeatNo == 0 {
|
||
base.SeatNo = body.GetFromSeat()
|
||
}
|
||
base.Attributes = map[string]string{"action": body.GetAction()}
|
||
return base, true, nil
|
||
case "RoomUserMuted":
|
||
var body roomeventsv1.RoomUserMuted
|
||
if err := proto.Unmarshal(envelope.GetBody(), &body); err != nil {
|
||
return tencentim.RoomEvent{}, false, err
|
||
}
|
||
base.ActorUserID = body.GetActorUserId()
|
||
base.TargetUserID = body.GetTargetUserId()
|
||
base.Attributes = map[string]string{"muted": fmt.Sprintf("%t", body.GetMuted())}
|
||
return base, true, nil
|
||
case "RoomUserKicked":
|
||
var body roomeventsv1.RoomUserKicked
|
||
if err := proto.Unmarshal(envelope.GetBody(), &body); err != nil {
|
||
return tencentim.RoomEvent{}, false, err
|
||
}
|
||
base.ActorUserID = body.GetActorUserId()
|
||
base.TargetUserID = body.GetTargetUserId()
|
||
return base, true, nil
|
||
case "RoomGiftSent":
|
||
var body roomeventsv1.RoomGiftSent
|
||
if err := proto.Unmarshal(envelope.GetBody(), &body); err != nil {
|
||
return tencentim.RoomEvent{}, false, err
|
||
}
|
||
base.ActorUserID = body.GetSenderUserId()
|
||
base.TargetUserID = body.GetTargetUserId()
|
||
base.GiftValue = body.GetGiftValue()
|
||
base.Attributes = map[string]string{
|
||
"gift_id": body.GetGiftId(),
|
||
"gift_count": fmt.Sprintf("%d", body.GetGiftCount()),
|
||
"billing_receipt_id": body.GetBillingReceiptId(),
|
||
}
|
||
return base, true, nil
|
||
default:
|
||
// RoomCreated/HeatChanged/RankChanged 不单独推客户端,避免一条命令产生多条系统消息。
|
||
return tencentim.RoomEvent{}, false, nil
|
||
}
|
||
}
|
||
|
||
func eventTypeForClient(eventType string) string {
|
||
switch eventType {
|
||
case "RoomUserJoined":
|
||
return "room_user_joined"
|
||
case "RoomUserLeft":
|
||
return "room_user_left"
|
||
case "RoomMicChanged":
|
||
return "room_mic_changed"
|
||
case "RoomUserMuted":
|
||
return "room_user_muted"
|
||
case "RoomUserKicked":
|
||
return "room_user_kicked"
|
||
case "RoomGiftSent":
|
||
return "room_gift_sent"
|
||
default:
|
||
return eventType
|
||
}
|
||
}
|