2026-05-11 19:26:01 +08:00

308 lines
14 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 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
// HostUserID 是主持人,恢复无快照房间时用于重建管理员集合。
HostUserID int64
// SeatCount 是初始麦位数量,只有无快照恢复时需要它重建麦位。
SeatCount int32
// Mode 是房间模式,当前作为元数据持久化。
Mode string
// Status 是房间基础状态,快照缺失时用于恢复 RoomState.Status。
Status 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
// RoomStatus 非空时同步更新 rooms 和 room_list_entries 的生命周期状态。
RoomStatus string
// RoomSeatCount 非 nil 时同步更新 rooms 元数据中的麦位总数。
RoomSeatCount *int32
}
// 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
// OwnerUserID 是房间所有者,用于卡片展示和运营排查。
OwnerUserID int64
// HostUserID 是当前主持人,用于卡片展示。
HostUserID int64
// Title 是卡片标题;空值由客户端或后续资料聚合兜底。
Title string
// CoverURL 是卡片封面;空值表示没有单独封面。
CoverURL string
// Mode 是房间模式,来自 RoomState/RoomMeta。
Mode string
// Status 是房间生命周期状态,列表默认只查 active。
Status string
// 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
}
// RoomSeatConfig 是后台房间配置里控制创建/修改房间座位数的低频配置。
type RoomSeatConfig struct {
// AppCode 是配置所属 App。
AppCode string
// AllowedSeatCounts 是当前 App 允许客户端使用的麦位总数。
AllowedSeatCounts []int32
// DefaultSeatCount 是 CreateRoom 未传 seat_count 时使用的默认麦位总数。
DefaultSeatCount int32
// UpdatedAtMS 是配置最后更新时间,主要用于后台展示和排障。
UpdatedAtMS 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
// LastSeenAtMS 是用户在 Room Cell 内的最后业务心跳时间。
LastSeenAtMS int64
// UpdatedAtMS 是投影写入时间。
UpdatedAtMS int64
}
// RoomListQuery 是 room-service 房间列表读模型查询条件。
type RoomListQuery struct {
// AppCode 是列表查询所属 App通常来自 gateway RequestMeta。
AppCode string
// VisibleRegionID 是服务端解析出的用户区域,客户端不能伪造。
VisibleRegionID int64
// Tab 只允许 hot/new决定公共发现列表排序字段。
Tab string
// OwnerUserID 保留给内部定向读模型;公开 Mine 顶部卡片走 GetMyRoom。
OwnerUserID int64
// Query 非空时按 room_id 或 title 做包含匹配。
Query string
// Limit 是实际查询数量service 层会限制最大值。
Limit int
// CursorSortScore 是 hot tab 的游标 score。
CursorSortScore int64
// CursorCreatedAtMS 是 new tab 的游标创建时间。
CursorCreatedAtMS int64
// CursorUpdatedAtMS 是用户关系 feed tab 的游标更新时间。
CursorUpdatedAtMS int64
// CursorRoomID 是同分或同时间下的稳定翻页边界。
CursorRoomID 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
}
// 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 在首版需要的全部持久化读写。
type Repository 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)
// 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
// GetRoomSeatConfig 读取后台配置的房间座位数规则;不存在时 service 层使用内置默认值。
GetRoomSeatConfig(ctx context.Context) (RoomSeatConfig, bool, error)
// UpsertRoomSeatConfig 写入房间座位数配置,供本地验证和后台配置共享同一张表。
UpsertRoomSeatConfig(ctx context.Context, config RoomSeatConfig) error
// ListCommandsAfter 读取快照版本之后的命令,恢复时按版本顺序回放。
ListCommandsAfter(ctx context.Context, roomID string, roomVersion int64) ([]CommandRecord, error)
// SaveSnapshot 保存最新房间快照,允许覆盖较低版本号快照但不能倒退。
SaveSnapshot(ctx context.Context, snapshot SnapshotRecord) error
// GetLatestSnapshot 读取当前最新快照,恢复时优先使用它减少回放成本。
GetLatestSnapshot(ctx context.Context, roomID string) (SnapshotRecord, bool, error)
// 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
// MarkOutboxFailed 记录一次投递失败并转为 retryable 状态等待重试。
MarkOutboxFailed(ctx context.Context, eventID string, lastErr string) error
// UpsertRoomListEntry 写入或更新房间列表读模型;失败不应破坏 Room Cell 已提交状态。
UpsertRoomListEntry(ctx context.Context, entry RoomListEntry) error
// ListRoomListEntries 按区域和 tab 查询房间列表,不访问 Room Cell 内存。
ListRoomListEntries(ctx context.Context, query RoomListQuery) ([]RoomListEntry, error)
// UpsertRoomUserFeedEntry 写入用户房间关系流读模型;失败不应影响房间主链路。
UpsertRoomUserFeedEntry(ctx context.Context, entry RoomUserFeedEntry) error
// ListRoomUserFeedEntries 按用户关系流读取房间卡片,不访问 Room Cell 内存集合。
ListRoomUserFeedEntries(ctx context.Context, query RoomUserFeedQuery) ([]RoomListEntry, error)
// ListRoomRelatedFeedEntries 根据 user-service 关系事实查询 active 房间卡片,不持久化关系状态。
ListRoomRelatedFeedEntries(ctx context.Context, query RoomRelatedFeedQuery) ([]RoomListEntry, error)
// ProjectRoomPresence 用最新快照刷新用户当前房间读模型;失败不应破坏 Room Cell 已提交状态。
ProjectRoomPresence(ctx context.Context, snapshot RoomPresenceSnapshot) error
// GetCurrentRoomPresence 查询用户当前 active 房间 presence不扫描房间列表或快照。
GetCurrentRoomPresence(ctx context.Context, userID int64) (RoomPresence, bool, error)
}
// RoomPresenceSnapshot 是 repository 投影接口的稳定入参,避免存储层反向依赖 protobuf。
type RoomPresenceSnapshot struct {
AppCode string
RoomID string
RoomVersion int64
RoomStatus string
Users []RoomPresence
UpdatedAtMS int64
}