[ВОЛК] переход на прямого httpx клиента для постинга в телеграм
ci/woodpecker/push/woodpecker Pipeline was successful

This commit is contained in:
2025-12-21 18:44:34 +03:00
parent de7fc5ad8a
commit ebaa7e89e4
+166 -93
View File
@@ -4,10 +4,8 @@ import httpx
import asyncio import asyncio
import time import time
import sys import sys
import json
from datetime import datetime from datetime import datetime
from telegram import Bot
from telegram.request import HTTPXRequest
from telegram.error import TelegramError, RetryAfter, TimedOut
from dotenv import load_dotenv from dotenv import load_dotenv
# Загрузка переменных окружения # Загрузка переменных окружения
@@ -132,44 +130,54 @@ async def test_telegram_publish():
logger.info(final_text) logger.info(final_text)
logger.info("=" * 80) logger.info("=" * 80)
# Создаем httpx клиент и бота с отключенным HTTP/2 # Создаем httpx клиент для прямых запросов к Telegram Bot API
httpx_client = None httpx_client = None
try: try:
# Создаём клиент БЕЗ HTTP/2 # Создаём клиент БЕЗ HTTP/2 с указанными параметрами
logger.info("Создание httpx клиента с отключенным HTTP/2...") logger.info("Создание httpx клиента с отключенным HTTP/2...")
httpx_client = httpx.AsyncClient( httpx_client = httpx.AsyncClient(
http2=False, # ← отключаем HTTP/2 http2=False, # ← отключаем HTTP/2
timeout=20.0, # явный таймаут timeout=20.0, # явный таймаут
follow_redirects=True follow_redirects=True
) )
logger.info("httpx клиент успешно создан с http2=False") logger.info("httpx клиент успешно создан с http2=False, timeout=20.0")
# Создаем HTTPXRequest с явным указанием HTTP/1.1 (отключаем HTTP/2) # Получаем информацию о боте через Telegram Bot API
# HTTPXRequest автоматически создаст httpx клиент с http2=False при http_version="1.1"
logger.info("Создание HTTPXRequest с http_version='1.1' (HTTP/2 отключен)...")
request = HTTPXRequest(http_version="1.1", connection_pool_size=8)
logger.info("HTTPXRequest создан с http_version='1.1'")
# Примечание: HTTPXRequest создаст свой собственный httpx клиент с http2=False
# Наш httpx_client будет закрыт в finally, но не используется Bot'ом
# Это нормально - главное, что HTTP/2 отключен через http_version="1.1"
# Создаем бота с отключенным HTTP/2
logger.info("Создание объекта Bot с отключенным HTTP/2...")
bot = Bot(token=POSTER_BOT_TOKEN, request=request)
logger.info("Объект Bot успешно создан с отключенным HTTP/2")
# Получаем информацию о боте
try: try:
logger.info("Попытка получения информации о боте через bot.get_me()...") logger.info("=" * 80)
logger.debug(f"Параметры запроса get_me(): нет параметров (метод без аргументов)") logger.info("ПОПЫТКА ПОЛУЧЕНИЯ ИНФОРМАЦИИ О БОТЕ")
bot_info = await bot.get_me() logger.info("=" * 80)
logger.info(f"Информация о боте:") get_me_url = f"https://api.telegram.org/bot{POSTER_BOT_TOKEN}/getMe"
logger.info(f" ID: {bot_info.id}") logger.info(f"URL запроса: {get_me_url}")
logger.info(f" Username: @{bot_info.username}") logger.info(f"Метод: GET")
logger.info(f" First name: {bot_info.first_name}")
logger.info(f" Is bot: {bot_info.is_bot}") start_time = datetime.now()
except TimedOut as e: response = await httpx_client.get(get_me_url)
end_time = datetime.now()
duration = (end_time - start_time).total_seconds()
logger.info(f"Статус ответа: {response.status_code}")
logger.info(f"Время запроса: {duration:.2f} секунд")
if response.status_code == 200:
bot_info = response.json()
if bot_info.get('ok'):
result = bot_info.get('result', {})
logger.info("=" * 80)
logger.info("ИНФОРМАЦИЯ О БОТЕ УСПЕШНО ПОЛУЧЕНА!")
logger.info("=" * 80)
logger.info(f"ID: {result.get('id')}")
logger.info(f"Username: @{result.get('username')}")
logger.info(f"First name: {result.get('first_name')}")
logger.info(f"Is bot: {result.get('is_bot')}")
logger.info("=" * 80)
else:
logger.error(f"Ошибка в ответе API: {bot_info}")
else:
logger.error(f"HTTP ошибка: {response.status_code}")
logger.error(f"Текст ответа: {response.text}")
except httpx.TimeoutException as e:
logger.error("=" * 80) logger.error("=" * 80)
logger.error("ТАЙМАУТ при получении информации о боте!") logger.error("ТАЙМАУТ при получении информации о боте!")
logger.error("=" * 80) logger.error("=" * 80)
@@ -177,32 +185,14 @@ async def test_telegram_publish():
logger.error(f"Сообщение: {str(e)}") logger.error(f"Сообщение: {str(e)}")
logger.error(f"Все атрибуты ошибки: {vars(e)}") logger.error(f"Все атрибуты ошибки: {vars(e)}")
logger.error(f"Полное представление: {repr(e)}") logger.error(f"Полное представление: {repr(e)}")
logger.error(f"Параметры запроса:") except httpx.HTTPError as e:
logger.error(f" Метод: bot.get_me()")
logger.error(f" Токен: {'*' * 20 if POSTER_BOT_TOKEN else 'НЕ ЗАДАН'}")
logger.error(f" Длина токена: {len(POSTER_BOT_TOKEN) if POSTER_BOT_TOKEN else 0}")
except RetryAfter as e:
logger.error("=" * 80) logger.error("=" * 80)
logger.error("ОШИБКА FLOODWAIT (429) при получении информации о боте!") logger.error("ОШИБКА HTTP при получении информации о боте!")
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)}")
except TelegramError as e:
logger.error("=" * 80)
logger.error("ОШИБКА TELEGRAM при получении информации о боте!")
logger.error("=" * 80) logger.error("=" * 80)
logger.error(f"Тип ошибки: {type(e).__name__}") logger.error(f"Тип ошибки: {type(e).__name__}")
logger.error(f"Сообщение: {str(e)}") logger.error(f"Сообщение: {str(e)}")
logger.error(f"Все атрибуты ошибки: {vars(e)}") logger.error(f"Все атрибуты ошибки: {vars(e)}")
logger.error(f"Полное представление: {repr(e)}") logger.error(f"Полное представление: {repr(e)}")
logger.error(f"Параметры запроса:")
logger.error(f" Метод: bot.get_me()")
logger.error(f" Токен: {'*' * 20 if POSTER_BOT_TOKEN else 'НЕ ЗАДАН'}")
logger.error(f" Длина токена: {len(POSTER_BOT_TOKEN) if POSTER_BOT_TOKEN else 0}")
logger.error(f" Первые 10 символов токена: {POSTER_BOT_TOKEN[:10] if POSTER_BOT_TOKEN and len(POSTER_BOT_TOKEN) >= 10 else 'N/A'}")
except Exception as e: except Exception as e:
logger.error("=" * 80) logger.error("=" * 80)
logger.error("НЕОЖИДАННАЯ ОШИБКА при получении информации о боте!") logger.error("НЕОЖИДАННАЯ ОШИБКА при получении информации о боте!")
@@ -211,18 +201,17 @@ async def test_telegram_publish():
logger.error(f"Сообщение: {str(e)}") logger.error(f"Сообщение: {str(e)}")
logger.error(f"Все атрибуты ошибки: {vars(e) if hasattr(e, '__dict__') else 'N/A'}") logger.error(f"Все атрибуты ошибки: {vars(e) if hasattr(e, '__dict__') else 'N/A'}")
logger.error(f"Полное представление: {repr(e)}") logger.error(f"Полное представление: {repr(e)}")
logger.error(f"Параметры запроса:")
logger.error(f" Метод: bot.get_me()")
logger.error(f" Токен: {'*' * 20 if POSTER_BOT_TOKEN else 'НЕ ЗАДАН'}")
logger.error(f" Длина токена: {len(POSTER_BOT_TOKEN) if POSTER_BOT_TOKEN else 0}")
import traceback import traceback
logger.error(f"Трассировка стека:\n{traceback.format_exc()}") logger.error(f"Трассировка стека:\n{traceback.format_exc()}")
# Публикуем тестовое сообщение # Публикуем тестовое сообщение через Telegram Bot API
try: try:
logger.info("=" * 80) logger.info("=" * 80)
logger.info("ПОПЫТКА ОТПРАВКИ ТЕСТОВОГО СООБЩЕНИЯ") logger.info("ПОПЫТКА ОТПРАВКИ ТЕСТОВОГО СООБЩЕНИЯ")
logger.info("=" * 80) logger.info("=" * 80)
send_message_url = f"https://api.telegram.org/bot{POSTER_BOT_TOKEN}/sendMessage"
logger.info(f"URL запроса: {send_message_url}")
logger.info(f"Метод: POST")
logger.info(f"Параметры запроса:") logger.info(f"Параметры запроса:")
logger.info(f" chat_id: {CHANNEL_ID}") logger.info(f" chat_id: {CHANNEL_ID}")
logger.info(f" text_length: {len(final_text)}") logger.info(f" text_length: {len(final_text)}")
@@ -230,31 +219,130 @@ async def test_telegram_publish():
logger.info(f" disable_notification: {PUBLISH_SILENTLY}") logger.info(f" disable_notification: {PUBLISH_SILENTLY}")
logger.info(f" disable_web_page_preview: True") logger.info(f" disable_web_page_preview: True")
payload = {
'chat_id': CHANNEL_ID,
'text': final_text,
'parse_mode': 'HTML',
'disable_notification': PUBLISH_SILENTLY,
'disable_web_page_preview': True
}
start_time = datetime.now() start_time = datetime.now()
message = await bot.send_message( response = await httpx_client.post(send_message_url, json=payload)
chat_id=CHANNEL_ID,
text=final_text,
parse_mode="HTML",
disable_notification=PUBLISH_SILENTLY,
disable_web_page_preview=True
)
end_time = datetime.now() end_time = datetime.now()
duration = (end_time - start_time).total_seconds() duration = (end_time - start_time).total_seconds()
logger.info("=" * 80) logger.info(f"Статус ответа: {response.status_code}")
logger.info("СООБЩЕНИЕ УСПЕШНО ОТПРАВЛЕНО!") logger.info(f"Время запроса: {duration:.2f} секунд")
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 if response.status_code == 200:
result = response.json()
except TimedOut as e: if result.get('ok'):
message_data = result.get('result', {})
message_id = message_data.get('message_id')
chat_data = message_data.get('chat', {})
logger.info("=" * 80)
logger.info("СООБЩЕНИЕ УСПЕШНО ОТПРАВЛЕНО!")
logger.info("=" * 80)
logger.info(f"Message ID: {message_id}")
logger.info(f"Chat ID: {chat_data.get('id')}")
logger.info(f"Chat type: {chat_data.get('type')}")
logger.info(f"Chat title: {chat_data.get('title', 'N/A')}")
logger.info(f"Время отправки: {duration:.2f} секунд")
logger.info(f"Дата сообщения: {message_data.get('date')}")
logger.info("=" * 80)
# Редактируем сообщение, добавляя информацию о редактировании
try:
logger.info("=" * 80)
logger.info("ПОПЫТКА РЕДАКТИРОВАНИЯ СООБЩЕНИЯ")
logger.info("=" * 80)
edit_message_url = f"https://api.telegram.org/bot{POSTER_BOT_TOKEN}/editMessageText"
logger.info(f"URL запроса: {edit_message_url}")
logger.info(f"Метод: POST")
logger.info(f"Параметры запроса:")
logger.info(f" chat_id: {CHANNEL_ID}")
logger.info(f" message_id: {message_id}")
# Добавляем информацию о редактировании в конец сообщения
edited_text = f"{final_text}\n\n<i>Сообщение отредактировано через httpx клиент</i>"
logger.info(f" text_length (после редактирования): {len(edited_text)}")
logger.info(f" parse_mode: HTML")
edit_payload = {
'chat_id': CHANNEL_ID,
'message_id': message_id,
'text': edited_text,
'parse_mode': 'HTML',
'disable_web_page_preview': True
}
edit_start_time = datetime.now()
edit_response = await httpx_client.post(edit_message_url, json=edit_payload)
edit_end_time = datetime.now()
edit_duration = (edit_end_time - edit_start_time).total_seconds()
logger.info(f"Статус ответа: {edit_response.status_code}")
logger.info(f"Время запроса: {edit_duration:.2f} секунд")
if edit_response.status_code == 200:
edit_result = edit_response.json()
if edit_result.get('ok'):
logger.info("=" * 80)
logger.info("СООБЩЕНИЕ УСПЕШНО ОТРЕДАКТИРОВАНО!")
logger.info("=" * 80)
logger.info(f"Время редактирования: {edit_duration:.2f} секунд")
logger.info("=" * 80)
else:
logger.error(f"Ошибка в ответе API при редактировании: {edit_result}")
else:
logger.error(f"HTTP ошибка при редактировании: {edit_response.status_code}")
logger.error(f"Текст ответа: {edit_response.text}")
except httpx.TimeoutException 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" message_id: {message_id}")
logger.error(f" text_length: {len(edited_text)}")
except httpx.HTTPError as e:
logger.error("=" * 80)
logger.error("ОШИБКА HTTP ПРИ РЕДАКТИРОВАНИИ СООБЩЕНИЯ!")
logger.error("=" * 80)
logger.error(f"Тип ошибки: {type(e).__name__}")
logger.error(f"Сообщение: {str(e)}")
logger.error(f"Все атрибуты ошибки: {vars(e)}")
logger.error(f"Полное представление: {repr(e)}")
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 True
else:
logger.error(f"Ошибка в ответе API: {result}")
logger.error(f"Описание ошибки: {result.get('description', 'N/A')}")
logger.error(f"Код ошибки: {result.get('error_code', 'N/A')}")
return False
else:
logger.error(f"HTTP ошибка: {response.status_code}")
logger.error(f"Текст ответа: {response.text}")
return False
except httpx.TimeoutException as e:
logger.error("=" * 80) logger.error("=" * 80)
logger.error("ТАЙМАУТ ПРИ ОТПРАВКЕ СООБЩЕНИЯ!") logger.error("ТАЙМАУТ ПРИ ОТПРАВКЕ СООБЩЕНИЯ!")
logger.error("=" * 80) logger.error("=" * 80)
@@ -268,29 +356,14 @@ async def test_telegram_publish():
logger.error(f" parse_mode: HTML") logger.error(f" parse_mode: HTML")
return False return False
except RetryAfter as e: except httpx.HTTPError as e:
logger.error("=" * 80) logger.error("=" * 80)
logger.error("ОШИБКА FLOODWAIT (429) ПРИ ОТПРАВКЕ СООБЩЕНИЯ!") logger.error("ОШИБКА HTTP ПРИ ОТПРАВКЕ СООБЩЕНИЯ!")
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("=" * 80)
logger.error(f"Тип ошибки: {type(e).__name__}") logger.error(f"Тип ошибки: {type(e).__name__}")
logger.error(f"Сообщение: {str(e)}") logger.error(f"Сообщение: {str(e)}")
logger.error(f"Все атрибуты ошибки: {vars(e)}") logger.error(f"Все атрибуты ошибки: {vars(e)}")
logger.error(f"Полное представление: {repr(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 return False
except Exception as e: except Exception as e: