package grpc import ( "context" activityv1 "hyapp.local/api/proto/activity/v1" "hyapp/pkg/appcode" "hyapp/pkg/xerr" messagedomain "hyapp/services/activity-service/internal/domain/message" messageservice "hyapp/services/activity-service/internal/service/message" ) // MessageServer adapts the message inbox owner to gRPC without mixing it into activity status APIs. type MessageServer struct { activityv1.UnimplementedMessageInboxServiceServer svc *messageservice.Service } // NewMessageServer creates the gRPC adapter for system/activity inbox RPCs. func NewMessageServer(svc *messageservice.Service) *MessageServer { return &MessageServer{svc: svc} } func (s *MessageServer) ListMessageTabs(ctx context.Context, req *activityv1.ListMessageTabsRequest) (*activityv1.ListMessageTabsResponse, error) { ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode()) sections, err := s.svc.ListMessageTabs(ctx, req.GetUserId()) if err != nil { return nil, xerr.ToGRPCError(err) } result := make([]*activityv1.MessageTabSection, 0, len(sections)) for _, section := range sections { result = append(result, &activityv1.MessageTabSection{ Section: section.Section, Title: section.Title, UnreadCount: section.UnreadCount, Source: section.Source, }) } return &activityv1.ListMessageTabsResponse{Sections: result}, nil } func (s *MessageServer) ListInboxMessages(ctx context.Context, req *activityv1.ListInboxMessagesRequest) (*activityv1.ListInboxMessagesResponse, error) { ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode()) messages, nextPageToken, err := s.svc.ListInboxMessages(ctx, req.GetUserId(), req.GetSection(), req.GetPageSize(), req.GetPageToken()) if err != nil { return nil, xerr.ToGRPCError(err) } items := make([]*activityv1.InboxMessage, 0, len(messages)) for _, message := range messages { items = append(items, inboxMessageProto(message)) } return &activityv1.ListInboxMessagesResponse{Section: req.GetSection(), Items: items, NextPageToken: nextPageToken}, nil } func (s *MessageServer) MarkInboxMessageRead(ctx context.Context, req *activityv1.MarkInboxMessageReadRequest) (*activityv1.MarkInboxMessageReadResponse, error) { ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode()) message, err := s.svc.MarkInboxMessageRead(ctx, req.GetUserId(), req.GetMessageId()) if err != nil { return nil, xerr.ToGRPCError(err) } return &activityv1.MarkInboxMessageReadResponse{MessageId: message.MessageID, Read: true, ReadAtMs: message.ReadAtMS}, nil } func (s *MessageServer) MarkInboxSectionRead(ctx context.Context, req *activityv1.MarkInboxSectionReadRequest) (*activityv1.MarkInboxSectionReadResponse, error) { ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode()) count, err := s.svc.MarkInboxSectionRead(ctx, req.GetUserId(), req.GetSection()) if err != nil { return nil, xerr.ToGRPCError(err) } return &activityv1.MarkInboxSectionReadResponse{Section: req.GetSection(), ReadCount: count}, nil } func (s *MessageServer) DeleteInboxMessage(ctx context.Context, req *activityv1.DeleteInboxMessageRequest) (*activityv1.DeleteInboxMessageResponse, error) { ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode()) if err := s.svc.DeleteInboxMessage(ctx, req.GetUserId(), req.GetMessageId()); err != nil { return nil, xerr.ToGRPCError(err) } return &activityv1.DeleteInboxMessageResponse{MessageId: req.GetMessageId(), Deleted: true}, nil } func (s *MessageServer) CreateInboxMessage(ctx context.Context, req *activityv1.CreateInboxMessageRequest) (*activityv1.CreateInboxMessageResponse, error) { ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode()) message, created, err := s.svc.CreateInboxMessage(ctx, messagedomain.CreateInput{ TargetUserID: req.GetTargetUserId(), Producer: req.GetProducer(), ProducerEventID: req.GetProducerEventId(), ProducerEventType: req.GetProducerEventType(), MessageType: req.GetMessageType(), AggregateType: req.GetAggregateType(), AggregateID: req.GetAggregateId(), TemplateID: req.GetTemplateId(), TemplateVersion: req.GetTemplateVersion(), Title: req.GetTitle(), Summary: req.GetSummary(), Body: req.GetBody(), IconURL: req.GetIconUrl(), ImageURL: req.GetImageUrl(), ActionType: req.GetActionType(), ActionParam: req.GetActionParam(), Priority: req.GetPriority(), SentAtMS: req.GetSentAtMs(), ExpireAtMS: req.GetExpireAtMs(), MetadataJSON: req.GetMetadataJson(), }) if err != nil { return nil, xerr.ToGRPCError(err) } return &activityv1.CreateInboxMessageResponse{MessageId: message.MessageID, Created: created}, nil } func (s *MessageServer) CreateFanoutJob(ctx context.Context, req *activityv1.CreateFanoutJobRequest) (*activityv1.CreateFanoutJobResponse, error) { ctx = appcode.WithContext(ctx, req.GetMeta().GetAppCode()) job, created, err := s.svc.CreateFanoutJob(ctx, messagedomain.CreateFanoutInput{ CommandID: req.GetCommandId(), MessageType: req.GetMessageType(), TargetScope: req.GetTargetScope(), TargetFilterJSON: req.GetTargetFilterJson(), TemplateSnapshotJSON: req.GetTemplateSnapshotJson(), BatchSize: req.GetBatchSize(), CreatedBy: req.GetCreatedBy(), }) if err != nil { return nil, xerr.ToGRPCError(err) } return &activityv1.CreateFanoutJobResponse{JobId: job.JobID, Status: job.Status, Created: created}, nil } func inboxMessageProto(message messagedomain.InboxMessage) *activityv1.InboxMessage { return &activityv1.InboxMessage{ MessageId: message.MessageID, Section: message.MessageType, Title: message.Title, Summary: message.Summary, Body: message.Body, IconUrl: message.IconURL, ImageUrl: message.ImageURL, ActionType: message.ActionType, ActionParam: message.ActionParam, Read: message.Read(), SentAtMs: message.SentAtMS, } }