diff --git a/.env b/.env index 15dcf82..d0fa5b2 100644 --- a/.env +++ b/.env @@ -3,18 +3,28 @@ SECRET_KEY=24af5f41dba9d8cc0dbc1841660da0b14d7df86ab5e0ed973cdd3bc2dbac23f6 LOG_FILE = /opt/testbot-git/logs/testzilantposter.log # LOG_FILE = /opt/volk/logs/volkposter.log -# WORKMODE = "ZILANT" -WORKMODE = "VOLK" +WORKMODE = "ZILANT" +# WORKMODE = "VOLK" +# Telegram API через internal_relay (retransbot) — обязательно +# Локально: http://127.0.0.1:8081 +# Через nginx: https://rbin.aabpro.ru +RELAY_URL = "https://rbin.aabpro.ru" + # Webhook Responder-bot -# WEBHOOK_URL = "https://bot.aabpro.ru/volk_bot" +# WEBHOOK_URL — адрес, по которому internal_relay доставляет апдейты боту +# (должен быть доступен с машины internal_relay). Не публичный URL для Telegram: +# Telegram ходит на external_relay; setWebhook перехватывается relay. +# WEBHOOK_URL = "http://127.0.0.1:5010/volk_bot" # WEBHOOK_PORT = 5010 # WEBHOOK_SECRET = "cc0dbc1841660da0b14d7df86ab5e0ed973c" # Webhook Responder-bot +# Пример: бот и relay на одной машине — http://127.0.0.1:5005/testbot +# Или URL через nginx, если internal_relay достучится до него WEBHOOK_URL = "https://bot.aabpro.ru/testbot" WEBHOOK_PORT = 5005 WEBHOOK_SECRET = "cc0dbc1841660da0b14d7df86ab5e0ed973c" @@ -40,16 +50,18 @@ DEFPW=Z1l@ntAdm1n23 # VK access # Zilant group -# VK_GROUP_ID = -3342146 +VK_GROUP_ID = -3342146 # VOLK group -VK_GROUP_ID = -58475527 +# VK_GROUP_ID = -58475527 VK_ACCESS_TOKEN = 'e3732a7ee3732a7ee3732a7ea7e044a75fee373e3732a7e8bf4e48a52d012e946b952a8' VK_API_VERSION = '5.131' # MySQL database # MDBASE = 'testposts' # MDBASE = 'tempzilant' # debug Zilant database -MDBASE = 'volk_test' # debug VOLK database +# Zilant 2026 database +MDBASE = 'zilant_2026' +# MDBASE = 'volk_test' # debug VOLK database # MDBASE = 'volkdata' # VOLK production database MDB_HOST = 'localhost' MDB_USER = 'testuser' @@ -61,16 +73,14 @@ MDB_PW = 'T38tU83r69' # Debug bot @posto_1638_bot # BOT_TOKEN = "8301828103:AAHDuBkw7EUkmMvv5TPpVJaLeeBLu-EB21U" # @info_1638_bot -# POSTER_BOT_TOKEN = "8215624618:AAF6VtqRtFr4twFRTiTjedSDE6txkbIy6rc" +POSTER_BOT_TOKEN = "8215624618:AAF6VtqRtFr4twFRTiTjedSDE6txkbIy6rc" # VOLK production bot @VOLK_informer_bot -POSTER_BOT_TOKEN = "8279661544:AAEsJee6icCUn_AbWxhDpk2CLxQhzaartuI" +# POSTER_BOT_TOKEN = "8279661544:AAEsJee6icCUn_AbWxhDpk2CLxQhzaartuI" # VOLK backup production bot @VOLK_informer2_bot # POSTER_BOT_TOKEN = "8001674071:AAFyGW4xibAFnuApEaSJvshqEyYHmD7RRts" # VOLK responder bot # RESPONDER_BOT_TOKEN = "8072579275:AAFiyKN1EPPnP5ZVZNTDGEriYJf1xADbfsY" # RESPONDER_BOT_NAME = "VOLK_responder_bot" - - # @posto_1638_bot RESPONDER_BOT_TOKEN = "8301828103:AAHDuBkw7EUkmMvv5TPpVJaLeeBLu-EB21U" RESPONDER_BOT_NAME = "posto_1638_bot" @@ -100,9 +110,9 @@ VK_NO_REPOST_TAG = "#окоЗиланта" # !! DB datetime is UTC !! # # Set 1 hour when Zilant is near -EVENT_POST_DELAY = 60 +# EVENT_POST_DELAY = 60 # keep 1 day when far from Zilant -# EVENT_POST_DELAY = 1440 +EVENT_POST_DELAY = 1440 # Poster channel # Debug channel @@ -120,16 +130,16 @@ MAX_TEXT_LENGTH = 4000 # # add event number and trailing / # -# PZK_PREFIX = "https://reg.konvent.ru/zk2025/draft/plan/api/add/" -# EVT_PREFIX = "https://reg.konvent.ru/zk2025/events/actions/api/" -# DESC_PREFIX = "https://reg.konvent.ru/zk2025/events/actions/" +PZK_PREFIX = "https://reg.konvent.ru/zk2026/draft/plan/api/add/" +EVT_PREFIX = "https://reg.konvent.ru/zk2026/events/actions/api/" +DESC_PREFIX = "https://reg.konvent.ru/zk2026/events/actions/" # VOLK mode API links # add category ID (volk24_larp for ex.) -VOLK_API_VERSION = "1.0" -VOLK_CATEGORY_LIST = "https://base.volk-nn.ru/api/categories?event=volk26&form=volk26_event" -VOLK_CATEGORY_DESC_PREFIX = "https://base.volk-nn.ru/api/category?event=volk26&form=volk26_event&category=" -VOLK_EVENT_LIST_PREFIX = "https://base.volk-nn.ru/api/applications?event=volk26&form=volk26_event&apps_on_page=200&page=0&category=" +# VOLK_API_VERSION = "1.0" +# VOLK_CATEGORY_LIST = "https://base.volk-nn.ru/api/categories?event=volk26&form=volk26_event" +# VOLK_CATEGORY_DESC_PREFIX = "https://base.volk-nn.ru/api/category?event=volk26&form=volk26_event&category=" +# VOLK_EVENT_LIST_PREFIX = "https://base.volk-nn.ru/api/applications?event=volk26&form=volk26_event&apps_on_page=200&page=0&category=" # Event status IS_EVENT = true @@ -143,7 +153,8 @@ LOG_DEBUG_DATA = false # OpenRouter OR_KEY = "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" -OR_MODEL_NAME = "qwen/qwen3-vl-235b-a22b-instruct" +# OR_MODEL_NAME = "qwen/qwen3-vl-235b-a22b-instruct" +OR_MODEL_NAME = "anthropic/claude-sonnet-5" # OR_MODEL_NAME = "deepseek/deepseek-chat-v3.1" # OR_MODEL_NAME = "deepseek/deepseek-r1-0528:free" # OR_MODEL_NAME = "qwen/qwen3-coder:free" diff --git a/TELEGRAM_MESSAGING.md b/TELEGRAM_MESSAGING.md index 12b726f..02202ae 100644 --- a/TELEGRAM_MESSAGING.md +++ b/TELEGRAM_MESSAGING.md @@ -20,8 +20,9 @@ API endpoint `/send_message` находится в Telegram боте, поэто ### Конфигурация портов Порты и URL настраиваются в файле `.env`: +- `RELAY_URL` - базовый URL **internal_relay** (все исходящие вызовы Bot API идут только через него) - `WEBHOOK_PORT` - порт для Telegram бота (по умолчанию 5005) -- `WEBHOOK_URL` - полный URL бота (например, https://bot.aabpro.ru/testbot) +- `WEBHOOK_URL` - URL доставки апдейтов от internal_relay к боту (доступен с машины relay; не URL, который видит Telegram напрямую) - `WEBCTRL_PORT` - порт для веб-интерфейса (по умолчанию 5006) Веб-интерфейс автоматически читает URL и порт бота из переменных окружения и использует их для отправки запросов. diff --git a/evtg_publish.py b/evtg_publish.py index 6278efb..8a0a2f7 100644 --- a/evtg_publish.py +++ b/evtg_publish.py @@ -8,6 +8,7 @@ import httpx from datetime import datetime, timezone, timedelta from dotenv import load_dotenv from formatter import get_event_text +from telegram_relay import bot_api_method_url # Загрузка переменных окружения load_dotenv() @@ -188,8 +189,8 @@ async def tg_post_event(httpx_client, event_data): logger.info(f"Текст для публикации: {initial_text[:200]}..." if len(initial_text) > 200 else f"Текст для публикации: {initial_text}") # Публикация первоначального сообщения без ссылок - send_photo_url = f"https://api.telegram.org/bot{BOT_TOKEN}/sendPhoto" - send_message_url = f"https://api.telegram.org/bot{BOT_TOKEN}/sendMessage" + send_photo_url = bot_api_method_url(BOT_TOKEN, "sendPhoto") + send_message_url = bot_api_method_url(BOT_TOKEN, "sendMessage") if has_image: try: @@ -373,8 +374,8 @@ async def tg_post_event(httpx_client, event_data): # Редактируем сообщение, добавляя ссылки logger.info(f"Попытка редактирования сообщения для события {event_data['number']}: message_id={message_id}, final_text_length={len(final_text)}") - edit_caption_url = f"https://api.telegram.org/bot{BOT_TOKEN}/editMessageCaption" - edit_text_url = f"https://api.telegram.org/bot{BOT_TOKEN}/editMessageText" + edit_caption_url = bot_api_method_url(BOT_TOKEN, "editMessageCaption") + edit_text_url = bot_api_method_url(BOT_TOKEN, "editMessageText") if has_image: try: diff --git a/telegram_relay.py b/telegram_relay.py new file mode 100644 index 0000000..772a88a --- /dev/null +++ b/telegram_relay.py @@ -0,0 +1,49 @@ +""" +Конфигурация доступа к Telegram Bot API через internal_relay (retransbot). + +Все исходящие вызовы Bot API должны идти на RELAY_URL, а не на api.telegram.org. +""" + +import os +from typing import Tuple + +from dotenv import load_dotenv + + +def get_relay_url() -> str: + """Базовый URL internal_relay без завершающего слэша.""" + load_dotenv() + relay = (os.getenv("RELAY_URL") or "").rstrip("/") + if not relay: + raise RuntimeError( + "Требуется переменная окружения RELAY_URL " + "(базовый URL internal_relay, например http://127.0.0.1:8081)" + ) + return relay + + +def configure_telebot_api() -> str: + """ + Настраивает pyTelegramBotAPI (telebot.apihelper) на работу через relay. + Вызывать до создания TeleBot. + """ + from telebot import apihelper + + relay = get_relay_url() + apihelper.API_URL = f"{relay}/bot{{0}}/{{1}}" + apihelper.FILE_URL = f"{relay}/file/bot{{0}}/{{1}}" + return relay + + +def get_ptb_base_urls() -> Tuple[str, str]: + """ + base_url и base_file_url для python-telegram-bot.Bot. + Формат как в Bot API: .../bot и .../file/bot (библиотека сама дописывает token/method). + """ + relay = get_relay_url() + return f"{relay}/bot", f"{relay}/file/bot" + + +def bot_api_method_url(token: str, method: str) -> str: + """Полный URL метода Bot API через relay (для сырых httpx/requests вызовов).""" + return f"{get_relay_url()}/bot{token}/{method}" diff --git a/test_tg_poster.py b/test_tg_poster.py index f485be8..1b8c340 100644 --- a/test_tg_poster.py +++ b/test_tg_poster.py @@ -6,6 +6,7 @@ from dotenv import load_dotenv from telegram import Bot from telegram.error import TelegramError, TimedOut from telegram.request import HTTPXRequest +from telegram_relay import get_ptb_base_urls, get_relay_url # Загрузка переменных окружения load_dotenv() @@ -74,8 +75,15 @@ async def make_test_post_async(): media_write_timeout=120.0 # Таймаут для медиа (на будущее) ) - # Создание экземпляра бота с кастомным Request - bot = Bot(token=POSTER_BOT_TOKEN, request=request) + # Создание экземпляра бота через internal_relay + base_url, base_file_url = get_ptb_base_urls() + bot = Bot( + token=POSTER_BOT_TOKEN, + request=request, + base_url=base_url, + base_file_url=base_file_url, + ) + logger.info(f"Telegram Bot API через ретранслятор: {get_relay_url()}") # Определяем путь к изображению в том же каталоге, что и скрипт script_dir = os.path.dirname(os.path.abspath(__file__)) diff --git a/tg_mainbot.py b/tg_mainbot.py index 3f96311..8374510 100644 --- a/tg_mainbot.py +++ b/tg_mainbot.py @@ -14,6 +14,7 @@ import requests from io import BytesIO from flask import Flask, request from formatter import get_post_text, get_event_text +from telegram_relay import configure_telebot_api, get_relay_url # Создаем Flask app на верхнем уровне для экспорта app = Flask(__name__) @@ -28,6 +29,7 @@ WEBHOOK_URL = os.getenv('WEBHOOK_URL') WEBHOOK_PORT = int(os.getenv('WEBHOOK_PORT', '8443')) WEBHOOK_SECRET = os.getenv('WEBHOOK_SECRET') LOG_FILE = os.getenv('LOG_FILE', 'bot.log') +RELAY_URL = os.getenv('RELAY_URL') # Настройка логирования logger = logging.getLogger('TG_bot') @@ -149,6 +151,7 @@ required_vars = { "RESPONDER_BOT_TOKEN": RESPONDER_BOT_TOKEN, "CHANNEL_ID": CHANNEL_ID, "WEBHOOK_URL": WEBHOOK_URL, + "RELAY_URL": RELAY_URL, "MDB_HOST": MDB_HOST, "MDB_USER": MDB_USER, "MDB_PW": MDB_PW, @@ -165,6 +168,10 @@ apihelper.READ_TIMEOUT = 120 # Таймаут на чтение ответа ( apihelper.CONNECT_TIMEOUT = 30 # Таймаут на подключение apihelper.RETRY_ON_TIMEOUT = True # Автоматические повторные попытки при таймауте +# Весь Bot API — только через internal_relay +relay = configure_telebot_api() +logger.info(f"Telegram Bot API через ретранслятор: {relay}") + # Создаем экземпляр бота bot = telebot.TeleBot(RESPONDER_BOT_TOKEN) @@ -1438,7 +1445,7 @@ def setup_webhook(): secret_token=WEBHOOK_SECRET, max_connections=40 ) - logger.info(f"Вебхук установлен: {WEBHOOK_URL}") + logger.info(f"Вебхук установлен через ретранслятор {get_relay_url()}: локальная доставка {WEBHOOK_URL}") logger.info(f"Секретный токен: {'установлен' if WEBHOOK_SECRET else 'не установлен'}") logger.info(f"Прослушивание порта: {WEBHOOK_PORT}") logger.info(f"Путь вебхука: {WEBHOOK_PATH}") diff --git a/tg_publish.py b/tg_publish.py index 5893e67..c2112dc 100644 --- a/tg_publish.py +++ b/tg_publish.py @@ -16,6 +16,7 @@ from formatter import get_event_text from telegram import Bot from telegram.error import TelegramError, TimedOut from telegram.request import HTTPXRequest +from telegram_relay import get_ptb_base_urls, get_relay_url # Настройка anyio для правильной работы в отдельном потоке # Устанавливаем правильный backend для anyio (используем asyncio) @@ -182,8 +183,15 @@ async def publish_to_tg(vk_post_id): media_write_timeout=120.0 # Таймаут для медиа ) - # Создание экземпляра бота с кастомным Request - bot = Bot(token=BOT_TOKEN, request=request) + # Bot API только через internal_relay + base_url, base_file_url = get_ptb_base_urls() + bot = Bot( + token=BOT_TOKEN, + request=request, + base_url=base_url, + base_file_url=base_file_url, + ) + logger.info(f"Telegram Bot API через ретранслятор: {get_relay_url()}") # Создаем httpx клиент только для скачивания изображений timeout_config = httpx.Timeout( diff --git a/volk_cat_publish.py b/volk_cat_publish.py index b2edf64..0cf660a 100644 --- a/volk_cat_publish.py +++ b/volk_cat_publish.py @@ -8,6 +8,7 @@ import httpx from datetime import datetime, timezone from dotenv import load_dotenv from formatter import get_event_text +from telegram_relay import bot_api_method_url # Загрузка переменных окружения load_dotenv() @@ -113,8 +114,8 @@ async def tg_post_category(httpx_client, category_data): logger.info(f"Текст для публикации: {initial_text[:200]}..." if len(initial_text) > 200 else f"Текст для публикации: {initial_text}") # Публикация сообщения - send_photo_url = f"https://api.telegram.org/bot{BOT_TOKEN}/sendPhoto" - send_message_url = f"https://api.telegram.org/bot{BOT_TOKEN}/sendMessage" + send_photo_url = bot_api_method_url(BOT_TOKEN, "sendPhoto") + send_message_url = bot_api_method_url(BOT_TOKEN, "sendMessage") if has_image: try: diff --git a/volk_telegram_testing.py b/volk_telegram_testing.py index ea6b88e..1e226db 100644 --- a/volk_telegram_testing.py +++ b/volk_telegram_testing.py @@ -7,6 +7,7 @@ import sys import json from datetime import datetime from dotenv import load_dotenv +from telegram_relay import bot_api_method_url, get_relay_url # Загрузка переменных окружения load_dotenv() @@ -68,6 +69,7 @@ async def test_telegram_publish(): 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}") + logger.info(f" RELAY_URL: {get_relay_url()}") # Проверка обязательных параметров if not POSTER_BOT_TOKEN: @@ -147,7 +149,7 @@ async def test_telegram_publish(): logger.info("=" * 80) logger.info("ПОПЫТКА ПОЛУЧЕНИЯ ИНФОРМАЦИИ О БОТЕ") logger.info("=" * 80) - get_me_url = f"https://api.telegram.org/bot{POSTER_BOT_TOKEN}/getMe" + get_me_url = bot_api_method_url(POSTER_BOT_TOKEN, "getMe") logger.info(f"URL запроса: {get_me_url}") logger.info(f"Метод: GET") @@ -209,7 +211,7 @@ async def test_telegram_publish(): logger.info("=" * 80) logger.info("ПОПЫТКА ОТПРАВКИ ТЕСТОВОГО СООБЩЕНИЯ") logger.info("=" * 80) - send_message_url = f"https://api.telegram.org/bot{POSTER_BOT_TOKEN}/sendMessage" + send_message_url = bot_api_method_url(POSTER_BOT_TOKEN, "sendMessage") logger.info(f"URL запроса: {send_message_url}") logger.info(f"Метод: POST") logger.info(f"Параметры запроса:") @@ -258,7 +260,7 @@ async def test_telegram_publish(): logger.info("=" * 80) logger.info("ПОПЫТКА РЕДАКТИРОВАНИЯ СООБЩЕНИЯ") logger.info("=" * 80) - edit_message_url = f"https://api.telegram.org/bot{POSTER_BOT_TOKEN}/editMessageText" + edit_message_url = bot_api_method_url(POSTER_BOT_TOKEN, "editMessageText") logger.info(f"URL запроса: {edit_message_url}") logger.info(f"Метод: POST") logger.info(f"Параметры запроса:") @@ -336,7 +338,7 @@ async def test_telegram_publish(): logger.info("=" * 80) logger.info("ПОПЫТКА ОТПРАВКИ ТЕСТОВОГО СООБЩЕНИЯ С КАРТИНКОЙ") logger.info("=" * 80) - send_photo_url = f"https://api.telegram.org/bot{POSTER_BOT_TOKEN}/sendPhoto" + send_photo_url = bot_api_method_url(POSTER_BOT_TOKEN, "sendPhoto") image_url = "https://base.volk-nn.ru/uploads/events/volk26/volk26_event/20251210_175059_0.jpg" # Формируем текст для сообщения с картинкой @@ -391,7 +393,7 @@ async def test_telegram_publish(): logger.info("=" * 80) logger.info("ПОПЫТКА РЕДАКТИРОВАНИЯ СООБЩЕНИЯ С КАРТИНКОЙ") logger.info("=" * 80) - edit_photo_caption_url = f"https://api.telegram.org/bot{POSTER_BOT_TOKEN}/editMessageCaption" + edit_photo_caption_url = bot_api_method_url(POSTER_BOT_TOKEN, "editMessageCaption") logger.info(f"URL запроса: {edit_photo_caption_url}") logger.info(f"Метод: POST") logger.info(f"Параметры запроса:")