main functional bot. BugFixing required

This commit is contained in:
2025-08-17 16:16:49 +09:00
parent 8e782bd741
commit 43dda889f8
3 changed files with 332 additions and 88 deletions

View File

@@ -992,95 +992,87 @@ async def _dispatch_with_eta(uid: int, when: datetime) -> None:
logger.error(f"Error in _dispatch_with_eta: {e}")
raise
def main():
"""Инициализация и запуск бота."""
try:
# Настройка логирования
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.INFO
)
# Инициализация планировщика
scheduler = AsyncIOScheduler()
scheduler.add_job(cleanup_old_sessions, 'interval', minutes=30)
scheduler.start()
app = Application.builder().token(settings.editor_bot_token).build()
# Регистрация обработчиков
post_conv = ConversationHandler(
entry_points=[CommandHandler("newpost", newpost)],
states={
CHOOSE_CHANNEL: [CallbackQueryHandler(choose_channel, pattern=r"^channel:")],
CHOOSE_TYPE: [CallbackQueryHandler(choose_type, pattern=r"^type:")],
CHOOSE_FORMAT: [CallbackQueryHandler(choose_format, pattern=r"^fmt:")],
ENTER_TEXT: [
MessageHandler(filters.TEXT & ~filters.COMMAND, enter_text),
CallbackQueryHandler(choose_template_open, pattern=r"^tpl:choose$"),
],
SELECT_TEMPLATE: [
CallbackQueryHandler(choose_template_apply, pattern=r"^tpluse:"),
CallbackQueryHandler(choose_template_preview, pattern=r"^tplprev:"),
CallbackQueryHandler(choose_template_navigate, pattern=r"^tplpage:"),
CallbackQueryHandler(choose_template_cancel, pattern=r"^tpl:cancel$"),
],
PREVIEW_VARS: [
MessageHandler(filters.TEXT & ~filters.COMMAND, preview_collect_vars)
],
PREVIEW_CONFIRM: [
CallbackQueryHandler(preview_confirm, pattern=r"^pv:(use|edit)$"),
CallbackQueryHandler(choose_template_cancel, pattern=r"^tpl:cancel$"),
],
ENTER_MEDIA: [
MessageHandler(filters.TEXT & ~filters.COMMAND, enter_media)
],
EDIT_KEYBOARD: [
MessageHandler(filters.TEXT & ~filters.COMMAND, edit_keyboard)
],
CONFIRM_SEND: [
CallbackQueryHandler(confirm_send, pattern=r"^send:")
],
ENTER_SCHEDULE: [
MessageHandler(filters.TEXT & ~filters.COMMAND, enter_schedule)
],
},
fallbacks=[CommandHandler("start", start)],
)
def init_application():
"""Инициализация приложения и регистрация обработчиков."""
# Настройка логирования
logging.basicConfig(
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
level=logging.INFO
)
# Инициализация бота
app = Application.builder().token(settings.editor_bot_token).build()
# Создание обработчика постов
post_conv = ConversationHandler(
entry_points=[CommandHandler("newpost", newpost)],
states={
CHOOSE_CHANNEL: [CallbackQueryHandler(choose_channel, pattern=r"^channel:")],
CHOOSE_TYPE: [CallbackQueryHandler(choose_type, pattern=r"^type:")],
CHOOSE_FORMAT: [CallbackQueryHandler(choose_format, pattern=r"^fmt:")],
ENTER_TEXT: [
MessageHandler(filters.TEXT & ~filters.COMMAND, enter_text),
CallbackQueryHandler(choose_template_open, pattern=r"^tpl:choose$"),
],
SELECT_TEMPLATE: [
CallbackQueryHandler(choose_template_apply, pattern=r"^tpluse:"),
CallbackQueryHandler(choose_template_preview, pattern=r"^tplprev:"),
CallbackQueryHandler(choose_template_navigate, pattern=r"^tplpage:"),
CallbackQueryHandler(choose_template_cancel, pattern=r"^tpl:cancel$"),
],
PREVIEW_VARS: [
MessageHandler(filters.TEXT & ~filters.COMMAND, preview_collect_vars)
],
PREVIEW_CONFIRM: [
CallbackQueryHandler(preview_confirm, pattern=r"^pv:(use|edit)$"),
CallbackQueryHandler(choose_template_cancel, pattern=r"^tpl:cancel$"),
],
ENTER_MEDIA: [
MessageHandler(filters.TEXT & ~filters.COMMAND, enter_media)
],
EDIT_KEYBOARD: [
MessageHandler(filters.TEXT & ~filters.COMMAND, edit_keyboard)
],
CONFIRM_SEND: [
CallbackQueryHandler(confirm_send, pattern=r"^send:")
],
ENTER_SCHEDULE: [
MessageHandler(filters.TEXT & ~filters.COMMAND, enter_schedule)
],
},
fallbacks=[CommandHandler("start", start)],
)
tpl_conv = ConversationHandler(
entry_points=[CommandHandler("tpl_new", tpl_new_start)],
states={
TPL_NEW_NAME: [
MessageHandler(filters.TEXT & ~filters.COMMAND, tpl_new_name)
],
TPL_NEW_TYPE: [
CallbackQueryHandler(tpl_new_type, pattern=r"^tpltype:")
],
TPL_NEW_FORMAT: [
CallbackQueryHandler(tpl_new_format, pattern=r"^tplfmt:")
],
TPL_NEW_CONTENT: [
MessageHandler(filters.TEXT & ~filters.COMMAND, tpl_new_content)
],
TPL_NEW_KB: [
MessageHandler(filters.TEXT & ~filters.COMMAND, tpl_new_kb)
],
},
fallbacks=[CommandHandler("start", start)],
)
# Создание обработчика шаблонов
tpl_conv = ConversationHandler(
entry_points=[CommandHandler("tpl_new", tpl_new_start)],
states={
TPL_NEW_NAME: [
MessageHandler(filters.TEXT & ~filters.COMMAND, tpl_new_name)
],
TPL_NEW_TYPE: [
CallbackQueryHandler(tpl_new_type, pattern=r"^tpltype:")
],
TPL_NEW_FORMAT: [
CallbackQueryHandler(tpl_new_format, pattern=r"^tplfmt:")
],
TPL_NEW_CONTENT: [
MessageHandler(filters.TEXT & ~filters.COMMAND, tpl_new_content)
],
TPL_NEW_KB: [
MessageHandler(filters.TEXT & ~filters.COMMAND, tpl_new_kb)
],
},
fallbacks=[CommandHandler("start", start)],
)
app.add_handler(CommandHandler("start", start))
app.add_handler(post_conv)
app.add_handler(tpl_conv)
app.add_handler(CommandHandler("tpl_list", tpl_list))
# Запуск бота
app.run_polling(allowed_updates=Update.ALL_TYPES)
except Exception as e:
logger.critical(f"Critical error in main: {e}")
raise
# Регистрация всех обработчиков
app.add_handler(CommandHandler("start", start))
app.add_handler(post_conv)
app.add_handler(tpl_conv)
app.add_handler(CommandHandler("tpl_list", tpl_list))
return app
# -------- Вспомогательные функции для шаблонов ---------
@@ -1511,5 +1503,132 @@ async def choose_template_cancel(update: Update, context: CallbackContext) -> in
)
return ENTER_TEXT
import asyncio
import signal
from contextlib import suppress
class BotApplication:
"""Класс для управления жизненным циклом бота и планировщика."""
def __init__(self):
self.app = None
self.scheduler = None
self.loop = None
self._shutdown = False
def signal_handler(self, signum, frame):
"""Обработчик сигналов для корректного завершения."""
self._shutdown = True
if self.loop:
self.loop.stop()
async def shutdown(self):
"""Корректное завершение работы всех компонентов."""
if self.scheduler:
with suppress(Exception):
self.scheduler.shutdown()
if self.app:
with suppress(Exception):
await self.app.stop()
with suppress(Exception):
await self.app.shutdown()
async def run_bot(self):
"""Запуск бота и планировщика."""
try:
# Инициализация приложения
self.app = init_application()
if not self.app:
logger.critical("Failed to initialize application")
return
# Настройка планировщика
self.scheduler = AsyncIOScheduler()
self.scheduler.add_job(cleanup_old_sessions, 'interval', minutes=30)
# Инициализация приложения
await self.app.initialize()
await self.app.start()
# Запуск планировщика
self.scheduler.start()
# Запуск бота
while not self._shutdown:
try:
await self.app.updater.start_polling()
except Exception as e:
if not self._shutdown:
logger.error(f"Polling error: {e}")
await asyncio.sleep(1)
else:
break
except Exception as e:
logger.critical(f"Critical error: {e}")
finally:
await self.shutdown()
async def init_bot():
"""Инициализация и настройка бота."""
try:
application = init_application()
if not application:
logger.critical("Не удалось инициализировать приложение")
return None
return application
except Exception as e:
logger.critical(f"Ошибка при инициализации бота: {e}")
return None
def start_bot():
"""Запуск бота с правильным управлением циклом событий."""
loop = None
try:
# Создаем и настраиваем цикл событий
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
# Инициализируем бота
application = loop.run_until_complete(init_bot())
if not application:
return
# Запускаем бота с правильным управлением циклом событий
from app.bots.bot_runner import run_bot
run_bot(application, cleanup_old_sessions)
except Exception as e:
logger.critical(f"Критическая ошибка при запуске бота: {e}")
raise
finally:
if loop:
try:
loop.close()
except Exception as e:
logger.error(f"Ошибка при закрытии цикла событий: {e}")
try:
# Создаем и настраиваем цикл событий
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
# Инициализируем бота
application = loop.run_until_complete(init_bot())
if not application:
return
# Запускаем бота с правильным управлением циклом событий
from app.bots.bot_runner import run_bot
run_bot(application, cleanup_old_sessions)
except Exception as e:
logger.critical(f"Критическая ошибка при запуске бота: {e}")
raise
finally:
if loop:
try:
loop.close()
except Exception as e:
logger.error(f"Ошибка при закрытии цикла событий: {e}")
if __name__ == "__main__":
main()
start_bot()