2025-04-12 10:20:46 +07:00
using DailyDigestWorker.Configuration ; // Н е используется напрямую, но нужно для DI WTelegramClient
using Microsoft.Extensions.Options ;
using System.Collections.Generic ;
using System.Threading ;
using System.Threading.Tasks ;
using TL ; // Основное пространство имен WTelegramClient
2025-04-12 00:27:03 +07:00
using WTelegram ; // Для Client
namespace DailyDigestWorker.Services
{
2025-04-12 10:20:46 +07:00
public class TelegramChannelReader : ITelegramChannelReader // Реализуем обновленный интерфейс
2025-04-12 00:27:03 +07:00
{
private readonly ILogger < TelegramChannelReader > _logger ;
private readonly Client _client ; // Наш Singleton WTelegramClient
2025-04-12 10:20:46 +07:00
// Зависимость от IOptions<TelegramClientSettings> убрана
// Кэшированное поле _targetPeer убрано
2025-04-12 00:27:03 +07:00
2025-04-12 10:20:46 +07:00
// Конструктор теперь принимает только логгер и WTelegramClient
2025-04-12 00:27:03 +07:00
public TelegramChannelReader (
ILogger < TelegramChannelReader > logger ,
2025-04-12 10:20:46 +07:00
Client client )
2025-04-12 00:27:03 +07:00
{
_logger = logger ;
_client = client ;
}
2025-04-12 10:20:46 +07:00
// Метод теперь принимает channelUsername как параметр
public async Task < List < string > ? > GetRecentNewsAsync (
string channelUsername , // Имя канала для этого конкретного вызова
int maxAgeHours ,
int limit ,
CancellationToken cancellationToken )
2025-04-12 00:27:03 +07:00
{
2025-04-12 10:20:46 +07:00
// Внешний try-catch для диагностики любых ошибок
2025-04-12 00:27:03 +07:00
try
{
2025-04-12 10:20:46 +07:00
_logger . LogInformation ( "[GetRecentNewsAsync] Попытка чтения новостей из канала {ChannelUsername}..." , channelUsername ) ;
if ( cancellationToken . IsCancellationRequested )
{
_logger . LogWarning ( "[GetRecentNewsAsync] Операция отменена ПЕРЕД началом работы для канала {ChannelUsername}." , channelUsername ) ;
return null ;
}
_logger . LogDebug ( "[GetRecentNewsAsync] Шаг 1: Проверка/выполнение авторизации пользователя..." ) ;
2025-04-12 00:27:03 +07:00
User ? currentUser = null ;
try
{
2025-04-12 10:20:46 +07:00
// Выполняем логин, если необходимо (может запросить ввод в консоль)
currentUser = await _client . LoginUserIfNeeded ( ) . ConfigureAwait ( false ) ;
2025-04-12 00:27:03 +07:00
}
catch ( Exception loginEx )
{
2025-04-12 10:20:46 +07:00
_logger . LogError ( loginEx , "[GetRecentNewsAsync] Ошибка В О ВРЕМЯ выполнения LoginUserIfNeeded." ) ;
return null ;
2025-04-12 00:27:03 +07:00
}
if ( currentUser = = null )
{
2025-04-12 10:20:46 +07:00
_logger . LogError ( "[GetRecentNewsAsync] Авторизация не удалась (LoginUserIfNeeded вернул null или произошла ошибка выше)." ) ;
2025-04-12 00:27:03 +07:00
return null ;
}
2025-04-12 10:20:46 +07:00
_logger . LogInformation ( "[GetRecentNewsAsync] Шаг 1 Успех: Авторизация как {UserFirstName} (ID: {UserId})" , currentUser . first_name , currentUser . id ) ;
2025-04-12 00:27:03 +07:00
2025-04-12 10:20:46 +07:00
// 2. Найти канал (получить InputPeer) - делаем это каждый раз
_logger . LogDebug ( "[GetRecentNewsAsync] Шаг 2: Поиск InputPeer для канала {ChannelUsername}..." , channelUsername ) ;
InputPeer ? targetPeer = null ; // Локальная переменная
try
2025-04-12 00:27:03 +07:00
{
2025-04-12 10:20:46 +07:00
var resolved = await _client . Contacts_ResolveUsername ( channelUsername ) . ConfigureAwait ( false ) ;
2025-04-12 00:27:03 +07:00
if ( resolved ? . UserOrChat is Channel channel )
{
2025-04-12 10:20:46 +07:00
targetPeer = channel . ToInputPeer ( ) ;
_logger . LogInformation ( "[GetRecentNewsAsync] Шаг 2 Успех: Найден InputPeer для канала '{ChannelTitle}' (ID: {ChannelId})" , channel . title , channel . id ) ;
2025-04-12 00:27:03 +07:00
}
else
{
2025-04-12 10:20:46 +07:00
_logger . LogError ( "[GetRecentNewsAsync] Шаг 2 Ошибка: Н е удалось найти канал по юзернейму {ChannelUsername} или это не канал. Resolved: {@Resolved}" , channelUsername , resolved ) ;
2025-04-12 00:27:03 +07:00
return null ;
}
}
2025-04-12 10:20:46 +07:00
catch ( RpcException e )
2025-04-12 00:27:03 +07:00
{
2025-04-12 10:20:46 +07:00
_logger . LogError ( e , "[GetRecentNewsAsync] Ошибка Telegram API ({ErrorCode}) при поиске канала {ChannelUsername}: {ErrorMessage}" , e . Code , channelUsername , e . Message ) ;
return null ;
}
catch ( Exception ex )
{
_logger . LogError ( ex , "[GetRecentNewsAsync] Неожиданная ошибка при поиске канала {ChannelUsername}." , channelUsername ) ;
return null ;
}
// Если targetPeer все еще null (не должно произойти при успешном resolve)
if ( targetPeer = = null )
{
_logger . LogError ( "[GetRecentNewsAsync] Критическая ошибка: InputPeer остался null после ResolveUsername для {ChannelUsername}" , channelUsername ) ;
return null ;
2025-04-12 00:27:03 +07:00
}
2025-04-12 10:20:46 +07:00
2025-04-12 00:27:03 +07:00
// 3. Получить историю сообщений
2025-04-12 10:20:46 +07:00
_logger . LogDebug ( "[GetRecentNewsAsync] Шаг 3: Запрос истории сообщений (limit={Limit})..." , limit ) ;
Messages_MessagesBase ? history = null ; // Используем nullable тип
try
{
history = await _client . Messages_GetHistory ( targetPeer , limit : limit ) . ConfigureAwait ( false ) ;
}
catch ( RpcException e )
{
_logger . LogError ( e , "[GetRecentNewsAsync] Ошибка Telegram API ({ErrorCode}) при получении истории для {ChannelUsername}: {ErrorMessage}" , e . Code , channelUsername , e . Message ) ;
return null ;
}
catch ( Exception ex )
{
_logger . LogError ( ex , "[GetRecentNewsAsync] Неожиданная ошибка при получении истории для {ChannelUsername}." , channelUsername ) ;
return null ;
}
2025-04-12 00:27:03 +07:00
if ( history = = null )
{
2025-04-12 10:20:46 +07:00
_logger . LogWarning ( "[GetRecentNewsAsync] Шаг 3 Ошибка: Н е удалось получить историю сообщений (результат null) для канала {ChannelUsername}." , channelUsername ) ;
2025-04-12 00:27:03 +07:00
return null ;
}
2025-04-12 10:20:46 +07:00
_logger . LogInformation ( "[GetRecentNewsAsync] Шаг 3 Успех: Получено {Count} сообщений/элементов в истории для канала {ChannelUsername}." , history . Messages . Length , channelUsername ) ;
2025-04-12 00:27:03 +07:00
// 4. Отфильтровать сообщения по дате и извлечь текст
2025-04-12 10:20:46 +07:00
_logger . LogDebug ( "[GetRecentNewsAsync] Шаг 4: Фильтрация сообщений новее {CutoffDateUtc} UTC..." , DateTime . UtcNow . AddHours ( - maxAgeHours ) ) ;
2025-04-12 00:27:03 +07:00
var newsTexts = new List < string > ( ) ;
var cutoffDate = DateTime . UtcNow . AddHours ( - maxAgeHours ) ;
foreach ( var msgBase in history . Messages )
{
2025-04-12 10:20:46 +07:00
if ( cancellationToken . IsCancellationRequested )
{
_logger . LogWarning ( "[GetRecentNewsAsync] Операция отменена во время фильтрации сообщений." ) ;
return null ;
}
2025-04-12 00:27:03 +07:00
if ( msgBase is Message message )
{
if ( message . Date > = cutoffDate )
{
if ( ! string . IsNullOrWhiteSpace ( message . message ) )
{
newsTexts . Add ( message . message ) ;
}
}
else
{
2025-04-12 10:20:46 +07:00
_logger . LogDebug ( "[GetRecentNewsAsync] Достигнуто сообщение старше {CutoffDateUtc} UTC, остановка фильтрации." , cutoffDate ) ;
break ; // Оптимизация: сообщения идут от новых к старым
2025-04-12 00:27:03 +07:00
}
}
}
2025-04-12 10:20:46 +07:00
_logger . LogInformation ( "[GetRecentNewsAsync] Шаг 4 Успех: Найдено {Count} новостных сообщений за последние {Hours} часов из канала {ChannelUsername}." , newsTexts . Count , maxAgeHours , channelUsername ) ;
2025-04-12 00:27:03 +07:00
2025-04-12 10:20:46 +07:00
// Сообщения были от новых к старым, переворачиваем для хронологии
2025-04-12 00:27:03 +07:00
newsTexts . Reverse ( ) ;
return newsTexts ;
2025-04-12 10:20:46 +07:00
2025-04-12 00:27:03 +07:00
}
2025-04-12 10:20:46 +07:00
catch ( RpcException e ) // Ловим ошибки Telegram API на уровне всего метода
2025-04-12 00:27:03 +07:00
{
2025-04-12 10:20:46 +07:00
_logger . LogError ( e , "[GetRecentNewsAsync] Ошибка Telegram API ({ErrorCode}) во время работы с каналом {ChannelUsername}: {ErrorMessage}" , e . Code , channelUsername , e . Message ) ;
if ( e . Code = = 420 ) // FLOOD_WAIT_X
2025-04-12 00:27:03 +07:00
{
2025-04-12 10:20:46 +07:00
_logger . LogWarning ( "[GetRecentNewsAsync] Получен FloodWait на {Seconds} секунд. Пропускаем чтение." , e . X ) ;
2025-04-12 00:27:03 +07:00
}
return null ;
}
2025-04-12 10:20:46 +07:00
catch ( Exception ex ) // Ловим ЛЮБЫЕ другие ошибки внутри метода
2025-04-12 00:27:03 +07:00
{
2025-04-12 10:20:46 +07:00
_logger . LogError ( ex , "[GetRecentNewsAsync] Неожиданная ошибка ВНУТРИ метода для канала {ChannelUsername}." , channelUsername ) ;
2025-04-12 00:27:03 +07:00
return null ;
}
}
}
}