851 lines
36 KiB
Go
851 lines
36 KiB
Go
// Package service 定义 room-service 领域服务及其持久化边界。
|
||
package service
|
||
|
||
import (
|
||
"context"
|
||
|
||
"hyapp/services/room-service/internal/room/outbox"
|
||
)
|
||
|
||
// RoomMeta 对应 rooms 表中房间的持久元数据。
|
||
type RoomMeta struct {
|
||
// AppCode 是房间所属 App,和 RoomID 共同构成房间持久化隔离边界。
|
||
AppCode string
|
||
// RoomID 是房间主键,也是恢复和 lease 路由的分区键。
|
||
RoomID string
|
||
// RoomShortID 是客户端可搜索/展示的短房号,首版等于 owner 展示短号。
|
||
RoomShortID string
|
||
// OwnerUserID 是房间所有者,恢复无快照房间时用于重建管理员集合。
|
||
OwnerUserID int64
|
||
// SeatCount 是初始麦位数量,只有无快照恢复时需要它重建麦位。
|
||
SeatCount int32
|
||
// Mode 是房间模式,当前作为元数据持久化。
|
||
Mode string
|
||
// Status 是房间基础状态,快照缺失时用于恢复 RoomState.Status。
|
||
Status string
|
||
// RoomPasswordHash 是当前入房密码哈希;为空表示未锁房,明文从不落库。
|
||
RoomPasswordHash string
|
||
// VisibleRegionID 是房间列表可见区域,0 表示 GLOBAL 兜底桶。
|
||
VisibleRegionID int64
|
||
}
|
||
|
||
// CommandRecord 对应 room_command_log 中一条成功命令。
|
||
type CommandRecord struct {
|
||
// AppCode 是命令所属 App,保证 command_id 幂等只在单个 App 内生效。
|
||
AppCode string
|
||
// RoomID 是命令所属房间。
|
||
RoomID string
|
||
// RoomVersion 是命令成功应用后的房间版本,恢复时按它排序回放。
|
||
RoomVersion int64
|
||
// CommandID 是幂等键,repository 必须保证同房间唯一。
|
||
CommandID string
|
||
// CommandType 是反序列化命令 payload 的分发键。
|
||
CommandType string
|
||
// Payload 是命令 JSON 序列化结果。
|
||
Payload []byte
|
||
// Replayable 标记该命令是否参与恢复回放。
|
||
Replayable bool
|
||
// OwnerNodeID 是提交命令时持有房间 lease 的 room-service 节点。
|
||
OwnerNodeID string
|
||
// LeaseToken 是提交命令前通过 Redis fencing 校验的 lease token。
|
||
LeaseToken string
|
||
// CreatedAtMS 是命令成功落盘的 UTC 毫秒时间戳,恢复和审计不依赖数据库时区。
|
||
CreatedAtMS int64
|
||
}
|
||
|
||
// MutationCommit 表达一次 Room Cell 命令需要一起提交的持久化副作用。
|
||
type MutationCommit struct {
|
||
// Command 是本次命令日志,所有成功命令都必须写入。
|
||
Command CommandRecord
|
||
// OutboxRecords 是本次命令产生的房间外事件。
|
||
OutboxRecords []outbox.Record
|
||
// DeleteRoom 表示后台确认删除房间后清理该房间的持久恢复来源和列表投影。
|
||
// 该标记只用于 AdminDeleteRoom;关闭房间必须继续走 RoomStatus=closed,保留可恢复的房间事实。
|
||
DeleteRoom bool
|
||
// RoomStatus 非空时同步更新 rooms 和 room_list_entries 的生命周期状态。
|
||
RoomStatus string
|
||
// RoomSeatCount 非 nil 时同步更新 rooms 元数据中的麦位总数。
|
||
RoomSeatCount *int32
|
||
// RoomPasswordHash 非 nil 时同步更新 rooms 中的当前密码哈希,供最新快照恢复锁房态。
|
||
RoomPasswordHash *string
|
||
// RoomMode 非 nil 时同步更新 rooms 元数据中的房间模式。
|
||
RoomMode *string
|
||
// VisibleRegionID 非 nil 时同步更新 rooms 元数据中的列表可见区域。
|
||
VisibleRegionID *int64
|
||
// CloseInfo 非 nil 时同步更新后台生命周期审计字段。
|
||
CloseInfo *RoomCloseInfo
|
||
// RoomUserGiftStats 是本次命令产生的房间用户送礼价值增量,必须和命令日志同事务提交。
|
||
RoomUserGiftStats []RoomUserGiftStatIncrement
|
||
// RoomUserContributionPeriodStats 是本次命令产生的房间用户周期贡献增量,必须和命令日志同事务提交。
|
||
RoomUserContributionPeriodStats []RoomUserContributionPeriodStatIncrement
|
||
// RoomWeeklyContribution 是后台房间贡献列的 UTC 周期读模型增量;它和命令日志同事务提交,避免送礼成功后榜单缺分。
|
||
RoomWeeklyContribution *RoomWeeklyContributionIncrement
|
||
}
|
||
|
||
// RoomUserGiftStatIncrement 表达当前房间内某个送礼用户的礼物价值增量。
|
||
type RoomUserGiftStatIncrement struct {
|
||
AppCode string
|
||
RoomID string
|
||
UserID int64
|
||
GiftValue int64
|
||
LastGiftAtMS int64
|
||
}
|
||
|
||
// RoomUserContributionPeriodStatIncrement 表达当前房间内某个送礼用户在固定 UTC 周期内的贡献增量。
|
||
type RoomUserContributionPeriodStatIncrement struct {
|
||
AppCode string
|
||
RoomID string
|
||
Period string
|
||
PeriodStartMS int64
|
||
PeriodEndMS int64
|
||
UserID int64
|
||
GiftValue int64
|
||
LastGiftAtMS int64
|
||
}
|
||
|
||
// RoomWeeklyContributionIncrement 表达一个房间在当前 UTC 周内新增的展示贡献。
|
||
type RoomWeeklyContributionIncrement struct {
|
||
AppCode string
|
||
RoomID string
|
||
GiftValue int64
|
||
OccurredMS int64
|
||
}
|
||
|
||
type RoomCloseInfo struct {
|
||
Reason string
|
||
AdminID uint64
|
||
AdminName string
|
||
ClosedAtMS int64
|
||
ClearOnOpen bool
|
||
}
|
||
|
||
// RoomBackgroundImage 是房间 owner 保存过的背景图素材。
|
||
// 当前生效背景仍属于 Room Cell 快照;该表只保存可选素材列表。
|
||
type RoomBackgroundImage struct {
|
||
AppCode string
|
||
BackgroundID int64
|
||
RoomID string
|
||
ImageURL string
|
||
CreatedByUserID int64
|
||
CreatedAtMS int64
|
||
UpdatedAtMS int64
|
||
}
|
||
|
||
// SnapshotRecord 对应 room_snapshots 中的一条最新快照。
|
||
type SnapshotRecord struct {
|
||
// AppCode 是快照所属 App,恢复时必须和房间 meta 保持一致。
|
||
AppCode string
|
||
// RoomID 是快照所属房间。
|
||
RoomID string
|
||
// RoomVersion 是快照覆盖到的房间版本。
|
||
RoomVersion int64
|
||
// Payload 是 roomv1.RoomSnapshot 的 protobuf 序列化结果。
|
||
Payload []byte
|
||
// CreatedAtMS 是快照生成的 UTC 毫秒时间戳。
|
||
CreatedAtMS int64
|
||
}
|
||
|
||
// RoomListEntry 是 room_list_entries 的领域投影,只保存列表卡片所需字段。
|
||
type RoomListEntry struct {
|
||
// AppCode 是列表投影所属 App,发现页不能跨 App 读到房间。
|
||
AppCode string
|
||
// RoomID 是列表卡片和 JoinRoom 的跳转目标。
|
||
RoomID string
|
||
// RoomShortID 是列表卡片展示/搜索用短房号。
|
||
RoomShortID string
|
||
// VisibleRegionID 是房间自身的列表区域;公共发现列表会用它把当前区域房间排在其他区域之前。
|
||
VisibleRegionID int64
|
||
// OwnerCountryCode 是房主国家码;公共发现列表国家 tab 使用它做服务端筛选。
|
||
OwnerCountryCode string
|
||
// OwnerUserID 是房间所有者,用于卡片展示和运营排查。
|
||
OwnerUserID int64
|
||
// Title 是卡片标题;空值由客户端或后续资料聚合兜底。
|
||
Title string
|
||
// CoverURL 是卡片封面;空值表示没有单独封面。
|
||
CoverURL string
|
||
// Mode 是房间模式,来自 RoomState/RoomMeta。
|
||
Mode string
|
||
// Status 是房间生命周期状态,列表默认只查 active。
|
||
Status string
|
||
// Locked 表示进入房间是否需要密码;列表和搜索只暴露布尔标识,不暴露密码哈希。
|
||
Locked bool
|
||
// Heat 是房间热度,当前主要由送礼累计。
|
||
Heat int64
|
||
// OnlineCount 是 room-service 业务 presence 数量。
|
||
OnlineCount int32
|
||
// SeatCount 是麦位总数。
|
||
SeatCount int32
|
||
// OccupiedSeatCount 是当前被占用麦位数。
|
||
OccupiedSeatCount int32
|
||
// SortScore 是热门列表排序分,算法不进入 RoomState。
|
||
SortScore int64
|
||
// CreatedAtMS 是创建房间时的毫秒时间,new tab 使用它排序。
|
||
CreatedAtMS int64
|
||
// UpdatedAtMS 是投影最后更新时间。
|
||
UpdatedAtMS int64
|
||
// FeedSubjectUserID 是关系房间流命中的好友/关注用户;只用于生成稳定 cursor,不出现在 HTTP 卡片里。
|
||
FeedSubjectUserID int64
|
||
// IsPinned 表达该卡片在当前公共列表查询中是否命中有效置顶。
|
||
IsPinned bool
|
||
// PinListRank 是公共发现列表排序桶;hot 会把有人房和空房再拆层,new 仍只区分本区和外区。
|
||
PinListRank int64
|
||
// PinWeight 是命中置顶的排序权重;只用于公共房间列表排序和 cursor。
|
||
PinWeight int64
|
||
// PinnedUntilMS 是命中置顶的过期时间;只用于公共房间列表排序和 cursor。
|
||
PinnedUntilMS int64
|
||
}
|
||
|
||
// RoomListPinEntry 是公共发现页置顶读模型的最小事实。
|
||
type RoomListPinEntry struct {
|
||
// ID 是 room_region_pins 的自增主键,缓存增量更新和删除都用它定位旧 zset member。
|
||
ID int64
|
||
// AppCode 限定置顶所属 App,避免多 App 共用 Redis key 时互相污染。
|
||
AppCode string
|
||
// VisibleRegionID 是置顶作用域;global 统一写 0,region/country 使用房间区域。
|
||
VisibleRegionID int64
|
||
// PinType 区分 global、region、country 三种公共列表置顶语义。
|
||
PinType string
|
||
// RoomID 是置顶命中的房间卡片。
|
||
RoomID string
|
||
// Weight 是置顶同桶排序的第一关键字,值越大越靠前。
|
||
Weight int64
|
||
// Status 保留 owner 表状态;非 active 必须从缓存索引移除。
|
||
Status string
|
||
// PinnedAtMS 是置顶生效开始时间,未来置顶可以先写缓存但读时不能提前展示。
|
||
PinnedAtMS int64
|
||
// ExpiresAtMS 是置顶失效时间,读缓存时必须按当前 UTC 毫秒过滤。
|
||
ExpiresAtMS int64
|
||
}
|
||
|
||
type AdminRoomListEntry struct {
|
||
RoomID string
|
||
RoomShortID string
|
||
VisibleRegionID int64
|
||
OwnerUserID int64
|
||
Title string
|
||
CoverURL string
|
||
Mode string
|
||
Status string
|
||
CloseReason string
|
||
ClosedByAdminID uint64
|
||
ClosedByAdminName string
|
||
ClosedAtMS int64
|
||
Heat int64
|
||
OnlineCount int32
|
||
SeatCount int32
|
||
OccupiedSeatCount int32
|
||
SortScore int64
|
||
CreatedAtMS int64
|
||
UpdatedAtMS int64
|
||
}
|
||
|
||
type AdminRoomListQuery struct {
|
||
AppCode string
|
||
Page int
|
||
PageSize int
|
||
Keyword string
|
||
Status string
|
||
RegionID int64
|
||
OwnerUserID int64
|
||
SortBy string
|
||
SortDirection string
|
||
// NowMS 用于把后台房间贡献收敛到当前 UTC 周;调用方传服务时钟,测试可以固定边界。
|
||
NowMS int64
|
||
}
|
||
|
||
type AdminRoomPinEntry struct {
|
||
AppCode string
|
||
ID int64
|
||
VisibleRegionID int64
|
||
PinType string
|
||
RoomID string
|
||
Weight int64
|
||
Status string
|
||
PinnedAtMS int64
|
||
ExpiresAtMS int64
|
||
CancelledAtMS int64
|
||
CreatedByAdminID uint64
|
||
CancelledByAdminID uint64
|
||
CreatedAtMS int64
|
||
UpdatedAtMS int64
|
||
RoomShortID string
|
||
RoomVisibleRegionID int64
|
||
Title string
|
||
CoverURL string
|
||
OwnerUserID int64
|
||
RoomStatus string
|
||
}
|
||
|
||
type AdminRoomPinQuery struct {
|
||
AppCode string
|
||
Page int
|
||
PageSize int
|
||
Keyword string
|
||
Status string
|
||
RegionID int64
|
||
PinType string
|
||
NowMS int64
|
||
}
|
||
|
||
type AdminCreateRoomPinInput struct {
|
||
RoomID string
|
||
PinType string
|
||
Weight int64
|
||
DurationDays int64
|
||
PinnedAtMS int64
|
||
ExpiresAtMS int64
|
||
AdminID uint64
|
||
NowMS int64
|
||
}
|
||
|
||
type HumanRoomRobotCountryPool struct {
|
||
CountryCode string
|
||
RobotUserIDs []int64
|
||
}
|
||
|
||
type HumanRoomRobotCountryRule struct {
|
||
CountryCode string
|
||
MaxRoomCount int32
|
||
AllowedOwnerIDs []string
|
||
}
|
||
|
||
type HumanRoomRobotConfig struct {
|
||
AppCode string
|
||
Enabled bool
|
||
CandidateRoomMaxOnline int32
|
||
RoomFullStopOnline int32
|
||
RoomTargetMinOnline int32
|
||
RoomTargetMaxOnline int32
|
||
RobotStayMinMS int64
|
||
RobotStayMaxMS int64
|
||
RobotReplaceMinMS int64
|
||
RobotReplaceMaxMS int64
|
||
NormalGiftIntervalMS int64
|
||
NormalGiftIntervalMinMS int64
|
||
NormalGiftIntervalMaxMS int64
|
||
GiftIDs []string
|
||
LuckyGiftIDs []string
|
||
SuperLuckyGiftIDs []string
|
||
LuckyComboMin int64
|
||
LuckyComboMax int64
|
||
LuckyPauseMinMS int64
|
||
LuckyPauseMaxMS int64
|
||
MaxGiftSenders int64
|
||
CountryPools []HumanRoomRobotCountryPool
|
||
AllowedOwnerIDs []string
|
||
CountryLimitEnabled bool
|
||
CountryRules []HumanRoomRobotCountryRule
|
||
UpdatedByAdminID uint64
|
||
CreatedAtMS int64
|
||
UpdatedAtMS int64
|
||
}
|
||
|
||
// RoomSeatConfig 是后台房间配置里控制创建/修改房间座位数的低频配置。
|
||
type RoomSeatConfig struct {
|
||
// AppCode 是配置所属 App。
|
||
AppCode string
|
||
// AllowedSeatCounts 是当前 App 允许客户端使用的麦位总数。
|
||
AllowedSeatCounts []int32
|
||
// DefaultSeatCount 是 CreateRoom 未传 seat_count 时使用的默认麦位总数。
|
||
DefaultSeatCount int32
|
||
// UpdatedAtMS 是配置最后更新时间,主要用于后台展示和排障。
|
||
UpdatedAtMS int64
|
||
}
|
||
|
||
// RoomRocketConfig 是后台语音房火箭配置的运行时快照。
|
||
type RoomRocketConfig struct {
|
||
AppCode string
|
||
Enabled bool
|
||
ConfigVersion int64
|
||
FuelSource string
|
||
LaunchDelayMS int64
|
||
BroadcastEnabled bool
|
||
BroadcastScope string
|
||
BroadcastDelayMS int64
|
||
RewardStackPolicy string
|
||
Levels []RoomRocketLevelConfig
|
||
GiftFuelRules []GiftFuelRuleConfig
|
||
UpdatedByAdminID int64
|
||
CreatedAtMS int64
|
||
UpdatedAtMS int64
|
||
}
|
||
|
||
// RoomRocketLevelConfig 描述单个等级的物料、阈值和三类奖励池。
|
||
type RoomRocketLevelConfig struct {
|
||
Level int32 `json:"level"`
|
||
FuelThreshold int64 `json:"fuelThreshold"`
|
||
CoverURL string `json:"coverUrl"`
|
||
AnimationURL string `json:"animationUrl"`
|
||
LaunchAnimationURL string `json:"launchAnimationUrl"`
|
||
LaunchedImageURL string `json:"launchedImageUrl"`
|
||
InRoomRewards []RoomRocketRewardItem `json:"inRoomRewards"`
|
||
Top1Rewards []RoomRocketRewardItem `json:"top1Rewards"`
|
||
IgniterRewards []RoomRocketRewardItem `json:"igniterRewards"`
|
||
}
|
||
|
||
// RoomRocketRewardItem 是后台配置中的奖励候选项。
|
||
type RoomRocketRewardItem struct {
|
||
RewardItemID string `json:"rewardItemId"`
|
||
ResourceGroupID int64 `json:"resourceGroupId"`
|
||
Weight int64 `json:"weight"`
|
||
Quantity int64 `json:"quantity"`
|
||
DisplayName string `json:"displayName"`
|
||
IconURL string `json:"iconUrl"`
|
||
}
|
||
|
||
// GiftFuelRuleConfig 控制特定礼物或礼物类型如何覆盖默认燃料计算。
|
||
type GiftFuelRuleConfig struct {
|
||
RuleID string `json:"ruleId"`
|
||
GiftID string `json:"giftId"`
|
||
GiftTypeCode string `json:"giftTypeCode"`
|
||
MultiplierPPM int64 `json:"multiplierPpm"`
|
||
FixedFuel int64 `json:"fixedFuel"`
|
||
Excluded bool `json:"excluded"`
|
||
}
|
||
|
||
// RobotRoomGiftRule 是后台配置的机器人房间送礼节奏;它只驱动机器人展示链路,不进入真实活动奖池。
|
||
type RobotRoomGiftRule struct {
|
||
GiftIDs []string
|
||
LuckyGiftIDs []string
|
||
NormalGiftIntervalMS int64
|
||
LuckyComboMin int64
|
||
LuckyComboMax int64
|
||
LuckyPauseMinMS int64
|
||
LuckyPauseMaxMS int64
|
||
RobotStayMinMS int64
|
||
RobotStayMaxMS int64
|
||
RobotReplaceMinMS int64
|
||
RobotReplaceMaxMS int64
|
||
MaxGiftSenders int64
|
||
}
|
||
|
||
// RobotRoomConfig 是 room-service 持久化的机器人房间配置和账号占用事实。
|
||
type RobotRoomConfig struct {
|
||
AppCode string
|
||
RoomID string
|
||
RoomShortID string
|
||
Title string
|
||
CoverURL string
|
||
VisibleRegionID int64
|
||
OwnerCountryCode string
|
||
Status string
|
||
OwnerRobotUserID int64
|
||
RobotUserIDs []int64
|
||
ActiveRobotCount int32
|
||
SeatCount int32
|
||
GiftRule RobotRoomGiftRule
|
||
CreatedByAdminID uint64
|
||
CreatedAtMS int64
|
||
UpdatedAtMS int64
|
||
}
|
||
|
||
// RobotRoomListQuery 是后台机器人房间列表查询条件。
|
||
type RobotRoomListQuery struct {
|
||
AppCode string
|
||
Status string
|
||
Page int
|
||
PageSize int
|
||
}
|
||
|
||
// CreateRobotRoomConfigInput 在同一事务中锁定机器人账号并写入房间配置。
|
||
type CreateRobotRoomConfigInput struct {
|
||
Config RobotRoomConfig
|
||
NowMS int64
|
||
}
|
||
|
||
// RoomPresence 是当前用户可恢复房间的轻量读模型。
|
||
// 它从 RoomSnapshot 投影而来,只用于 App 启动/回前台探测,不替代 Room Cell 权威状态。
|
||
type RoomPresence struct {
|
||
// AppCode 是 presence 所属 App,和 user_id 一起限定用户当前房间。
|
||
AppCode string
|
||
// UserID 是业务 presence 所属用户。
|
||
UserID int64
|
||
// RoomID 是用户当前仍在的房间;status=left 时只保留排障参考。
|
||
RoomID string
|
||
// Role 是房间内轻量角色,来自 RoomUser.role。
|
||
Role string
|
||
// PublishState 是用户当前麦位发流状态,非上麦用户为空。
|
||
PublishState string
|
||
// MicSessionID 是当前麦位发流会话,非上麦用户为空。
|
||
MicSessionID string
|
||
// RoomVersion 是投影来自的房间版本。
|
||
RoomVersion int64
|
||
// Status 表示该用户 presence 是否仍 active。
|
||
Status string
|
||
// JoinedAtMS 是用户进入当前房间的时间。
|
||
JoinedAtMS int64
|
||
// LastSeenAtMS 是用户在 Room Cell 内的最后业务心跳时间。
|
||
LastSeenAtMS int64
|
||
// UpdatedAtMS 是投影写入时间。
|
||
UpdatedAtMS int64
|
||
// GiftValue 是该用户在当前房间生命周期内作为送礼方累计送出的礼物价值。
|
||
GiftValue int64
|
||
}
|
||
|
||
// RoomOnlineUserQuery 是房间在线用户分页读模型查询条件。
|
||
type RoomOnlineUserQuery struct {
|
||
AppCode string
|
||
RoomID string
|
||
Page int
|
||
PageSize int
|
||
Sort string
|
||
}
|
||
|
||
// RoomOnlineUserPage 是 room_user_presence 中某房间 active 用户的一页结果。
|
||
type RoomOnlineUserPage struct {
|
||
Users []RoomPresence
|
||
Total int64
|
||
Page int
|
||
PageSize int
|
||
}
|
||
|
||
// RoomContributionRankStore 管理房间内用户周期贡献榜读模型。
|
||
type RoomContributionRankStore interface {
|
||
// ListRoomContributionRank 查询房间内某周期 Top 用户贡献,不扫描命令日志或 outbox。
|
||
ListRoomContributionRank(ctx context.Context, query RoomContributionRankQuery) (RoomContributionRankPage, error)
|
||
}
|
||
|
||
// RoomListQuery 是 room-service 房间列表读模型查询条件。
|
||
type RoomListQuery struct {
|
||
// AppCode 是列表查询所属 App,通常来自 gateway RequestMeta。
|
||
AppCode string
|
||
// VisibleRegionID 是服务端解析出的用户区域,客户端不能伪造。
|
||
VisibleRegionID int64
|
||
// AllVisibleRegions 只服务后台白名单用户;为 true 时列表读模型不再按 VisibleRegionID 收敛。
|
||
AllVisibleRegions bool
|
||
// Tab 只允许 hot/new,决定公共发现列表排序字段。
|
||
Tab string
|
||
// OwnerUserID 保留给内部定向读模型;公开 Mine 顶部卡片走 GetMyRoom。
|
||
OwnerUserID int64
|
||
// OwnerUserIDs 是业务方预先解析出的房主集合,用于 Agency 等组织页批量取房间卡片。
|
||
OwnerUserIDs []int64
|
||
// Query 非空时按 room_id 或 title 做包含匹配。
|
||
Query string
|
||
// CountryCode 非空时只返回房主国家命中的房间;gateway 必须先校验它属于当前用户区域。
|
||
CountryCode string
|
||
// ViewerCountryCode 是当前用户国家;公共列表不按它过滤,只用它在区域内把本国家房间排到同状态房间前。
|
||
ViewerCountryCode string
|
||
// Limit 是实际查询数量,service 层会限制最大值。
|
||
Limit int
|
||
// CursorSortScore 是 hot tab 的游标 score。
|
||
CursorSortScore int64
|
||
// CursorCreatedAtMS 是 new tab 的游标创建时间。
|
||
CursorCreatedAtMS int64
|
||
// CursorUpdatedAtMS 是用户关系 feed tab 的游标更新时间。
|
||
CursorUpdatedAtMS int64
|
||
// CursorRoomID 是同分或同时间下的稳定翻页边界。
|
||
CursorRoomID string
|
||
// CursorPinListRank 是上一页最后一条所在排序桶,公共列表用它跨全区、区域和普通房分区翻页。
|
||
CursorPinListRank int64
|
||
// CursorPinned 是旧游标兼容字段;新排序以 CursorPinListRank 为准。
|
||
CursorPinned bool
|
||
// CursorPinWeight 是上一页最后一条置顶权重。
|
||
CursorPinWeight int64
|
||
// CursorPinnedUntilMS 是上一页最后一条置顶过期时间。
|
||
CursorPinnedUntilMS int64
|
||
// NowMS 是有效置顶判断时间,service 层使用 UTC 业务时钟注入。
|
||
NowMS int64
|
||
}
|
||
|
||
// RoomListCacheEntryScanQuery 是缓存全量刷新时按主键批量扫描 MySQL 列表投影的游标。
|
||
type RoomListCacheEntryScanQuery struct {
|
||
// AfterAppCode 和 AfterRoomID 组成严格递增游标,避免 OFFSET 在大表上反复扫描。
|
||
AfterAppCode string
|
||
AfterRoomID string
|
||
// Limit 是单批扫描数量,由 worker 固定小批量推进。
|
||
Limit int
|
||
}
|
||
|
||
// RoomListPinScanQuery 是缓存全量刷新时扫描有效置顶事实的游标。
|
||
type RoomListPinScanQuery struct {
|
||
// AfterID 是 room_region_pins 自增主键游标。
|
||
AfterID int64
|
||
// Limit 是单批扫描数量。
|
||
Limit int
|
||
// NowMS 用于排除已过期置顶;未来置顶保留,读缓存时按 pinned_at_ms 再判断。
|
||
NowMS int64
|
||
}
|
||
|
||
// RoomListEntriesByIDQuery 是榜单等定向补全房间卡片时的批量读取条件。
|
||
type RoomListEntriesByIDQuery struct {
|
||
// AppCode 限定 App 边界,避免一个榜单读到其他 App 的同名 room_id。
|
||
AppCode string
|
||
// RoomIDs 是榜单已经命中的房间集合;repository 必须按这些 key 精确读取。
|
||
RoomIDs []string
|
||
}
|
||
|
||
// RoomUserFeedEntry 是“访问过/好友/关注”房间流的读模型索引。
|
||
// 它只保存用户到房间的列表关系,不复制房间卡片字段,卡片内容仍来自 room_list_entries。
|
||
type RoomUserFeedEntry struct {
|
||
// AppCode 是 feed 所属 App,防止跨 App 看到关系流。
|
||
AppCode string
|
||
// UserID 是拥有该 feed 的用户。
|
||
UserID int64
|
||
// FeedType 是 visited/friend/following 之一;关系事实 owner 后续可通过事件填充 friend/following。
|
||
FeedType string
|
||
// RoomID 是 feed 指向的房间。
|
||
RoomID string
|
||
// CreatedAtMS 是首次建立该 feed 关系的 UTC 毫秒。
|
||
CreatedAtMS int64
|
||
// UpdatedAtMS 是 feed 排序时间,visited 会在 JoinRoom 成功后刷新。
|
||
UpdatedAtMS int64
|
||
}
|
||
|
||
// RoomUserFeedQuery 是用户房间关系流的分页查询条件。
|
||
type RoomUserFeedQuery struct {
|
||
// AppCode 是 feed 查询所属 App。
|
||
AppCode string
|
||
// UserID 是当前登录用户。
|
||
UserID int64
|
||
// FeedType 是 visited/friend/following 之一。
|
||
FeedType string
|
||
// VisibleRegionID 沿用房间发现页区域桶,避免关系流跨区域露出。
|
||
VisibleRegionID int64
|
||
// Query 非空时按 room_id、room_short_id 或 title 做包含匹配。
|
||
Query string
|
||
// Limit 是实际查询数量,service 层会限制最大值。
|
||
Limit int
|
||
// CursorUpdatedAtMS 是上一页最后一条 feed 更新时间。
|
||
CursorUpdatedAtMS int64
|
||
// CursorRoomID 是同时间下的稳定翻页边界。
|
||
CursorRoomID string
|
||
}
|
||
|
||
// RoomFollowRecord 是用户关注房间的低频关系事实。
|
||
// 它不进入 Room Cell 快照,避免把用户个性化关系扩散到房间核心状态。
|
||
type RoomFollowRecord struct {
|
||
// AppCode 是关系所属 App,防止多 App 之间互相看到关注关系。
|
||
AppCode string
|
||
// UserID 是发起关注的登录用户。
|
||
UserID int64
|
||
// RoomID 是被关注房间。
|
||
RoomID string
|
||
// Status 表达当前关系是否仍 active;取消关注只改状态,保留审计时间。
|
||
Status string
|
||
// FollowedAtMS 是最近一次从非 active 转为 active 的 UTC 毫秒。
|
||
FollowedAtMS int64
|
||
// UpdatedAtMS 是关系最后一次写入时间。
|
||
UpdatedAtMS int64
|
||
}
|
||
|
||
// RoomFollowQuery 是 Mine 页“关注的房间”分页查询条件。
|
||
type RoomFollowQuery struct {
|
||
// AppCode 是查询所属 App。
|
||
AppCode string
|
||
// UserID 是当前登录用户。
|
||
UserID int64
|
||
// VisibleRegionID 沿用 Mine 房间流区域桶,避免跨区域露出房间卡片。
|
||
VisibleRegionID int64
|
||
// Query 非空时按 room_id、room_short_id 或 title 做包含匹配。
|
||
Query string
|
||
// Limit 是实际查询数量,service 层会限制最大值。
|
||
Limit int
|
||
// CursorFollowedAtMS 是上一页最后一条关注关系排序时间。
|
||
CursorFollowedAtMS int64
|
||
// CursorRoomID 是同时间下的稳定翻页边界。
|
||
CursorRoomID string
|
||
}
|
||
|
||
// RoomFeedRelatedUser 是 gateway 从 user-service 读取到的关系事实快照。
|
||
// room-service 只使用它做 active 房间卡片查询和排序,不保存好友/关注关系。
|
||
type RoomFeedRelatedUser struct {
|
||
// UserID 是好友或关注对象的用户 ID。
|
||
UserID int64
|
||
// RelationUpdatedAtMS 是该关系的排序时间,followed_at_ms/friended_at_ms 都映射到这里。
|
||
RelationUpdatedAtMS int64
|
||
}
|
||
|
||
// RoomRelatedFeedQuery 根据一批关系用户查询他们当前 active 房间卡片。
|
||
type RoomRelatedFeedQuery struct {
|
||
// AppCode 是 feed 查询所属 App。
|
||
AppCode string
|
||
// VisibleRegionID 沿用房间发现页区域桶,避免关系流跨区域露出。
|
||
VisibleRegionID int64
|
||
// RelatedUsers 是 user-service 已授权返回的好友/关注对象。
|
||
RelatedUsers []RoomFeedRelatedUser
|
||
// Query 非空时按 room_id、room_short_id 或 title 做包含匹配。
|
||
Query string
|
||
// Limit 是实际查询数量,service 层会限制最大值。
|
||
Limit int
|
||
// CursorUpdatedAtMS 是上一页最后一条关系排序时间。
|
||
CursorUpdatedAtMS int64
|
||
// CursorSubjectUserID 是关系排序时间相同时的好友/关注用户边界。
|
||
CursorSubjectUserID int64
|
||
// CursorRoomID 是同时间下的稳定翻页边界。
|
||
CursorRoomID string
|
||
}
|
||
|
||
// Repository 聚合 room-service 当前运行需要的全部持久化能力。
|
||
//
|
||
// 总接口继续保留给 Service 装配使用,子接口按变化原因拆开,后续单测可以只依赖
|
||
// CommandStore、RoomListStore 或 OutboxStore 这类窄接口,避免为一个用例 mock 整个仓储面。
|
||
type Repository interface {
|
||
RoomMetaStore
|
||
CommandStore
|
||
SnapshotStore
|
||
RoomConfigStore
|
||
OutboxStore
|
||
RoomListStore
|
||
PresenceStore
|
||
RoomContributionRankStore
|
||
AdminRoomStore
|
||
RobotRoomStore
|
||
}
|
||
|
||
// RoomListCacheStore 是公共发现页 Redis 展示读模型边界。
|
||
//
|
||
// MySQL 仍然是房间列表和置顶事实 owner;缓存只服务高频 hot/new 发现页,
|
||
// 因此所有写入都必须 best-effort,任何错误都回落到 MySQL 查询。
|
||
type RoomListCacheStore interface {
|
||
// ListRoomListEntries 尝试从缓存返回一页公共列表;ok=false 表示缓存未就绪或扫描保护触发,调用方应走 MySQL。
|
||
ListRoomListEntries(ctx context.Context, query RoomListQuery) ([]RoomListEntry, bool, error)
|
||
// UpsertRoomListEntry 根据最新列表投影刷新缓存;非 active 房间必须从所有展示 zset 移除。
|
||
UpsertRoomListEntry(ctx context.Context, entry RoomListEntry) error
|
||
// DeleteRoomListEntry 从缓存删除指定房间的卡片和所有展示索引。
|
||
DeleteRoomListEntry(ctx context.Context, appCode string, roomID string) error
|
||
// UpsertRoomPin 根据后台置顶事实刷新 pin 索引;非 active 或已过期置顶由实现移除。
|
||
UpsertRoomPin(ctx context.Context, pin RoomListPinEntry) error
|
||
// RebuildRoomList 用 MySQL 扫描结果重建某个 App 的缓存,并在成功后标记 ready。
|
||
RebuildRoomList(ctx context.Context, appCode string, entries []RoomListEntry, pins []RoomListPinEntry, nowMS int64) error
|
||
}
|
||
|
||
// RoomMetaStore 保存房间基础元数据和房主背景素材;它是 Room Cell 恢复前的轻量入口。
|
||
type RoomMetaStore interface {
|
||
// SaveRoomMeta 保存房间基础元数据,创建房间时必须先建立它。
|
||
SaveRoomMeta(ctx context.Context, meta RoomMeta) error
|
||
// GetRoomMeta 读取房间基础元数据,恢复无内存 Cell 的房间依赖它。
|
||
GetRoomMeta(ctx context.Context, roomID string) (RoomMeta, bool, error)
|
||
// GetRoomMetaByOwner 查询 owner 已创建的房间;产品规则要求一个用户只能创建一个房间。
|
||
GetRoomMetaByOwner(ctx context.Context, ownerUserID int64) (RoomMeta, bool, error)
|
||
// SaveRoomBackground 保存房间 owner 上传过的背景图 URL;相同房间相同 URL 幂等返回同一条素材。
|
||
SaveRoomBackground(ctx context.Context, background RoomBackgroundImage) (RoomBackgroundImage, error)
|
||
// GetRoomBackground 精确读取一个背景图素材,用于 SetRoomBackground 校验归属。
|
||
GetRoomBackground(ctx context.Context, roomID string, backgroundID int64) (RoomBackgroundImage, bool, error)
|
||
// ListRoomBackgrounds 按房间读取背景图素材列表,不读取 Room Cell 状态。
|
||
ListRoomBackgrounds(ctx context.Context, roomID string) ([]RoomBackgroundImage, error)
|
||
}
|
||
|
||
// CommandStore 保存命令幂等记录和一次 Room Cell mutation 的事务提交边界。
|
||
type CommandStore interface {
|
||
// GetCommand 读取已提交命令,用于幂等重试和 command_id 冲突判定。
|
||
GetCommand(ctx context.Context, roomID string, commandID string) (CommandRecord, bool, error)
|
||
// SaveCommand 追加成功命令日志,关键命令恢复必须依赖它。
|
||
SaveCommand(ctx context.Context, record CommandRecord) error
|
||
// SaveMutation 在同一事务中提交命令日志、outbox 事件和可选房间生命周期状态。
|
||
SaveMutation(ctx context.Context, commit MutationCommit) error
|
||
// ListCommandsAfter 读取快照版本之后的命令,恢复时按版本顺序回放。
|
||
ListCommandsAfter(ctx context.Context, roomID string, roomVersion int64) ([]CommandRecord, error)
|
||
}
|
||
|
||
// SnapshotStore 保存和读取最新快照;它只负责降低恢复成本,不替代 command log。
|
||
type SnapshotStore interface {
|
||
// SaveSnapshot 保存最新房间快照,允许覆盖较低版本号快照但不能倒退。
|
||
SaveSnapshot(ctx context.Context, snapshot SnapshotRecord) error
|
||
// GetLatestSnapshot 读取当前最新快照,恢复时优先使用它减少回放成本。
|
||
GetLatestSnapshot(ctx context.Context, roomID string) (SnapshotRecord, bool, error)
|
||
}
|
||
|
||
// RoomConfigStore 管理后台低频配置;读取失败由调用方决定是否使用内置默认值。
|
||
type RoomConfigStore interface {
|
||
// GetRoomSeatConfig 读取后台配置的房间座位数规则;不存在时 service 层使用内置默认值。
|
||
GetRoomSeatConfig(ctx context.Context) (RoomSeatConfig, bool, error)
|
||
// UpsertRoomSeatConfig 写入房间座位数配置,供本地验证和后台配置共享同一张表。
|
||
UpsertRoomSeatConfig(ctx context.Context, config RoomSeatConfig) error
|
||
// GetRoomRocketConfig 读取语音房火箭低频配置;不存在时 service 层使用关闭态默认配置。
|
||
GetRoomRocketConfig(ctx context.Context) (RoomRocketConfig, bool, error)
|
||
// UpsertRoomRocketConfig 写入语音房火箭配置,主要供集成测试和本地验证复用生产表结构。
|
||
UpsertRoomRocketConfig(ctx context.Context, config RoomRocketConfig) error
|
||
}
|
||
|
||
// OutboxStore 管理 room_outbox 的补偿投递生命周期。
|
||
type OutboxStore interface {
|
||
// SaveOutbox 写入房间外事件,必须和成功命令保持同一提交语义。
|
||
SaveOutbox(ctx context.Context, records []outbox.Record) error
|
||
// ListPendingOutbox 扫描待补偿投递事件。
|
||
ListPendingOutbox(ctx context.Context, limit int) ([]outbox.Record, error)
|
||
// ClaimPendingOutbox 抢占一批待投递事件,避免多 worker 同时投递同一批。
|
||
ClaimPendingOutbox(ctx context.Context, workerID string, limit int, lockUntilMS int64) ([]outbox.Record, error)
|
||
// MarkOutboxDelivered 标记事件已经投递成功。
|
||
MarkOutboxDelivered(ctx context.Context, eventID string) error
|
||
// MarkOutboxRetryable 记录一次投递失败,并写入下一次允许抢占的退避时间。
|
||
MarkOutboxRetryable(ctx context.Context, eventID string, lastErr string, nextRetryAtMS int64) error
|
||
// MarkOutboxDead 把超过最大重试次数的事件转入 failed,避免固定污染日志和外部依赖。
|
||
MarkOutboxDead(ctx context.Context, eventID string, lastErr string) error
|
||
// DeleteDeliveredOutboxBefore 删除一小批 delivered 且 updated_at_ms 早于 cutoffMS 的历史事件,返回本批删除行数。
|
||
DeleteDeliveredOutboxBefore(ctx context.Context, cutoffMS int64, limit int) (int64, error)
|
||
}
|
||
|
||
// RoomListStore 管理发现页、Mine 页和关系房间流读模型;它不读取 Room Cell 内存。
|
||
type RoomListStore interface {
|
||
// UpsertRoomListEntry 写入或更新房间列表读模型;失败不应破坏 Room Cell 已提交状态。
|
||
UpsertRoomListEntry(ctx context.Context, entry RoomListEntry) error
|
||
// ListRoomListEntries 按区域和 tab 查询房间列表,不访问 Room Cell 内存。
|
||
ListRoomListEntries(ctx context.Context, query RoomListQuery) ([]RoomListEntry, error)
|
||
// ListRoomListEntriesByIDs 按房间 ID 精确读取列表卡片,用于榜单展示补全。
|
||
ListRoomListEntriesByIDs(ctx context.Context, query RoomListEntriesByIDQuery) (map[string]RoomListEntry, error)
|
||
// UpsertRoomUserFeedEntry 写入用户房间关系流读模型;失败不应影响房间主链路。
|
||
UpsertRoomUserFeedEntry(ctx context.Context, entry RoomUserFeedEntry) error
|
||
// ListRoomUserFeedEntries 按用户关系流读取房间卡片,不访问 Room Cell 内存集合。
|
||
ListRoomUserFeedEntries(ctx context.Context, query RoomUserFeedQuery) ([]RoomListEntry, error)
|
||
// FollowRoom 建立或恢复用户对房间的关注关系;重复关注必须幂等。
|
||
FollowRoom(ctx context.Context, userID int64, roomID string, nowMS int64) (RoomFollowRecord, error)
|
||
// UnfollowRoom 取消用户对房间的关注关系;未关注时必须按幂等成功处理。
|
||
UnfollowRoom(ctx context.Context, userID int64, roomID string, nowMS int64) error
|
||
// IsRoomFollowed 查询 viewer 是否已经关注房间,用于房间详情个性化字段。
|
||
IsRoomFollowed(ctx context.Context, userID int64, roomID string) (bool, error)
|
||
// ListRoomFollowEntries 按当前用户关注关系读取 active 房间卡片。
|
||
ListRoomFollowEntries(ctx context.Context, query RoomFollowQuery) ([]RoomListEntry, error)
|
||
// ListRoomRelatedFeedEntries 根据 user-service 关系事实查询 active 房间卡片,不持久化关系状态。
|
||
ListRoomRelatedFeedEntries(ctx context.Context, query RoomRelatedFeedQuery) ([]RoomListEntry, error)
|
||
// ListRoomListCacheEntries 按主键小批量扫描 active 列表投影,只用于 Redis 展示读模型重建。
|
||
ListRoomListCacheEntries(ctx context.Context, query RoomListCacheEntryScanQuery) ([]RoomListEntry, error)
|
||
// ListRoomListCachePins 按主键小批量扫描 active 置顶事实,只用于 Redis 展示读模型重建。
|
||
ListRoomListCachePins(ctx context.Context, query RoomListPinScanQuery) ([]RoomListPinEntry, error)
|
||
}
|
||
|
||
// PresenceStore 管理当前房间 presence 投影;权威状态仍然来自 Room Cell 快照。
|
||
type PresenceStore interface {
|
||
// ProjectRoomPresence 用最新快照刷新用户当前房间读模型;失败不应破坏 Room Cell 已提交状态。
|
||
ProjectRoomPresence(ctx context.Context, snapshot RoomPresenceSnapshot) error
|
||
// UpsertRoomUserPresence 只刷新单个用户 active presence,服务 JoinRoom/Heartbeat 等单用户热路径。
|
||
UpsertRoomUserPresence(ctx context.Context, presence RoomPresence) error
|
||
// MarkRoomUserPresenceLeft 只把指定用户在指定房间标记为 left,避免 LeaveRoom 重新写整房间在线用户。
|
||
MarkRoomUserPresenceLeft(ctx context.Context, presence RoomPresence) error
|
||
// GetCurrentRoomPresence 查询用户当前 active 房间 presence,不扫描房间列表或快照。
|
||
GetCurrentRoomPresence(ctx context.Context, userID int64) (RoomPresence, bool, error)
|
||
// ListRoomOnlineUsers 查询房间 active 在线用户分页,不读取完整 RoomSnapshot。
|
||
ListRoomOnlineUsers(ctx context.Context, query RoomOnlineUserQuery) (RoomOnlineUserPage, error)
|
||
}
|
||
|
||
// AdminRoomStore 服务后台房间列表、详情和置顶管理;后台仍通过 room-service 访问 owner 数据。
|
||
type AdminRoomStore interface {
|
||
AdminListRooms(ctx context.Context, query AdminRoomListQuery) ([]AdminRoomListEntry, int64, error)
|
||
AdminGetRoom(ctx context.Context, roomID string, nowMS int64) (AdminRoomListEntry, bool, error)
|
||
AdminListRoomPins(ctx context.Context, query AdminRoomPinQuery) ([]AdminRoomPinEntry, int64, error)
|
||
AdminCreateRoomPin(ctx context.Context, input AdminCreateRoomPinInput) (AdminRoomPinEntry, bool, error)
|
||
AdminCancelRoomPin(ctx context.Context, pinID int64, adminID uint64, nowMS int64) (AdminRoomPinEntry, bool, error)
|
||
}
|
||
|
||
// RobotRoomStore 管理机器人房间配置、账号占用和真人房补机器人候选查询。
|
||
type RobotRoomStore interface {
|
||
ListRobotRooms(ctx context.Context, query RobotRoomListQuery) ([]RobotRoomConfig, int64, error)
|
||
GetRobotRoom(ctx context.Context, roomID string) (RobotRoomConfig, bool, error)
|
||
CreateRobotRoomConfig(ctx context.Context, input CreateRobotRoomConfigInput) (RobotRoomConfig, error)
|
||
UpdateRobotRoomStatus(ctx context.Context, roomID string, status string, nowMS int64) (RobotRoomConfig, bool, error)
|
||
OccupiedRobotUserIDs(ctx context.Context, userIDs []int64) (map[int64]bool, error)
|
||
ListActiveRobotRooms(ctx context.Context) ([]RobotRoomConfig, error)
|
||
GetHumanRoomRobotConfig(ctx context.Context) (HumanRoomRobotConfig, bool, error)
|
||
UpsertHumanRoomRobotConfig(ctx context.Context, config HumanRoomRobotConfig) (HumanRoomRobotConfig, error)
|
||
ListHumanRobotCandidateRooms(ctx context.Context, appCode string, countryCode string, maxOnline int32, fullStopOnline int32, limit int, allowedOwnerIDs []string) ([]RoomListEntry, error)
|
||
}
|
||
|
||
// RoomPresenceSnapshot 是 repository 投影接口的稳定入参,避免存储层反向依赖 protobuf。
|
||
type RoomPresenceSnapshot struct {
|
||
AppCode string
|
||
RoomID string
|
||
RoomVersion int64
|
||
RoomStatus string
|
||
Users []RoomPresence
|
||
UpdatedAtMS int64
|
||
}
|