surfaces/adapter/telegram/bot.py

110 lines
3.7 KiB
Python

# 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())