# adapter/telegram/bot.py from __future__ import annotations import asyncio import os import structlog from aiogram import Bot, Dispatcher from aiogram.fsm.storage.memory import MemoryStorage from aiogram.types import BotCommand from adapter.telegram import db from adapter.telegram.handlers import auth, chat, confirm, forum, settings from core.auth import AuthManager from core.chat import ChatManager from core.handler import EventDispatcher from core.handlers.callback import handle_confirm as core_handle_confirm from core.handlers.chat import handle_archive, handle_list_chats, handle_new_chat, handle_rename from core.handlers.message import handle_message from core.handlers.settings import ( handle_settings, handle_settings_skills, ) from core.handlers.start import handle_start from core.settings import SettingsManager from core.store import InMemoryStore from sdk.mock import MockPlatformClient logger = structlog.get_logger(__name__) class DispatcherMiddleware: """Injects EventDispatcher into every handler via data dict.""" def __init__(self, dispatcher: EventDispatcher) -> None: self._dispatcher = dispatcher async def __call__(self, handler, event, data): data["dispatcher"] = self._dispatcher return await handler(event, data) def build_event_dispatcher(platform: MockPlatformClient) -> EventDispatcher: store = InMemoryStore() chat_mgr = ChatManager(platform, store) auth_mgr = AuthManager(platform, store) settings_mgr = SettingsManager(platform, store) ed = EventDispatcher( platform=platform, chat_mgr=chat_mgr, auth_mgr=auth_mgr, settings_mgr=settings_mgr, ) # Register core handlers from core.protocol import IncomingCallback, IncomingCommand, IncomingMessage ed.register(IncomingCommand, "start", handle_start) ed.register(IncomingCommand, "settings", handle_settings) ed.register(IncomingCommand, "settings_skills", handle_settings_skills) ed.register(IncomingCommand, "new", handle_new_chat) ed.register(IncomingCommand, "chats", handle_list_chats) ed.register(IncomingCommand, "rename", handle_rename) ed.register(IncomingCommand, "archive", handle_archive) ed.register(IncomingMessage, "*", handle_message) ed.register(IncomingCallback, "confirm", core_handle_confirm) ed.register(IncomingCallback, "cancel", core_handle_confirm) return ed async def main() -> None: token = os.environ.get("BOT_TOKEN") if not token: raise RuntimeError("BOT_TOKEN env variable is not set") db.init_db() bot = Bot(token=token) storage = MemoryStorage() dp = Dispatcher(storage=storage) platform = MockPlatformClient() event_dispatcher = build_event_dispatcher(platform) # Register middleware on all update types dp.message.middleware(DispatcherMiddleware(event_dispatcher)) dp.callback_query.middleware(DispatcherMiddleware(event_dispatcher)) # Include routers dp.include_router(auth.router) dp.include_router(forum.router) dp.include_router(chat.router) dp.include_router(settings.router) dp.include_router(confirm.router) await bot.set_my_commands([ BotCommand(command="start", description="Начать / восстановить сессию"), BotCommand(command="new", description="Создать новый чат"), BotCommand(command="chats", description="Список чатов"), BotCommand(command="settings", description="Настройки"), BotCommand(command="forum", description="Подключить Forum-группу"), ]) logger.info("Bot starting") await dp.start_polling(bot) if __name__ == "__main__": asyncio.run(main())