using AutoMapper; using IM.Commons; using MessageService.Domain.Enums; using MessageService.Domain.IReposities; using MessageService.Domain.KeyObjects; using MessageService.Domain.Tools; using MessageService.WebApi.Application.Dtos; using MessageService.WebApi.Application.IntegrationServices; namespace MessageService.WebApi.Application.Message { public class MessageService { private readonly IMessageReposity reposity; private readonly IConversationReposity conversationReposity; private readonly IMapper mapper; private readonly IGroupMemberIntegrationService memberService; private readonly IContactIntegrationService contactService; private readonly SquenceService squenceService; public MessageService(IMessageReposity reposity, IConversationReposity conversationReposity, IMapper mapper, IGroupMemberIntegrationService memberService, IContactIntegrationService contactService, SquenceService squenceService) { this.reposity = reposity; this.conversationReposity = conversationReposity; this.mapper = mapper; this.memberService = memberService; this.contactService = contactService; this.squenceService = squenceService; } public async Task> SendMsgAsync(SendMsgCommand command) { if (command.ChatType == Domain.Enums.ChatType.PRIVATE) { bool passed = await contactService.CheckContactAsync(command.SenderId, command.TargetId); if (!passed) return Result.Fail(ResultCode.FRIEND_RELATION_NOT_FOUND); } else { bool passed = await memberService.CheckGroupMemberAsync(command.SenderId, command.TargetId); if (!passed) return Result.Fail(ResultCode.NO_GROUP_PERMISSION); } var ctx = new MessageCreateContext(command.ChatType, command.ClientMsgId, command.SenderId, command.TargetId); var streamKey = command.ChatType == ChatType.GROUP ? StreamKeyBuilder.Group(ctx.TargetId) : StreamKeyBuilder.Private(ctx.SenderId, ctx.TargetId); long sequenceId = await squenceService.GetNextSquenceIdAsync(streamKey); Domain.Entities.Message message = command.MsgType switch { MessageType.Text => Domain.Entities.Message.BuildTxt(ctx, command.Text!, sequenceId), MessageType.Image => Domain.Entities.Message.BuildImg(ctx, command.Url!, command.Width ?? 0, command.Height ?? 0, command.Thumb!, sequenceId), MessageType.Video => Domain.Entities.Message.BuildVideo(ctx, command.Url!, command.Width ?? 0, command.Height ?? 0, command.Thumb!, sequenceId), MessageType.Voice => Domain.Entities.Message.BuildVoice(ctx, command.Url!, command.Duration ?? 0, sequenceId), _ => null }; if (message == null) { return Result.Fail(ResultCode.UNSUPPORTED_MESSAGE_TYPE); } if (command.QuoteMessageId.HasValue) { // 2. 处理引用逻辑(如果传了 QuoteMessageId) QuoteInfo? quote = null; var originMsg = await reposity.FindByIdAsync(command.QuoteMessageId.Value); if (originMsg != null) { quote = new QuoteInfo { MessageId = originMsg.Id, SenderId = originMsg.SenderId, SenderName = "未知昵称", // 这里建议从缓存或DB获取发送者昵称 MessageType = originMsg.MsgType, Preview = originMsg.Content.Fallback }; } message.WithQuote(quote); } message.Send(); reposity.Create(message); return Result.Success(mapper.Map(message)); } public async Task> WithDrawMsgAsync(Guid msgId, Guid senderId) { var msg = await reposity.FindByIdAsync(msgId); if (msg == null || msg.SenderId != senderId) { return Result.Fail(ResultCode.MESSAGE_NOT_FOUND); } msg.Withdraw(); return Result.Success(); } public async Task> GetMessagesAsync(GetMessageCommand command) { var conversation = await conversationReposity.FindByIdAsync(command.conversationId); if(conversation is null || conversation.UserId != command.userId) { return Result.Fail(ResultCode.PERMISSION_DENIED); } var messages = await reposity.GetAsync(conversation.StreamKey, command.cusor, command.direction, command.limit); return Result.Success(new GetMessagesResponse(mapper.Map>(messages.messages.ToList()),messages.hasMore)); } } }