using IM.Commons.IntegrationEvents; using IM.DomainCommons; using MessageService.Domain.Enums; using MessageService.Domain.Events; using MessageService.Domain.KeyObjects; using MessageService.Domain.Tools; using System.Text.Json; namespace MessageService.Domain.Entities { public class Message : AggregateRootEntity { /// /// 聊天类型 /// (0:私聊,1:群聊) /// public ChatType ChatType { get; private set; } /// /// 消息类型 /// (0:文本,1:图片,2:语音,3:视频,4:文件,5:语音聊天,6:视频聊天) /// public MessageType MsgType { get; private set; } public Guid ClientMsgId { get; private set; } /// /// 消息内容 /// public MessageContent Content { get; private set; } = null!; /// /// 发送者 /// public Guid SenderId { get; private set; } /// /// 接收者(私聊为用户ID,群聊为群聊ID) /// public Guid TargetId { get; private set; } /// /// 消息状态(0:已发送,1:已撤回) /// public MessageState State { get; private set; } = MessageState.Sent; /// /// 消息推送唯一标识符 /// public string StreamKey { get; private set; } /// /// 消息排序标识 /// public long SequenceId { get; private set; } private Message() { } private Message(MessageCreateContext ctx, long sequenceId, MessageType messageType , MessageContent content ) { ChatType = ctx.ChatType; SenderId = ctx.SenderId; ClientMsgId = ctx.ClientMsgId; TargetId = ctx.TargetId; SequenceId = sequenceId; MsgType = messageType; StreamKey = ChatType == ChatType.GROUP ? StreamKeyBuilder.Group(ctx.TargetId) : StreamKeyBuilder.Private(ctx.SenderId, ctx.TargetId); Content = content; } /// /// 文本消息 /// /// /// 文本内容 /// /// public static Message BuildTxt(MessageCreateContext ctx, string text, long sequenceId) { var content = new MessageContent(text, new TextBody(text)); return new Message(ctx, sequenceId, MessageType.Text, content); } /// /// 图片消息 /// /// /// 相对路径 /// 宽度 /// 高度 /// 预览图 /// /// public static Message BuildImg(MessageCreateContext ctx, string? url, int width, int height, string thumb, long sequenceId, Guid? fileId = null) { var content = new MessageContent("[图片]", new ImageBody(url, width, height, thumb, fileId)); return new Message(ctx, sequenceId, MessageType.Image, content); } /// /// 视频消息 /// /// /// /// /// /// /// /// public static Message BuildVideo(MessageCreateContext ctx, string? url, int width, int height, string thumb, long sequenceId, Guid? fileId = null) { var content = new MessageContent("[视频]", new VideoBody(url, width, height, thumb, fileId)); return new Message(ctx, sequenceId, MessageType.Video, content); } /// /// 语音消息 /// /// /// /// 持续时间 /// /// public static Message BuildVoice(MessageCreateContext ctx, string? url, int duration, long sequenceId, Guid? fileId = null) { var content = new MessageContent("[音频]", new VoiceBody(url, duration, fileId)); return new Message(ctx, sequenceId, MessageType.Voice, content); } /// /// 文件 /// /// /// 相对路径 /// 文件名 /// 文件大小(KB) /// 文件格式 /// /// public static Message BuildFile(MessageCreateContext ctx, Guid fileId, string? url, string name, long size, string format, long sequenceId) { var content = new MessageContent("[文件]", new FileBody(fileId, url, name, size, format)); return new Message(ctx, sequenceId, MessageType.File, content); } /// /// 添加扩展字段 /// /// 字段名 /// 值 /// public Message WithExt(string key, string value) { var dic = new Dictionary(); dic.Add(key, value); Content.RawExt = JsonSerializer.Serialize(dic); return this; } /// /// 添加消息引用 /// /// /// public Message WithQuote(QuoteInfo quote) { this.Content.Quote = quote; return this; } /// /// 完成消息 /// public void Send() { AddDomainEvent(new MessageCreatedDomainEvent(this)); } public void Withdraw() { if (State != MessageState.Sent) { throw new DomainException("消息不可撤回"); } State = MessageState.Withdrwan; AddDomainEvent(new MessageWithdrawDomainEvent(this)); } public MsgCreatedEvent ToIntegrationEvent() { return new MsgCreatedEvent { Id = this.Id, ClientId = this.ClientMsgId, // 假设你有存发送端的设备ID ChatType = this.ChatType.ToString(), // 比如 "private" 或 "group" MsgType = this.MsgType.ToString() ?? MessageType.Text.ToString(), // 动态获取类型名,或从 Content 里的定义拿 SenderId = this.SenderId, TargetId = this.TargetId, State = State.ToString(), StreamKey = this.StreamKey, SequenceId = this.SequenceId, // 核心载荷:利用计算属性触发反序列化,打包成 DTO Content = new MsgContent( this.Content.Fallback, this.Content.Body, // 触发实体内部的反序列化逻辑 this.Content.Ext, this.Content.Quote != null ? new QuoteInfoDto( this.Content.Quote.MessageId, this.Content.Quote.SenderId, this.Content.Quote.SenderName, this.Content.Quote.MessageType.ToString(), this.Content.Quote.Preview ) : null ) }; } } }