package grpc import ( "context" userv1 "hyapp.local/api/proto/user/v1" "hyapp/pkg/xerr" cpdomain "hyapp/services/user-service/internal/domain/cp" ) // ListCPApplications 返回当前用户收到或发出的 CP/兄弟/姐妹申请。 func (s *Server) ListCPApplications(ctx context.Context, req *userv1.ListCPApplicationsRequest) (*userv1.ListCPApplicationsResponse, error) { ctx = contextWithApp(ctx, req.GetMeta()) if s.cpSvc == nil { return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "cp service is not configured")) } // gRPC 层只透传分页、方向和状态,pending 过期固化由 service/repository 统一处理。 applications, total, serverTimeMS, err := s.cpSvc.ListApplications(ctx, req.GetUserId(), req.GetDirection(), req.GetStatus(), req.GetPage(), req.GetPageSize()) if err != nil { return nil, xerr.ToGRPCError(err) } resp := &userv1.ListCPApplicationsResponse{ Applications: make([]*userv1.CPApplication, 0, len(applications)), Total: total, ServerTimeMs: serverTimeMS, } for _, application := range applications { resp.Applications = append(resp.Applications, toProtoCPApplication(application)) } return resp, nil } // AcceptCPApplication 同意申请并返回建立后的关系。 func (s *Server) AcceptCPApplication(ctx context.Context, req *userv1.AcceptCPApplicationRequest) (*userv1.AcceptCPApplicationResponse, error) { ctx = contextWithApp(ctx, req.GetMeta()) if s.cpSvc == nil { return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "cp service is not configured")) } application, relationship, err := s.cpSvc.AcceptApplication(ctx, req.GetUserId(), req.GetApplicationId()) if err != nil { return nil, xerr.ToGRPCError(err) } return &userv1.AcceptCPApplicationResponse{ Application: toProtoCPApplication(application), Relationship: toProtoCPRelationship(relationship), }, nil } // RejectCPApplication 拒绝申请;拒绝原因只进入 outbox payload,不改变关系主事实。 func (s *Server) RejectCPApplication(ctx context.Context, req *userv1.RejectCPApplicationRequest) (*userv1.RejectCPApplicationResponse, error) { ctx = contextWithApp(ctx, req.GetMeta()) if s.cpSvc == nil { return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "cp service is not configured")) } application, err := s.cpSvc.RejectApplication(ctx, req.GetUserId(), req.GetApplicationId(), req.GetReason()) if err != nil { return nil, xerr.ToGRPCError(err) } return &userv1.RejectCPApplicationResponse{Application: toProtoCPApplication(application)}, nil } // ListCPRelationships 返回用户 active 关系;当前每个用户最多同时拥有一条关系。 func (s *Server) ListCPRelationships(ctx context.Context, req *userv1.ListCPRelationshipsRequest) (*userv1.ListCPRelationshipsResponse, error) { ctx = contextWithApp(ctx, req.GetMeta()) if s.cpSvc == nil { return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "cp service is not configured")) } relationships, total, err := s.cpSvc.ListRelationships(ctx, req.GetUserId(), req.GetRelationType(), req.GetPage(), req.GetPageSize()) if err != nil { return nil, xerr.ToGRPCError(err) } resp := &userv1.ListCPRelationshipsResponse{ Relationships: make([]*userv1.CPRelationship, 0, len(relationships)), Total: total, } for _, relationship := range relationships { resp.Relationships = append(resp.Relationships, toProtoCPRelationship(relationship)) } return resp, nil } // ConsumeRoomGiftCPEvent 由 user-service 内部 MQ worker 调用,把 RoomGiftSent 转为 CP 申请或亲密值增长。 func (s *Server) ConsumeRoomGiftCPEvent(ctx context.Context, req *userv1.ConsumeRoomGiftCPEventRequest) (*userv1.ConsumeRoomGiftCPEventResponse, error) { ctx = contextWithApp(ctx, req.GetMeta()) if s.cpSvc == nil { return nil, xerr.ToGRPCError(xerr.New(xerr.Unavailable, "cp service is not configured")) } event := req.GetEvent() result, err := s.cpSvc.ConsumeGiftEvent(ctx, cpdomain.GiftEvent{ EventID: event.GetEventId(), RoomID: event.GetRoomId(), RoomVersion: event.GetRoomVersion(), OccurredAtMS: event.GetOccurredAtMs(), SenderUserID: event.GetSenderUserId(), TargetUserID: event.GetTargetUserId(), GiftID: event.GetGiftId(), GiftCount: event.GetGiftCount(), GiftValue: event.GetGiftValue(), BillingReceiptID: event.GetBillingReceiptId(), VisibleRegionID: event.GetVisibleRegionId(), CommandID: event.GetCommandId(), GiftTypeCode: event.GetGiftTypeCode(), CPRelationType: event.GetCpRelationType(), GiftName: event.GetGiftName(), GiftIconURL: event.GetGiftIconUrl(), GiftAnimationURL: event.GetGiftAnimationUrl(), }) if err != nil { return nil, xerr.ToGRPCError(err) } return &userv1.ConsumeRoomGiftCPEventResponse{ Consumed: result.Consumed, Application: toProtoCPApplication(result.Application), Relationship: toProtoCPRelationship(result.Relationship), }, nil } func toProtoCPApplication(application cpdomain.Application) *userv1.CPApplication { if application.ApplicationID == "" { return nil } return &userv1.CPApplication{ ApplicationId: application.ApplicationID, RelationType: application.RelationType, Status: application.Status, Requester: toProtoCPUserProfile(application.Requester), Target: toProtoCPUserProfile(application.Target), RoomId: application.RoomID, RoomRegionId: application.RoomRegionID, Gift: toProtoCPGiftSnapshot(application.Gift), CreatedAtMs: application.CreatedAtMS, UpdatedAtMs: application.UpdatedAtMS, ExpiresAtMs: application.ExpiresAtMS, DecidedAtMs: application.DecidedAtMS, } } func toProtoCPRelationship(relationship cpdomain.Relationship) *userv1.CPRelationship { if relationship.RelationshipID == "" { return nil } return &userv1.CPRelationship{ RelationshipId: relationship.RelationshipID, RelationType: relationship.RelationType, Status: relationship.Status, Me: toProtoCPUserProfile(relationship.Me), Partner: toProtoCPUserProfile(relationship.Partner), IntimacyValue: relationship.IntimacyValue, Level: relationship.Level, FormedAtMs: relationship.FormedAtMS, UpdatedAtMs: relationship.UpdatedAtMS, } } func toProtoCPUserProfile(profile cpdomain.UserProfile) *userv1.CPUserProfile { if profile.UserID <= 0 { return nil } return &userv1.CPUserProfile{ UserId: profile.UserID, DisplayUserId: profile.DisplayUserID, Username: profile.Username, Avatar: profile.Avatar, } } func toProtoCPGiftSnapshot(gift cpdomain.GiftSnapshot) *userv1.CPGiftSnapshot { if gift.GiftID == "" && gift.GiftName == "" { return nil } return &userv1.CPGiftSnapshot{ GiftId: gift.GiftID, GiftName: gift.GiftName, GiftIconUrl: gift.GiftIconURL, GiftAnimationUrl: gift.GiftAnimationURL, GiftCount: gift.GiftCount, GiftValue: gift.GiftValue, BillingReceiptId: gift.BillingReceiptID, } }