import os
import logging
import asyncio
import time
import sys
from datetime import datetime
from telegram import Bot
from telegram.error import TelegramError, RetryAfter, TimedOut
from dotenv import load_dotenv
# Загрузка переменных окружения
load_dotenv()
# Настройки из переменных окружения
POSTER_BOT_TOKEN = os.getenv('POSTER_BOT_TOKEN')
RESPONDER_BOT_NAME = os.getenv('RESPONDER_BOT_NAME')
CHANNEL_ID = os.getenv('CHANNEL_ID')
DESC_PREFIX = os.getenv('DESC_PREFIX', '')
PZK_PREFIX = os.getenv('PZK_PREFIX', '')
MAX_CAPTION_LENGTH = int(os.getenv('MAX_CAPTION_LENGTH', 1000))
MAX_TEXT_LENGTH = int(os.getenv('MAX_TEXT_LENGTH', 4000))
PUBLISH_SILENTLY = os.getenv('PUBLISH_SILENTLY', 'false').lower() in ('true', '1', 'yes', 'on')
USE_SUBSCRIPTION_BOT = os.getenv('USE_SUBSCRIPTION_BOT', 'true').lower() in ('true', '1', 'yes', 'on')
# Настройка логирования
LOG_FILE = 'volk_telegram_testing.log'
logger = logging.getLogger('VOLK_TG_Test')
logger.setLevel(logging.DEBUG)
formatter = logging.Formatter('[%(asctime)s] [%(levelname)s] [%(name)s] %(message)s', datefmt='%Y-%m-%d %H:%M:%S')
# Консольный обработчик
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.INFO)
console_handler.setFormatter(formatter)
logger.addHandler(console_handler)
# Файловый обработчик с повторными попытками
class RetryFileHandler(logging.FileHandler):
def emit(self, record):
for _ in range(5):
try:
super().emit(record)
return
except (IOError, PermissionError):
time.sleep(0.5)
print(f"Failed to write to log file after 5 attempts: {record.msg}")
file_handler = RetryFileHandler(LOG_FILE, encoding='utf-8')
file_handler.setLevel(logging.DEBUG)
file_handler.setFormatter(formatter)
logger.addHandler(file_handler)
async def test_telegram_publish():
"""Тестовая публикация сообщения в Telegram"""
logger.info("=" * 80)
logger.info("НАЧАЛО ТЕСТОВОЙ ПУБЛИКАЦИИ В TELEGRAM")
logger.info("=" * 80)
# Логируем загруженные параметры
logger.info("Загруженные параметры из .env:")
logger.info(f" POSTER_BOT_TOKEN: {'*' * 20 if POSTER_BOT_TOKEN else 'НЕ ЗАДАН'}")
logger.info(f" RESPONDER_BOT_NAME: {RESPONDER_BOT_NAME}")
logger.info(f" CHANNEL_ID: {CHANNEL_ID}")
logger.info(f" DESC_PREFIX: {DESC_PREFIX}")
logger.info(f" PZK_PREFIX: {PZK_PREFIX}")
logger.info(f" MAX_CAPTION_LENGTH: {MAX_CAPTION_LENGTH}")
logger.info(f" MAX_TEXT_LENGTH: {MAX_TEXT_LENGTH}")
logger.info(f" PUBLISH_SILENTLY: {PUBLISH_SILENTLY}")
logger.info(f" USE_SUBSCRIPTION_BOT: {USE_SUBSCRIPTION_BOT}")
# Проверка обязательных параметров
if not POSTER_BOT_TOKEN:
logger.error("ОШИБКА: POSTER_BOT_TOKEN не задан в .env")
return False
if not CHANNEL_ID:
logger.error("ОШИБКА: CHANNEL_ID не задан в .env")
return False
# Формируем тестовое сообщение
test_number = "TEST001"
test_tags = "#тест #volk_testing"
test_unit_name = "Тестовая площадка"
test_name = "Тестовое событие для проверки публикации"
test_about = "Это тестовое сообщение для проверки работы публикации в Telegram. " * 5
# Формируем базовый текст
base_text = f"{test_tags}\n{test_unit_name}\n{test_name}"
base_text_length = len(base_text)
# Формируем строку ссылок
placeholder_message_id = '1234567890'
if USE_SUBSCRIPTION_BOT:
links_line = f'🔎 Инфо | 📌 Иду | 🔜 Подписка'
else:
links_line = f'🔎 Инфо'
links_line_length = len(links_line)
# Определяем максимальную длину
max_length = MAX_CAPTION_LENGTH # Используем caption для теста
# Вычисляем доступную длину для текста
available_length = max_length - base_text_length - links_line_length - 3
if available_length < 0:
available_length = 0
# Обрезаем about до доступной длины
if len(test_about) > available_length:
test_about = test_about[:available_length-3] + "..."
# Формируем финальный текст
final_text = f"{base_text}\n\n{test_about}\n\n{links_line}"
# Логируем детали сообщения
logger.info("=" * 80)
logger.info("ДЕТАЛИ ТЕСТОВОГО СООБЩЕНИЯ:")
logger.info("=" * 80)
logger.info(f"Длина base_text: {base_text_length} символов")
logger.info(f"Длина test_about: {len(test_about)} символов")
logger.info(f"Длина links_line: {links_line_length} символов")
logger.info(f"Максимальная длина (max_length): {max_length} символов")
logger.info(f"Доступная длина для about: {available_length} символов")
logger.info(f"Длина final_text: {len(final_text)} символов")
logger.info(f"Используется изображение: НЕТ")
logger.info("=" * 80)
logger.info("ТЕКСТ СООБЩЕНИЯ:")
logger.info("=" * 80)
logger.info(final_text)
logger.info("=" * 80)
# Создаем бота
try:
logger.info("Создание объекта Bot...")
bot = Bot(token=POSTER_BOT_TOKEN)
logger.info("Объект Bot успешно создан")
# Получаем информацию о боте
try:
bot_info = await bot.get_me()
logger.info(f"Информация о боте:")
logger.info(f" ID: {bot_info.id}")
logger.info(f" Username: @{bot_info.username}")
logger.info(f" First name: {bot_info.first_name}")
logger.info(f" Is bot: {bot_info.is_bot}")
except Exception as e:
logger.warning(f"Не удалось получить информацию о боте: {e}")
except Exception as e:
logger.error(f"ОШИБКА при создании объекта Bot: {e}")
logger.error(f" Тип ошибки: {type(e).__name__}")
logger.error(f" Все атрибуты: {vars(e)}")
return False
# Публикуем тестовое сообщение
try:
logger.info("=" * 80)
logger.info("ПОПЫТКА ОТПРАВКИ ТЕСТОВОГО СООБЩЕНИЯ")
logger.info("=" * 80)
logger.info(f"Параметры запроса:")
logger.info(f" chat_id: {CHANNEL_ID}")
logger.info(f" text_length: {len(final_text)}")
logger.info(f" parse_mode: HTML")
logger.info(f" disable_notification: {PUBLISH_SILENTLY}")
logger.info(f" disable_web_page_preview: True")
start_time = datetime.now()
message = await bot.send_message(
chat_id=CHANNEL_ID,
text=final_text,
parse_mode="HTML",
disable_notification=PUBLISH_SILENTLY,
disable_web_page_preview=True
)
end_time = datetime.now()
duration = (end_time - start_time).total_seconds()
logger.info("=" * 80)
logger.info("СООБЩЕНИЕ УСПЕШНО ОТПРАВЛЕНО!")
logger.info("=" * 80)
logger.info(f"Message ID: {message.message_id}")
logger.info(f"Chat ID: {message.chat.id}")
logger.info(f"Chat type: {message.chat.type}")
logger.info(f"Chat title: {message.chat.title if hasattr(message.chat, 'title') else 'N/A'}")
logger.info(f"Время отправки: {duration:.2f} секунд")
logger.info(f"Дата сообщения: {message.date}")
logger.info("=" * 80)
return True
except TimedOut as e:
logger.error("=" * 80)
logger.error("ТАЙМАУТ ПРИ ОТПРАВКЕ СООБЩЕНИЯ!")
logger.error("=" * 80)
logger.error(f"Тип ошибки: {type(e).__name__}")
logger.error(f"Сообщение: {str(e)}")
logger.error(f"Все атрибуты ошибки: {vars(e)}")
logger.error(f"Полное представление: {repr(e)}")
logger.error(f"Параметры запроса:")
logger.error(f" chat_id: {CHANNEL_ID}")
logger.error(f" text_length: {len(final_text)}")
logger.error(f" parse_mode: HTML")
return False
except RetryAfter as e:
logger.error("=" * 80)
logger.error("ОШИБКА FLOODWAIT (429) ПРИ ОТПРАВКЕ СООБЩЕНИЯ!")
logger.error("=" * 80)
logger.error(f"Тип ошибки: {type(e).__name__}")
logger.error(f"Сообщение: {str(e)}")
logger.error(f"Необходимо подождать: {e.retry_after} секунд")
logger.error(f"Все атрибуты ошибки: {vars(e)}")
logger.error(f"Полное представление: {repr(e)}")
return False
except TelegramError as e:
logger.error("=" * 80)
logger.error("ОШИБКА TELEGRAM ПРИ ОТПРАВКЕ СООБЩЕНИЯ!")
logger.error("=" * 80)
logger.error(f"Тип ошибки: {type(e).__name__}")
logger.error(f"Сообщение: {str(e)}")
logger.error(f"Все атрибуты ошибки: {vars(e)}")
logger.error(f"Полное представление: {repr(e)}")
logger.error(f"Параметры запроса:")
logger.error(f" chat_id: {CHANNEL_ID}")
logger.error(f" text_length: {len(final_text)}")
logger.error(f" parse_mode: HTML")
return False
except Exception as e:
logger.error("=" * 80)
logger.error("НЕОЖИДАННАЯ ОШИБКА ПРИ ОТПРАВКЕ СООБЩЕНИЯ!")
logger.error("=" * 80)
logger.error(f"Тип ошибки: {type(e).__name__}")
logger.error(f"Сообщение: {str(e)}")
logger.error(f"Все атрибуты ошибки: {vars(e) if hasattr(e, '__dict__') else 'N/A'}")
logger.error(f"Полное представление: {repr(e)}")
import traceback
logger.error(f"Трассировка стека:\n{traceback.format_exc()}")
return False
async def main():
"""Главная функция"""
try:
success = await test_telegram_publish()
if success:
logger.info("=" * 80)
logger.info("ТЕСТ ЗАВЕРШЕН УСПЕШНО")
logger.info("=" * 80)
sys.exit(0)
else:
logger.error("=" * 80)
logger.error("ТЕСТ ЗАВЕРШЕН С ОШИБКОЙ")
logger.error("=" * 80)
sys.exit(1)
except KeyboardInterrupt:
logger.warning("Прервано пользователем")
sys.exit(1)
except Exception as e:
logger.error(f"Критическая ошибка: {e}")
import traceback
logger.error(f"Трассировка стека:\n{traceback.format_exc()}")
sys.exit(1)
if __name__ == "__main__":
asyncio.run(main())