diff --git a/src/Nocr.TelegramListener.AppServices/ServiceCollectionExtensions.cs b/src/Nocr.TelegramListener.AppServices/ServiceCollectionExtensions.cs index 22c385c..f664097 100644 --- a/src/Nocr.TelegramListener.AppServices/ServiceCollectionExtensions.cs +++ b/src/Nocr.TelegramListener.AppServices/ServiceCollectionExtensions.cs @@ -3,6 +3,7 @@ using Microsoft.Extensions.DependencyInjection; using Nocr.TelegramListener.AppServices.TextMatches; using Nocr.TelegramListener.AppServices.UpdateListeners; using Nocr.TelegramListener.AppServices.UpdateListeners.Handlers; +using Nocr.TelegramListener.AppServices.UpdateListeners.Publishers; using Rebus.Config; namespace Nocr.TelegramListener.AppServices; @@ -23,9 +24,15 @@ public static class ServiceCollectionExtensions services.AddScoped(); services.AddScoped(); services.AddScoped(); + + // Message event publishers + services.AddScoped(); + services.AddScoped(); + services.AddScoped(); + services.AddSingleton(); services.AddSingleton(); - + return services; } } \ No newline at end of file diff --git a/src/Nocr.TelegramListener.AppServices/UpdateListeners/Handlers/INewMessageHandler.cs b/src/Nocr.TelegramListener.AppServices/UpdateListeners/Handlers/INewMessageHandler.cs index 866ee09..2684e46 100644 --- a/src/Nocr.TelegramListener.AppServices/UpdateListeners/Handlers/INewMessageHandler.cs +++ b/src/Nocr.TelegramListener.AppServices/UpdateListeners/Handlers/INewMessageHandler.cs @@ -4,5 +4,5 @@ namespace Nocr.TelegramListener.AppServices.UpdateListeners.Handlers; public interface INewMessageHandler { - Task Handle(MessageBase messageBase); + Task Handle(MessageBase messageBase, bool isEdit = false); } \ No newline at end of file diff --git a/src/Nocr.TelegramListener.AppServices/UpdateListeners/Handlers/Implementation/NewMessageHandler.cs b/src/Nocr.TelegramListener.AppServices/UpdateListeners/Handlers/Implementation/NewMessageHandler.cs index c1867af..6023b5c 100644 --- a/src/Nocr.TelegramListener.AppServices/UpdateListeners/Handlers/Implementation/NewMessageHandler.cs +++ b/src/Nocr.TelegramListener.AppServices/UpdateListeners/Handlers/Implementation/NewMessageHandler.cs @@ -1,30 +1,28 @@ using Microsoft.Extensions.Logging; -using Nocr.TelegramListener.Async.Api.Contracts.Events; -using Nocr.TelegramListener.Core.Dates; -using Rebus.Bus; +using Nocr.TelegramListener.AppServices.UpdateListeners.Publishers; using TL; namespace Nocr.TelegramListener.AppServices.UpdateListeners.Handlers; public sealed class NewMessageHandler : INewMessageHandler { - private readonly IBus _bus; private readonly ILogger _logger; private readonly TelegramRegistry _telegramRegistry; - private readonly ICurrentDateProvider _dateProvider; + private readonly MessageEventPublisherFactory _publisherFactory; - public NewMessageHandler(IBus bus, ILogger logger, TelegramRegistry telegramRegistry, - ICurrentDateProvider dateProvider) + public NewMessageHandler( + ILogger logger, + TelegramRegistry telegramRegistry, + MessageEventPublisherFactory publisherFactory) { - _bus = bus ?? throw new ArgumentNullException(nameof(bus)); _logger = logger ?? throw new ArgumentNullException(nameof(logger)); _telegramRegistry = telegramRegistry ?? throw new ArgumentNullException(nameof(telegramRegistry)); - _dateProvider = dateProvider ?? throw new ArgumentNullException(nameof(dateProvider)); + _publisherFactory = publisherFactory ?? throw new ArgumentNullException(nameof(publisherFactory)); } - public async Task Handle(MessageBase messageBase) + public async Task Handle(MessageBase messageBase, bool isEdit = false) { - _logger.LogDebug("Executing {Handler} for message {MessageId}.", nameof(NewMessageHandler), messageBase.ID); + _logger.LogDebug("Executing {Handler} for message {MessageId}, isEdit={IsEdit}.", nameof(NewMessageHandler), messageBase.ID, isEdit); try { @@ -39,26 +37,17 @@ public sealed class NewMessageHandler : INewMessageHandler m.Peer.Peer(_telegramRegistry.Users, _telegramRegistry.Chats), m.message); var chatUserName = m.peer_id.Peer(_telegramRegistry.Users, _telegramRegistry.Chats)?.Split("@").Last(); - + if (string.IsNullOrWhiteSpace(chatUserName)) { _logger.LogWarning("Failed to get chat user name for chat {ChatId}.", m.peer_id.ID); break; } - var @event = new MessageReceived - { - MessageId = messageBase.ID, - // Для каналов from = null - FromId = m.From?.ID ?? m.Peer.ID, - From = (m.From ?? m.Peer).Peer(_telegramRegistry.Users, _telegramRegistry.Chats), - ChatUsername = chatUserName, - Text = m.message, - OccuredDateTime = _dateProvider.UtcNow - }; - - await _bus.Advanced.Topics.Publish("nocr.telegram.listener", @event); + var publisher = _publisherFactory.GetPublisher(isEdit); + await publisher.PublishAsync(m, chatUserName); break; + case MessageService ms: _logger.LogInformation("{From} in {Chat} > [{Action}]", ms.From?.Peer(_telegramRegistry.Users, _telegramRegistry.Chats), diff --git a/src/Nocr.TelegramListener.AppServices/UpdateListeners/Handlers/Implementation/UpdateHandler.cs b/src/Nocr.TelegramListener.AppServices/UpdateListeners/Handlers/Implementation/UpdateHandler.cs index b1e63f4..cc4951f 100644 --- a/src/Nocr.TelegramListener.AppServices/UpdateListeners/Handlers/Implementation/UpdateHandler.cs +++ b/src/Nocr.TelegramListener.AppServices/UpdateListeners/Handlers/Implementation/UpdateHandler.cs @@ -52,7 +52,7 @@ public sealed class UpdateHandler( { case Message m: _logger.LogDebug("({Edit}) from `{From}` in `{In}`: {Message}", edit ? "E" : "N", m.from_id, m.peer_id, m.message); - await _newMessageHandler.Handle(m); + await _newMessageHandler.Handle(m, isEdit: edit); break; } } diff --git a/src/Nocr.TelegramListener.AppServices/UpdateListeners/Publishers/EditedMessagePublisher.cs b/src/Nocr.TelegramListener.AppServices/UpdateListeners/Publishers/EditedMessagePublisher.cs new file mode 100644 index 0000000..25d7493 --- /dev/null +++ b/src/Nocr.TelegramListener.AppServices/UpdateListeners/Publishers/EditedMessagePublisher.cs @@ -0,0 +1,44 @@ +using Microsoft.Extensions.Logging; +using Nocr.TelegramListener.Async.Api.Contracts.Events; +using Nocr.TelegramListener.Core.Dates; +using Rebus.Bus; +using TL; + +namespace Nocr.TelegramListener.AppServices.UpdateListeners.Publishers; + +public sealed class EditedMessagePublisher : IMessageEventPublisher +{ + private readonly IBus _bus; + private readonly ILogger _logger; + private readonly TelegramRegistry _telegramRegistry; + private readonly ICurrentDateProvider _dateProvider; + + public EditedMessagePublisher( + IBus bus, + ILogger logger, + TelegramRegistry telegramRegistry, + ICurrentDateProvider dateProvider) + { + _bus = bus ?? throw new ArgumentNullException(nameof(bus)); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _telegramRegistry = telegramRegistry ?? throw new ArgumentNullException(nameof(telegramRegistry)); + _dateProvider = dateProvider ?? throw new ArgumentNullException(nameof(dateProvider)); + } + + public async Task PublishAsync(Message message, string chatUsername) + { + var @event = new MessageEdited + { + MessageId = message.ID, + // Для каналов from = null + FromId = message.From?.ID ?? message.Peer.ID, + From = (message.From ?? message.Peer).Peer(_telegramRegistry.Users, _telegramRegistry.Chats), + ChatUsername = chatUsername, + Text = message.message, + OccuredDateTime = _dateProvider.UtcNow + }; + + await _bus.Advanced.Topics.Publish("nocr.telegram.listener", @event); + _logger.LogDebug("Published MessageEdited for message {MessageId}.", message.ID); + } +} diff --git a/src/Nocr.TelegramListener.AppServices/UpdateListeners/Publishers/IMessageEventPublisher.cs b/src/Nocr.TelegramListener.AppServices/UpdateListeners/Publishers/IMessageEventPublisher.cs new file mode 100644 index 0000000..dcdba91 --- /dev/null +++ b/src/Nocr.TelegramListener.AppServices/UpdateListeners/Publishers/IMessageEventPublisher.cs @@ -0,0 +1,16 @@ +using TL; + +namespace Nocr.TelegramListener.AppServices.UpdateListeners.Publishers; + +/// +/// Interface for publishing message events to the message bus +/// +public interface IMessageEventPublisher +{ + /// + /// Publishes a message event based on the message content + /// + /// The Telegram message + /// Username of the chat + Task PublishAsync(Message message, string chatUsername); +} diff --git a/src/Nocr.TelegramListener.AppServices/UpdateListeners/Publishers/MessageEventPublisherFactory.cs b/src/Nocr.TelegramListener.AppServices/UpdateListeners/Publishers/MessageEventPublisherFactory.cs new file mode 100644 index 0000000..ad4bfdb --- /dev/null +++ b/src/Nocr.TelegramListener.AppServices/UpdateListeners/Publishers/MessageEventPublisherFactory.cs @@ -0,0 +1,25 @@ +namespace Nocr.TelegramListener.AppServices.UpdateListeners.Publishers; + +/// +/// Factory for creating appropriate message event publishers based on message type +/// +public sealed class MessageEventPublisherFactory +{ + private readonly NewMessagePublisher _newMessagePublisher; + private readonly EditedMessagePublisher _editedMessagePublisher; + + public MessageEventPublisherFactory( + NewMessagePublisher newMessagePublisher, + EditedMessagePublisher editedMessagePublisher) + { + _newMessagePublisher = newMessagePublisher ?? throw new ArgumentNullException(nameof(newMessagePublisher)); + _editedMessagePublisher = editedMessagePublisher ?? throw new ArgumentNullException(nameof(editedMessagePublisher)); + } + + /// + /// Gets the appropriate publisher based on whether the message is an edit + /// + /// True if the message is an edit, false if it's a new message + /// The appropriate publisher instance + public IMessageEventPublisher GetPublisher(bool isEdit) => isEdit ? _editedMessagePublisher : _newMessagePublisher; +} diff --git a/src/Nocr.TelegramListener.AppServices/UpdateListeners/Publishers/NewMessagePublisher.cs b/src/Nocr.TelegramListener.AppServices/UpdateListeners/Publishers/NewMessagePublisher.cs new file mode 100644 index 0000000..5b489a9 --- /dev/null +++ b/src/Nocr.TelegramListener.AppServices/UpdateListeners/Publishers/NewMessagePublisher.cs @@ -0,0 +1,44 @@ +using Microsoft.Extensions.Logging; +using Nocr.TelegramListener.Async.Api.Contracts.Events; +using Nocr.TelegramListener.Core.Dates; +using Rebus.Bus; +using TL; + +namespace Nocr.TelegramListener.AppServices.UpdateListeners.Publishers; + +public sealed class NewMessagePublisher : IMessageEventPublisher +{ + private readonly IBus _bus; + private readonly ILogger _logger; + private readonly TelegramRegistry _telegramRegistry; + private readonly ICurrentDateProvider _dateProvider; + + public NewMessagePublisher( + IBus bus, + ILogger logger, + TelegramRegistry telegramRegistry, + ICurrentDateProvider dateProvider) + { + _bus = bus ?? throw new ArgumentNullException(nameof(bus)); + _logger = logger ?? throw new ArgumentNullException(nameof(logger)); + _telegramRegistry = telegramRegistry ?? throw new ArgumentNullException(nameof(telegramRegistry)); + _dateProvider = dateProvider ?? throw new ArgumentNullException(nameof(dateProvider)); + } + + public async Task PublishAsync(Message message, string chatUsername) + { + var @event = new MessageReceived + { + MessageId = message.ID, + // Для каналов from = null + FromId = message.From?.ID ?? message.Peer.ID, + From = (message.From ?? message.Peer).Peer(_telegramRegistry.Users, _telegramRegistry.Chats), + ChatUsername = chatUsername, + Text = message.message, + OccuredDateTime = _dateProvider.UtcNow + }; + + await _bus.Advanced.Topics.Publish("nocr.telegram.listener", @event); + _logger.LogDebug("Published MessageReceived for message {MessageId}.", message.ID); + } +} diff --git a/src/Nocr.TelegramListener.Async.Api.Contracts/Events/MessageEdited.cs b/src/Nocr.TelegramListener.Async.Api.Contracts/Events/MessageEdited.cs new file mode 100644 index 0000000..a045164 --- /dev/null +++ b/src/Nocr.TelegramListener.Async.Api.Contracts/Events/MessageEdited.cs @@ -0,0 +1,39 @@ +namespace Nocr.TelegramListener.Async.Api.Contracts.Events; + +/// +/// Событие редактирования сообщения в Telegram +/// +public sealed class MessageEdited : IEvent +{ + public Guid Id { get; } = Guid.NewGuid(); + + /// + /// Текст сообщения после редактирования + /// + public string Text { get; set; } = default!; + + /// + /// Идентификатор отправителя + /// + public long FromId { get; set; } + + /// + /// Имя или username отправителя + /// + public string? From { get; set; } + + /// + /// Идентификатор сообщения + /// + public long MessageId { get; set; } + + /// + /// Username чата отправителя + /// + public string ChatUsername { get; set; } = default!; + + /// + /// Дата редактирования сообщения + /// + public DateTimeOffset OccuredDateTime { get; set; } +}