[ВОЛК] переход на прямого httpx клиента для постинга в телеграм
ci/woodpecker/push/woodpecker Pipeline was successful
ci/woodpecker/push/woodpecker Pipeline was successful
This commit is contained in:
+165
-92
@@ -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()
|
||||||
|
if result.get('ok'):
|
||||||
|
message_data = result.get('result', {})
|
||||||
|
message_id = message_data.get('message_id')
|
||||||
|
chat_data = message_data.get('chat', {})
|
||||||
|
|
||||||
except TimedOut as e:
|
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:
|
||||||
|
|||||||
Reference in New Issue
Block a user