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 IMapper mapper; private readonly IGroupMemberIntegrationService memberService; private readonly IContactIntegrationService contactService; private readonly SquenceService squenceService; public MessageService(IMessageReposity reposity, IMapper mapper, IGroupMemberIntegrationService memberService, IContactIntegrationService contactService, SquenceService squenceService ) { this.reposity = reposity; 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); } // 2. 处理引用逻辑(如果传了 QuoteMessageId) QuoteInfo? quote = null; if (command.QuoteMessageId.HasValue) { 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); 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(); } } }