添加项目文件。
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
using AutoMapper;
|
||||
using MessageService.Domain.KeyObjects;
|
||||
using MessageService.WebApi.Application.Dtos;
|
||||
|
||||
namespace MessageService.WebApi.Application.Message
|
||||
{
|
||||
public class MessageMapperConfig : Profile
|
||||
{
|
||||
public MessageMapperConfig()
|
||||
{
|
||||
// 1. 配置 QuoteInfo -> QuoteInfoResponse
|
||||
CreateMap<QuoteInfo, QuoteInfoResponse>();
|
||||
|
||||
// 2. 配置 MessageContent -> MessageContentResponse
|
||||
CreateMap<MessageContent, MessageContentResponse>()
|
||||
// 关键点:Body 是 object,由于我们在实体里写了 Body 计算属性
|
||||
// AutoMapper 默认会识别到同名的 Body 属性并进行映射
|
||||
// 如果你想显式指定逻辑,可以取消下面这行的注释:
|
||||
// .ForMember(dest => dest.Body, opt => opt.MapFrom(src => src.Body))
|
||||
.ForMember(dest => dest.Ext, opt => opt.MapFrom(src => src.Ext))
|
||||
.ForMember(dest => dest.Quote, opt => opt.MapFrom(src =>
|
||||
src.Quote.MessageId == Guid.Empty ? null : src.Quote));
|
||||
|
||||
// 3. 配置 Message -> MessageResponse
|
||||
CreateMap<Domain.Entities.Message, MessageResponse>()
|
||||
// 映射审计字段中的创建时间
|
||||
.ForMember(dest => dest.CreationTime, opt => opt.MapFrom(src => src.CreationTime))
|
||||
// 嵌套映射 Content
|
||||
.ForMember(dest => dest.Content, opt => opt.MapFrom(src => src.Content));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
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<Result<MessageResponse>> SendMsgAsync(SendMsgCommand command)
|
||||
{
|
||||
if (command.ChatType == Domain.Enums.ChatType.PRIVATE)
|
||||
{
|
||||
bool passed = await contactService.CheckContactAsync(command.SenderId, command.TargetId);
|
||||
if (!passed)
|
||||
return Result.Fail<MessageResponse>(ResultCode.FRIEND_RELATION_NOT_FOUND);
|
||||
}
|
||||
else
|
||||
{
|
||||
bool passed = await memberService.CheckGroupMemberAsync(command.SenderId, command.TargetId);
|
||||
if (!passed)
|
||||
return Result.Fail<MessageResponse>(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<MessageResponse>(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<MessageResponse>(message));
|
||||
|
||||
}
|
||||
|
||||
public async Task<Result<object>> WithDrawMsgAsync(Guid msgId, Guid senderId)
|
||||
{
|
||||
var msg = await reposity.FindByIdAsync(msgId);
|
||||
if (msg == null || msg.SenderId != senderId)
|
||||
{
|
||||
return Result.Fail<object>(ResultCode.MESSAGE_NOT_FOUND);
|
||||
}
|
||||
|
||||
msg.Withdraw();
|
||||
|
||||
return Result.Success();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using MessageService.Domain.Enums;
|
||||
|
||||
namespace MessageService.WebApi.Application.Message
|
||||
{
|
||||
public record SendMsgCommand
|
||||
{
|
||||
// 核心区别:Command 必须包含 SenderId,这是从后端 Token 解析出来的
|
||||
public Guid SenderId { get; init; }
|
||||
|
||||
public Guid TargetId { get; init; }
|
||||
public ChatType ChatType { get; init; }
|
||||
public MessageType MsgType { get; init; }
|
||||
public Guid ClientMsgId { get; init; }
|
||||
|
||||
public Guid? QuoteMessageId { get; init; }
|
||||
public Dictionary<string, string>? Ext { get; init; }
|
||||
|
||||
// 拍扁后的参数,方便 Service 直接调用工厂方法
|
||||
public string? Text { get; init; }
|
||||
public string? Url { get; init; }
|
||||
public int? Width { get; init; }
|
||||
public int? Height { get; init; }
|
||||
public string? Thumb { get; init; }
|
||||
public int? Duration { get; init; }
|
||||
|
||||
public SendMsgCommand(Guid senderId, Guid targetId, ChatType chatType, MessageType msgType, Guid clientMsgId, Guid? quoteMessageId, Dictionary<string, string>? ext, string? text, string? url, int? width, int? height, string? thumb, int? duration)
|
||||
{
|
||||
SenderId = senderId;
|
||||
TargetId = targetId;
|
||||
ChatType = chatType;
|
||||
MsgType = msgType;
|
||||
ClientMsgId = clientMsgId;
|
||||
QuoteMessageId = quoteMessageId;
|
||||
Ext = ext;
|
||||
Text = text;
|
||||
Url = url;
|
||||
Width = width;
|
||||
Height = height;
|
||||
Thumb = thumb;
|
||||
Duration = duration;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user