136 lines
4.6 KiB
Python
136 lines
4.6 KiB
Python
import asyncio
|
|
import logging
|
|
from pathlib import Path
|
|
|
|
from aiogram import Bot, Dispatcher
|
|
from aiogram.client.default import DefaultBotProperties
|
|
from aiogram.client.session.aiohttp import AiohttpSession
|
|
from aiogram.enums import ParseMode
|
|
from aiogram.exceptions import TelegramNetworkError
|
|
from aiogram.types import BotCommand
|
|
|
|
from app.bot.handlers.main import build_router
|
|
from app.config import Settings
|
|
from app.db.session import create_engine_and_session_factory, ensure_database_exists, init_db
|
|
from app.services.bot_config_service import BotConfigService
|
|
from app.services.notification_service import SubscriptionNotificationService
|
|
from app.services.payment_service import PaymentService
|
|
from app.services.remnawave_client import RemnawaveApiClient
|
|
from app.services.support_ticket_service import SupportTicketService
|
|
from app.services.sync_service import SyncService
|
|
|
|
|
|
async def main() -> None:
|
|
settings = Settings()
|
|
|
|
logging.basicConfig(
|
|
level=getattr(logging, settings.log_level.upper(), logging.INFO),
|
|
format="%(asctime)s | %(levelname)s | %(name)s | %(message)s",
|
|
)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
engine = None
|
|
remnawave_client = None
|
|
bot = None
|
|
|
|
try:
|
|
if settings.create_database_on_start:
|
|
logger.info(
|
|
"Ensuring MariaDB database '%s' exists on %s:%s",
|
|
settings.db_name,
|
|
settings.db_host,
|
|
settings.db_port,
|
|
)
|
|
await ensure_database_exists(
|
|
settings.database_server_url,
|
|
settings.db_name,
|
|
echo=settings.db_echo,
|
|
)
|
|
|
|
engine, session_factory = create_engine_and_session_factory(
|
|
settings.database_url,
|
|
echo=settings.db_echo,
|
|
)
|
|
|
|
if settings.create_tables_on_start:
|
|
await init_db(engine)
|
|
|
|
remnawave_client = RemnawaveApiClient(
|
|
base_url=settings.remnawave_base_url,
|
|
api_token=settings.remnawave_api_token,
|
|
caddy_api_key=settings.remnawave_caddy_api_key,
|
|
timeout_seconds=settings.remnawave_timeout_seconds,
|
|
)
|
|
sync_service = SyncService(
|
|
settings=settings,
|
|
session_factory=session_factory,
|
|
remnawave_client=remnawave_client,
|
|
)
|
|
bot_config_service = BotConfigService(
|
|
settings=settings,
|
|
session_factory=session_factory,
|
|
)
|
|
support_ticket_service = SupportTicketService(session_factory=session_factory)
|
|
payment_service = PaymentService(
|
|
settings=settings,
|
|
session_factory=session_factory,
|
|
remnawave_client=remnawave_client,
|
|
sync_service=sync_service,
|
|
config_service=bot_config_service,
|
|
)
|
|
|
|
bot_session = AiohttpSession(proxy=settings.telegram_proxy_url or None)
|
|
bot = Bot(
|
|
token=settings.bot_token,
|
|
session=bot_session,
|
|
default=DefaultBotProperties(parse_mode=ParseMode.HTML),
|
|
)
|
|
dispatcher = Dispatcher()
|
|
dispatcher.include_router(
|
|
build_router(
|
|
settings=settings,
|
|
sync_service=sync_service,
|
|
support_ticket_service=support_ticket_service,
|
|
payment_service=payment_service,
|
|
bot_config_service=bot_config_service,
|
|
)
|
|
)
|
|
|
|
await bot.set_my_commands(
|
|
[
|
|
BotCommand(command="start", description="Открыть главное меню"),
|
|
]
|
|
)
|
|
|
|
project_root = Path(__file__).resolve().parent.parent
|
|
notification_service = SubscriptionNotificationService(
|
|
session_factory=session_factory,
|
|
sync_service=sync_service,
|
|
config_service=bot_config_service,
|
|
project_root=project_root,
|
|
)
|
|
notification_task = asyncio.create_task(
|
|
notification_service.run_periodic(bot),
|
|
)
|
|
|
|
try:
|
|
await dispatcher.start_polling(bot)
|
|
finally:
|
|
notification_task.cancel()
|
|
try:
|
|
await notification_task
|
|
except asyncio.CancelledError:
|
|
pass
|
|
except TelegramNetworkError:
|
|
logger.exception(
|
|
"Cannot reach Telegram API. Check outbound HTTPS access to api.telegram.org:443, DNS, firewall, VPN, or proxy."
|
|
)
|
|
raise
|
|
finally:
|
|
if remnawave_client is not None:
|
|
await remnawave_client.close()
|
|
if bot is not None:
|
|
await bot.session.close()
|
|
if engine is not None:
|
|
await engine.dispose()
|