2026-05-11 01:40:29 +08:00

109 lines
4.8 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
import (
"context"
"time"
activityv1 "hyapp.local/api/proto/activity/v1"
"hyapp/pkg/appcode"
"hyapp/pkg/xerr"
broadcastservice "hyapp/services/activity-service/internal/service/broadcast"
)
// BroadcastServer 把 IM 播报能力暴露为内部 gRPC。
// 外部 HTTP 不直接调用这里gateway/cron/room-service 只能通过 protobuf 契约进入 activity-service。
type BroadcastServer struct {
activityv1.UnimplementedBroadcastServiceServer
activityv1.UnimplementedRoomEventConsumerServiceServer
svc *broadcastservice.Service
}
// NewBroadcastServer 创建播报和 room event 消费共用的 gRPC adapter。
func NewBroadcastServer(svc *broadcastservice.Service) *BroadcastServer {
return &BroadcastServer{svc: svc}
}
func (s *BroadcastServer) EnsureBroadcastGroups(ctx context.Context, req *activityv1.EnsureBroadcastGroupsRequest) (*activityv1.EnsureBroadcastGroupsResponse, error) {
// app_code 只从 RequestMeta 进入 context底层 repository 才能自动带上租户隔离条件。
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
count, err := s.svc.EnsureBroadcastGroups(ctx)
if err != nil {
return nil, xerr.ToGRPCError(err)
}
return &activityv1.EnsureBroadcastGroupsResponse{EnsuredCount: int32(count)}, nil
}
func (s *BroadcastServer) PublishRegionBroadcast(ctx context.Context, req *activityv1.PublishRegionBroadcastRequest) (*activityv1.PublishBroadcastResponse, error) {
// 区域播报是红包、贵重礼物等高频入口gRPC 层只做字段搬运,策略留给 service。
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
result, err := s.svc.PublishRegionBroadcast(ctx, broadcastservice.PublishInput{
EventID: req.GetEventId(),
BroadcastType: req.GetBroadcastType(),
RegionID: req.GetRegionId(),
PayloadJSON: req.GetPayloadJson(),
})
if err != nil {
return nil, xerr.ToGRPCError(err)
}
return &activityv1.PublishBroadcastResponse{EventId: result.EventID, GroupId: result.GroupID, Status: result.Status, Created: result.Created}, nil
}
func (s *BroadcastServer) PublishGlobalBroadcast(ctx context.Context, req *activityv1.PublishGlobalBroadcastRequest) (*activityv1.PublishBroadcastResponse, error) {
// 全局播报和区域播报共用返回结构,调用方通过 group_id/status/created 判断幂等结果。
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
result, err := s.svc.PublishGlobalBroadcast(ctx, broadcastservice.PublishInput{
EventID: req.GetEventId(),
BroadcastType: req.GetBroadcastType(),
PayloadJSON: req.GetPayloadJson(),
})
if err != nil {
return nil, xerr.ToGRPCError(err)
}
return &activityv1.PublishBroadcastResponse{EventId: result.EventID, GroupId: result.GroupID, Status: result.Status, Created: result.Created}, nil
}
func (s *BroadcastServer) RemoveRegionBroadcastMember(ctx context.Context, req *activityv1.RemoveRegionBroadcastMemberRequest) (*activityv1.RemoveRegionBroadcastMemberResponse, error) {
// 这里只删除 user_id 在旧区域群的成员关系,不删除区域群;群生命周期仍由 reconciler 管理。
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
groupID, removed, err := s.svc.RemoveRegionBroadcastMember(ctx, req.GetUserId(), req.GetRegionId())
if err != nil {
return nil, xerr.ToGRPCError(err)
}
return &activityv1.RemoveRegionBroadcastMemberResponse{GroupId: groupID, Removed: removed}, nil
}
func (s *BroadcastServer) ProcessBroadcastOutboxBatch(ctx context.Context, req *activityv1.CronBatchRequest) (*activityv1.ProcessBroadcastOutboxBatchResponse, error) {
// cron-service 可以显式触发一批投递;常驻 worker 也复用同一个 service 方法。
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
result, err := s.svc.ProcessPendingBroadcasts(ctx, broadcastservice.WorkerOptions{
WorkerID: req.GetWorkerId(),
BatchSize: int(req.GetBatchSize()),
LockTTL: time.Duration(req.GetLockTtlMs()) * time.Millisecond,
})
if err != nil {
return nil, xerr.ToGRPCError(err)
}
return &activityv1.ProcessBroadcastOutboxBatchResponse{
ClaimedCount: int32(result.ClaimedCount),
SuccessCount: int32(result.SuccessCount),
FailureCount: int32(result.FailureCount),
HasMore: result.HasMore,
}, nil
}
func (s *BroadcastServer) ConsumeRoomEvent(ctx context.Context, req *activityv1.ConsumeRoomEventRequest) (*activityv1.ConsumeRoomEventResponse, error) {
// room-service 只推送已提交的 outbox envelope是否播报、播给哪个群由 activity-service 判定。
ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode())
result, err := s.svc.HandleRoomEvent(ctx, req.GetEnvelope())
if err != nil {
return nil, xerr.ToGRPCError(err)
}
return &activityv1.ConsumeRoomEventResponse{
EventId: result.EventID,
Status: result.Status,
BroadcastEventId: result.BroadcastEventID,
BroadcastCreated: result.BroadcastCreated,
}, nil
}