196 lines
6.0 KiB
Go
196 lines
6.0 KiB
Go
// Package command 定义 room-service 可持久化、可回放的房间命令模型。
|
||
package command
|
||
|
||
import "encoding/json"
|
||
|
||
// Command 统一表达可写入 command log 的房间命令。
|
||
type Command interface {
|
||
// ID 返回命令幂等键,通常来自 gateway 的 RequestMeta.command_id。
|
||
ID() string
|
||
// RoomID 返回命令所属房间,Room Cell 路由和 command log 分区依赖它。
|
||
RoomID() string
|
||
// ActorUserID 返回命令操作者,不能由具体命令字段重复推导。
|
||
ActorUserID() int64
|
||
// Type 返回稳定命令类型,持久化和恢复反序列化都依赖该字符串。
|
||
Type() string
|
||
}
|
||
|
||
// Base 承载所有房间命令都共享的元信息。
|
||
type Base struct {
|
||
// RequestID 是入口请求 ID,用于追踪一次外部调用。
|
||
RequestID string `json:"request_id"`
|
||
// CommandID 是幂等主键,重复命令必须返回已提交状态而不是重复变更房间。
|
||
CommandID string `json:"command_id"`
|
||
// ActorID 是操作者用户 ID,房间权限和 presence 校验以它为准。
|
||
ActorID int64 `json:"actor_user_id"`
|
||
// Room 是目标房间 ID,命令只允许作用于一个 Room Cell。
|
||
Room string `json:"room_id"`
|
||
// GatewayNodeID 记录入口节点,便于排查命令来源。
|
||
GatewayNodeID string `json:"gateway_node_id"`
|
||
// SessionID 记录 gateway 看到的客户端会话,不等同于 im-service WebSocket 连接。
|
||
SessionID string `json:"session_id"`
|
||
// SentAtMS 是客户端请求进入系统的时间,恢复回放时用于还原用户态时间字段。
|
||
SentAtMS int64 `json:"sent_at_ms"`
|
||
}
|
||
|
||
// ID 返回命令幂等主键。
|
||
func (b Base) ID() string {
|
||
return b.CommandID
|
||
}
|
||
|
||
// RoomID 返回命令所属房间。
|
||
func (b Base) RoomID() string {
|
||
return b.Room
|
||
}
|
||
|
||
// ActorUserID 返回命令操作者。
|
||
func (b Base) ActorUserID() int64 {
|
||
return b.ActorID
|
||
}
|
||
|
||
// CreateRoom 定义房间创建请求。
|
||
type CreateRoom struct {
|
||
Base
|
||
// OwnerUserID 是房间所有者,创建后自动进入管理员集合。
|
||
OwnerUserID int64 `json:"owner_user_id"`
|
||
// HostUserID 是主持人,创建后也进入管理员集合。
|
||
HostUserID int64 `json:"host_user_id"`
|
||
// SeatCount 决定初始化麦位数量。
|
||
SeatCount int32 `json:"seat_count"`
|
||
// Mode 记录房间模式,当前版本只保存不做复杂策略分发。
|
||
Mode string `json:"mode"`
|
||
}
|
||
|
||
// Type 返回命令类型。
|
||
func (CreateRoom) Type() string { return "create_room" }
|
||
|
||
// JoinRoom 定义业务进房请求。
|
||
type JoinRoom struct {
|
||
Base
|
||
// Role 是用户在房间内的轻量角色,默认 audience。
|
||
Role string `json:"role"`
|
||
}
|
||
|
||
// Type 返回命令类型。
|
||
func (JoinRoom) Type() string { return "join_room" }
|
||
|
||
// LeaveRoom 定义业务离房请求。
|
||
type LeaveRoom struct {
|
||
Base
|
||
}
|
||
|
||
// Type 返回命令类型。
|
||
func (LeaveRoom) Type() string { return "leave_room" }
|
||
|
||
// MicUp 定义上麦请求。
|
||
type MicUp struct {
|
||
Base
|
||
// SeatNo 是目标麦位编号,从 RoomState 初始化的麦位集合中查找。
|
||
SeatNo int32 `json:"seat_no"`
|
||
}
|
||
|
||
// Type 返回命令类型。
|
||
func (MicUp) Type() string { return "mic_up" }
|
||
|
||
// MicDown 定义下麦请求。
|
||
type MicDown struct {
|
||
Base
|
||
// TargetUserID 是被下麦用户;操作者和目标用户可以不同。
|
||
TargetUserID int64 `json:"target_user_id"`
|
||
}
|
||
|
||
// Type 返回命令类型。
|
||
func (MicDown) Type() string { return "mic_down" }
|
||
|
||
// ChangeMicSeat 定义换麦位请求。
|
||
type ChangeMicSeat struct {
|
||
Base
|
||
// TargetUserID 是需要换位的用户。
|
||
TargetUserID int64 `json:"target_user_id"`
|
||
// SeatNo 是目标麦位编号。
|
||
SeatNo int32 `json:"seat_no"`
|
||
}
|
||
|
||
// Type 返回命令类型。
|
||
func (ChangeMicSeat) Type() string { return "change_mic_seat" }
|
||
|
||
// MuteUser 定义禁言请求。
|
||
type MuteUser struct {
|
||
Base
|
||
// TargetUserID 是被修改禁言状态的用户。
|
||
TargetUserID int64 `json:"target_user_id"`
|
||
// Muted 为 true 表示禁言,false 表示解除禁言。
|
||
Muted bool `json:"muted"`
|
||
}
|
||
|
||
// Type 返回命令类型。
|
||
func (MuteUser) Type() string { return "mute_user" }
|
||
|
||
// KickUser 定义踢人请求。
|
||
type KickUser struct {
|
||
Base
|
||
// TargetUserID 是被踢出并加入 ban 集合的用户。
|
||
TargetUserID int64 `json:"target_user_id"`
|
||
}
|
||
|
||
// Type 返回命令类型。
|
||
func (KickUser) Type() string { return "kick_user" }
|
||
|
||
// SendGift 定义送礼请求。
|
||
type SendGift struct {
|
||
Base
|
||
// TargetUserID 是礼物接收方,当前版本要求接收方在房间内。
|
||
TargetUserID int64 `json:"target_user_id"`
|
||
// GiftID 是礼物配置标识,具体配置有效性当前由调用方和 wallet 链路保证。
|
||
GiftID string `json:"gift_id"`
|
||
// GiftCount 是礼物数量,必须为正数。
|
||
GiftCount int32 `json:"gift_count"`
|
||
// GiftUnitValue 是单个礼物价值,必须为正数,账务扣费由 wallet-service 执行。
|
||
GiftUnitValue int64 `json:"gift_unit_value"`
|
||
}
|
||
|
||
// Type 返回命令类型。
|
||
func (SendGift) Type() string { return "send_gift" }
|
||
|
||
// Serialize 把命令编码成 command log 持久化所需的稳定载荷。
|
||
func Serialize(cmd Command) ([]byte, error) {
|
||
// 当前 command log 使用 JSON 载荷,便于排查;命令类型由独立列保存。
|
||
return json.Marshal(cmd)
|
||
}
|
||
|
||
// Deserialize 按命令类型恢复命令载荷。
|
||
func Deserialize(commandType string, payload []byte) (Command, error) {
|
||
var cmd Command
|
||
|
||
// command_type 是恢复时的分发键,未知命令返回 nil 让恢复流程安全跳过。
|
||
switch commandType {
|
||
case CreateRoom{}.Type():
|
||
cmd = &CreateRoom{}
|
||
case JoinRoom{}.Type():
|
||
cmd = &JoinRoom{}
|
||
case LeaveRoom{}.Type():
|
||
cmd = &LeaveRoom{}
|
||
case MicUp{}.Type():
|
||
cmd = &MicUp{}
|
||
case MicDown{}.Type():
|
||
cmd = &MicDown{}
|
||
case ChangeMicSeat{}.Type():
|
||
cmd = &ChangeMicSeat{}
|
||
case MuteUser{}.Type():
|
||
cmd = &MuteUser{}
|
||
case KickUser{}.Type():
|
||
cmd = &KickUser{}
|
||
case SendGift{}.Type():
|
||
cmd = &SendGift{}
|
||
default:
|
||
return nil, nil
|
||
}
|
||
|
||
if err := json.Unmarshal(payload, cmd); err != nil {
|
||
// 单条命令反序列化失败说明 command log 损坏,恢复流程必须失败而不是继续构建错误状态。
|
||
return nil, err
|
||
}
|
||
|
||
return cmd, nil
|
||
}
|