2026-04-30 02:30:32 +08:00

149 lines
6.7 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 grpc 将 room-service 领域服务适配成 protobuf gRPC 接口。
package grpc
import (
"context"
roomv1 "hyapp/api/proto/room/v1"
"hyapp/pkg/xerr"
roomservice "hyapp/services/room-service/internal/room/service"
)
// Server 把 room-service 领域实现挂到 gRPC 接口上。
type Server struct {
// UnimplementedRoomCommandServiceServer 提供未实现 RPC 的标准 gRPC 返回。
roomv1.UnimplementedRoomCommandServiceServer
// UnimplementedRoomGuardServiceServer 提供守卫服务未实现 RPC 的标准 gRPC 返回。
roomv1.UnimplementedRoomGuardServiceServer
// UnimplementedRoomQueryServiceServer 提供查询服务未实现 RPC 的标准 gRPC 返回。
roomv1.UnimplementedRoomQueryServiceServer
// svc 是领域服务入口gRPC 层不保存任何房间状态。
svc *roomservice.Service
}
// NewServer 创建一个可注册到 gRPC 的 room server。
func NewServer(svc *roomservice.Service) *Server {
return &Server{svc: svc}
}
// mapServiceResult 把领域错误固定转换为 gRPC status + ErrorInfo.reason。
// gateway 只认识传输层 gRPC 错误;如果这里直接透传 *xerr.Errorgrpc-go 会降级成 Unknown
// gateway 就无法恢复 INVALID_ARGUMENT/NOT_FOUND 等业务 reason最终只能错误地返回 INTERNAL_ERROR。
func mapServiceResult[T any](result T, err error) (T, error) {
if err != nil {
var zero T
return zero, xerr.ToGRPCError(err)
}
return result, nil
}
// CreateRoom 代理到领域服务。
func (s *Server) CreateRoom(ctx context.Context, req *roomv1.CreateRoomRequest) (*roomv1.CreateRoomResponse, error) {
// 创建房间会获取 Redis lease、写 MySQL meta/command/outbox/snapshot并安装本地 Cell。
return mapServiceResult(s.svc.CreateRoom(ctx, req))
}
// JoinRoom 代理到领域服务。
func (s *Server) JoinRoom(ctx context.Context, req *roomv1.JoinRoomRequest) (*roomv1.JoinRoomResponse, error) {
// JoinRoom 只维护 room-service presence真实消息连接由腾讯云 IM SDK 处理。
return mapServiceResult(s.svc.JoinRoom(ctx, req))
}
// LeaveRoom 代理到领域服务。
func (s *Server) LeaveRoom(ctx context.Context, req *roomv1.LeaveRoomRequest) (*roomv1.LeaveRoomResponse, error) {
// LeaveRoom 不直接操作腾讯云 IM 连接,只修改房间业务态。
return mapServiceResult(s.svc.LeaveRoom(ctx, req))
}
// MicUp 代理到领域服务。
func (s *Server) MicUp(ctx context.Context, req *roomv1.MicUpRequest) (*roomv1.MicUpResponse, error) {
// 麦位修改由 Room Cell 串行执行gRPC 层不做状态判断。
return mapServiceResult(s.svc.MicUp(ctx, req))
}
// MicDown 代理到领域服务。
func (s *Server) MicDown(ctx context.Context, req *roomv1.MicDownRequest) (*roomv1.MicDownResponse, error) {
// 下麦结果会进入 command log 和 outbox失败不产生部分状态。
return mapServiceResult(s.svc.MicDown(ctx, req))
}
// ChangeMicSeat 代理到领域服务。
func (s *Server) ChangeMicSeat(ctx context.Context, req *roomv1.ChangeMicSeatRequest) (*roomv1.ChangeMicSeatResponse, error) {
// 换位在领域层原子修改源麦位和目标麦位。
return mapServiceResult(s.svc.ChangeMicSeat(ctx, req))
}
// ConfirmMicPublishing 代理到领域服务。
func (s *Server) ConfirmMicPublishing(ctx context.Context, req *roomv1.ConfirmMicPublishingRequest) (*roomv1.ConfirmMicPublishingResponse, error) {
// 发流确认必须进入 Room Cell 串行状态机,避免旧 RTC 事件覆盖新 mic_session。
return mapServiceResult(s.svc.ConfirmMicPublishing(ctx, req))
}
// SetMicSeatLock 代理到领域服务。
func (s *Server) SetMicSeatLock(ctx context.Context, req *roomv1.SetMicSeatLockRequest) (*roomv1.SetMicSeatLockResponse, error) {
// 锁麦权限和目标麦位状态由 Room Cell 判定。
return mapServiceResult(s.svc.SetMicSeatLock(ctx, req))
}
// SetChatEnabled 代理到领域服务。
func (s *Server) SetChatEnabled(ctx context.Context, req *roomv1.SetChatEnabledRequest) (*roomv1.SetChatEnabledResponse, error) {
// 公屏开关是 room-service 发言守卫的权威状态。
return mapServiceResult(s.svc.SetChatEnabled(ctx, req))
}
// SetRoomAdmin 代理到领域服务。
func (s *Server) SetRoomAdmin(ctx context.Context, req *roomv1.SetRoomAdminRequest) (*roomv1.SetRoomAdminResponse, error) {
// 管理员集合只能由 room-service 权限矩阵修改。
return mapServiceResult(s.svc.SetRoomAdmin(ctx, req))
}
// TransferRoomHost 代理到领域服务。
func (s *Server) TransferRoomHost(ctx context.Context, req *roomv1.TransferRoomHostRequest) (*roomv1.TransferRoomHostResponse, error) {
// 主持人转移由 Room Cell 串行提交,并进入 command log/outbox。
return mapServiceResult(s.svc.TransferRoomHost(ctx, req))
}
// MuteUser 代理到领域服务。
func (s *Server) MuteUser(ctx context.Context, req *roomv1.MuteUserRequest) (*roomv1.MuteUserResponse, error) {
// 禁言状态是腾讯云 IM 发言回调的权威来源。
return mapServiceResult(s.svc.MuteUser(ctx, req))
}
// KickUser 代理到领域服务。
func (s *Server) KickUser(ctx context.Context, req *roomv1.KickUserRequest) (*roomv1.KickUserResponse, error) {
// 踢人会修改 presence、ban 集合和麦位占用。
return mapServiceResult(s.svc.KickUser(ctx, req))
}
// UnbanUser 代理到领域服务。
func (s *Server) UnbanUser(ctx context.Context, req *roomv1.UnbanUserRequest) (*roomv1.UnbanUserResponse, error) {
// 解封只解除 ban不恢复 presence、管理员身份或麦位。
return mapServiceResult(s.svc.UnbanUser(ctx, req))
}
// SendGift 代理到领域服务。
func (s *Server) SendGift(ctx context.Context, req *roomv1.SendGiftRequest) (*roomv1.SendGiftResponse, error) {
// SendGift 先同步扣费,成功后才更新房间热度和本地榜。
return mapServiceResult(s.svc.SendGift(ctx, req))
}
// CheckSpeakPermission 代理到领域服务。
func (s *Server) CheckSpeakPermission(ctx context.Context, req *roomv1.CheckSpeakPermissionRequest) (*roomv1.CheckSpeakPermissionResponse, error) {
// 外部 IM 发公屏前调用该守卫,避免复制禁言和房间状态规则。
return mapServiceResult(s.svc.CheckSpeakPermission(ctx, req))
}
// VerifyRoomPresence 代理到领域服务。
func (s *Server) VerifyRoomPresence(ctx context.Context, req *roomv1.VerifyRoomPresenceRequest) (*roomv1.VerifyRoomPresenceResponse, error) {
// 外部 IM 进群前调用该守卫,防止未进房或被踢用户收消息。
return mapServiceResult(s.svc.VerifyRoomPresence(ctx, req))
}
// ListRooms 代理到 room-service 列表读模型。
func (s *Server) ListRooms(ctx context.Context, req *roomv1.ListRoomsRequest) (*roomv1.ListRoomsResponse, error) {
// 列表查询只读 MySQL 投影,不扫描 Room Cell 内存集合。
return mapServiceResult(s.svc.ListRooms(ctx, req))
}