Добавил новый обработчик для выявления обновленных сообщений. Теперь данные сообщения идут отдельным событием в шину.

This commit is contained in:
ruberoid 2025-10-16 14:28:06 +04:00
parent f65d1fe7b2
commit 3802eb9dd6
9 changed files with 191 additions and 27 deletions

View File

@ -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<IUpdateHandler, UpdateHandler>();
services.AddScoped<INewMessageHandler, NewMessageHandler>();
services.AddScoped<IEditMessageHandler, EditMessageHandler>();
// Message event publishers
services.AddScoped<NewMessagePublisher>();
services.AddScoped<EditedMessagePublisher>();
services.AddScoped<MessageEventPublisherFactory>();
services.AddSingleton<ITelegramClientContainer, TelegramClientContainer>();
services.AddSingleton<TelegramRegistry>();
return services;
}
}

View File

@ -4,5 +4,5 @@ namespace Nocr.TelegramListener.AppServices.UpdateListeners.Handlers;
public interface INewMessageHandler
{
Task Handle(MessageBase messageBase);
Task Handle(MessageBase messageBase, bool isEdit = false);
}

View File

@ -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<NewMessageHandler> _logger;
private readonly TelegramRegistry _telegramRegistry;
private readonly ICurrentDateProvider _dateProvider;
private readonly MessageEventPublisherFactory _publisherFactory;
public NewMessageHandler(IBus bus, ILogger<NewMessageHandler> logger, TelegramRegistry telegramRegistry,
ICurrentDateProvider dateProvider)
public NewMessageHandler(
ILogger<NewMessageHandler> 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),

View File

@ -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;
}
}

View File

@ -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<EditedMessagePublisher> _logger;
private readonly TelegramRegistry _telegramRegistry;
private readonly ICurrentDateProvider _dateProvider;
public EditedMessagePublisher(
IBus bus,
ILogger<EditedMessagePublisher> 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);
}
}

View File

@ -0,0 +1,16 @@
using TL;
namespace Nocr.TelegramListener.AppServices.UpdateListeners.Publishers;
/// <summary>
/// Interface for publishing message events to the message bus
/// </summary>
public interface IMessageEventPublisher
{
/// <summary>
/// Publishes a message event based on the message content
/// </summary>
/// <param name="message">The Telegram message</param>
/// <param name="chatUsername">Username of the chat</param>
Task PublishAsync(Message message, string chatUsername);
}

View File

@ -0,0 +1,25 @@
namespace Nocr.TelegramListener.AppServices.UpdateListeners.Publishers;
/// <summary>
/// Factory for creating appropriate message event publishers based on message type
/// </summary>
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));
}
/// <summary>
/// Gets the appropriate publisher based on whether the message is an edit
/// </summary>
/// <param name="isEdit">True if the message is an edit, false if it's a new message</param>
/// <returns>The appropriate publisher instance</returns>
public IMessageEventPublisher GetPublisher(bool isEdit) => isEdit ? _editedMessagePublisher : _newMessagePublisher;
}

View File

@ -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<NewMessagePublisher> _logger;
private readonly TelegramRegistry _telegramRegistry;
private readonly ICurrentDateProvider _dateProvider;
public NewMessagePublisher(
IBus bus,
ILogger<NewMessagePublisher> 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);
}
}

View File

@ -0,0 +1,39 @@
namespace Nocr.TelegramListener.Async.Api.Contracts.Events;
/// <summary>
/// Событие редактирования сообщения в Telegram
/// </summary>
public sealed class MessageEdited : IEvent
{
public Guid Id { get; } = Guid.NewGuid();
/// <summary>
/// Текст сообщения после редактирования
/// </summary>
public string Text { get; set; } = default!;
/// <summary>
/// Идентификатор отправителя
/// </summary>
public long FromId { get; set; }
/// <summary>
/// Имя или username отправителя
/// </summary>
public string? From { get; set; }
/// <summary>
/// Идентификатор сообщения
/// </summary>
public long MessageId { get; set; }
/// <summary>
/// Username чата отправителя
/// </summary>
public string ChatUsername { get; set; } = default!;
/// <summary>
/// Дата редактирования сообщения
/// </summary>
public DateTimeOffset OccuredDateTime { get; set; }
}