using MediatR; using Microsoft.AspNetCore.SignalR; using Knot.Modules.Chats.Domain; using Knot.Modules.Chats.Infrastructure.SignalR; using Knot.Shared.Kernel; namespace Knot.Modules.Chats.Infrastructure.Handlers; /// /// Обработчик доменного события отправки сообщения. /// Отправляет уведомление через SignalR всем участникам чата. /// public sealed class MessageSentDomainEventHandler : INotificationHandler { private readonly IHubContext _hubContext; private readonly IMessageRepository _messageRepository; private readonly IUserDisplayNameProvider _displayNameProvider; public MessageSentDomainEventHandler( IHubContext hubContext, IMessageRepository messageRepository, IUserDisplayNameProvider displayNameProvider) { _hubContext = hubContext; _messageRepository = messageRepository; _displayNameProvider = displayNameProvider; } public async Task Handle(MessageSentDomainEvent notification, CancellationToken cancellationToken) { var message = await _messageRepository.GetByIdAsync(notification.MessageId, cancellationToken); if (message is null) { return; } var userInfo = await _displayNameProvider.GetUserInfoAsync(message.SenderId, cancellationToken); var senderObj = userInfo != null ? new { Id = userInfo.Id, Username = userInfo.Username, DisplayName = userInfo.DisplayName, Avatar = userInfo.Avatar } : new { Id = message.SenderId, Username = "unknown", DisplayName = "Unknown", Avatar = (string?)null }; // Fetch forwarded from info if exists object? forwardedFromObj = null; if (message.ForwardedFromId.HasValue) { var fwdUserInfo = await _displayNameProvider.GetUserInfoAsync(message.ForwardedFromId.Value, cancellationToken); forwardedFromObj = fwdUserInfo != null ? new { Id = fwdUserInfo.Id, Username = fwdUserInfo.Username, DisplayName = fwdUserInfo.DisplayName, Avatar = fwdUserInfo.Avatar } : new { Id = message.ForwardedFromId.Value, Username = "unknown", DisplayName = "Unknown", Avatar = (string?)null }; } // Fetch reply info if exists object? replyToObj = null; if (message.ReplyToId.HasValue) { var replyMsg = await _messageRepository.GetByIdAsync(message.ReplyToId.Value, cancellationToken); if (replyMsg != null) { var replySenderInfo = await _displayNameProvider.GetUserInfoAsync(replyMsg.SenderId, cancellationToken); replyToObj = new { Id = replyMsg.Id, Content = replyMsg.Content, Quote = message.Quote, media = replyMsg.Media.Select(rm => new { rm.Id, rm.Type, rm.Url }).ToList(), Sender = replySenderInfo != null ? new { Id = replySenderInfo.Id, Username = replySenderInfo.Username, DisplayName = replySenderInfo.DisplayName } : new { Id = replyMsg.SenderId, Username = "unknown", DisplayName = "Unknown" } }; } } // Отправляем сообщение в "комнату" чата. await _hubContext.Clients.Group(notification.ChatId.ToString()) .SendAsync("new_message", new { id = message.Id, chatId = message.ChatId, senderId = message.SenderId, content = message.Content, type = message.Type, createdAt = message.CreatedAt, forwardedFromId = message.ForwardedFromId, forwardedFrom = forwardedFromObj, replyToId = message.ReplyToId, replyTo = replyToObj, quote = message.Quote, media = message.Media.Select(m => new { id = m.Id, type = m.Type, url = m.Url, filename = m.Filename, size = m.Size }).ToList(), sender = senderObj, readBy = new List(), storyId = message.StoryId, storyMediaUrl = message.StoryMediaUrl, storyMediaType = message.StoryMediaType }, cancellationToken); } }