import asyncio import logging from datetime import datetime from aiogram import Bot, Dispatcher from aiogram.fsm.storage.memory import MemoryStorage from apscheduler.schedulers.asyncio import AsyncIOScheduler from config import CONFIG from database import db from marzban import marzban from handlers import routers # Настройка логирования logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) logger = logging.getLogger(__name__) # Assuming grant_subscription is defined elsewhere or was intended to be added here. # Based on the user's instruction and the provided "Code Edit" snippet, # it seems the user intended to add or modify this function. # Since the original content does not contain this function, I will add it # at the module level, as it's a common pattern for helper functions. # The "Code Edit" snippet was syntactically incorrect in its placement, # so I'm placing it logically. # Note: 'PLANS' is not defined in the provided content, assuming it's imported or defined elsewhere. # The '... rest of logic uses expire_days ...' part is a placeholder as it was in the instruction. async def grant_subscription(user_id, plan_id, is_unlimited_promo=False, bonus_days=0): # This function body is taken directly from the user's instruction. # 'PLANS' is not defined in the provided document, assuming it's available globally. # This is a placeholder for the actual implementation. PLANS = {} # Placeholder for demonstration, replace with actual PLANS source plan = PLANS.get(plan_id) if not plan and not is_unlimited_promo: return # Determine duration and data limit if is_unlimited_promo: expire_days = 365 * 10 # 10 years data_limit = 0 # Unlimited else: expire_days = plan['days'] + bonus_days data_limit = plan['limit_gb'] # ... rest of logic uses expire_days ... # This part was indicated by '{{ ... }}' in the user's instruction, # implying existing logic that uses expire_days. # For now, it's a comment. logger.info(f"Granting subscription for user {user_id} with plan {plan_id}. " f"Expire days: {expire_days}, Data limit: {data_limit} GB.") async def main(): # Инициализация бота bot = Bot(token=CONFIG["BOT_TOKEN"]) dp = Dispatcher(storage=MemoryStorage()) # Подключение роутеров из папки handlers for router in routers: dp.include_router(router) # Инициализация сервисов await db.connect() await marzban.init_session() # Web Server setup try: from server import app as web_app import uvicorn web_app.state.bot = bot config = uvicorn.Config(web_app, host="0.0.0.0", port=8000, log_level="info") server = uvicorn.Server(config) except ImportError: logger.error("Could not import server or uvicorn") server = None try: await bot.delete_webhook(drop_pending_updates=True) # Set Menu Button from aiogram.types import MenuButtonWebApp, WebAppInfo if CONFIG["BASE_URL"]: try: await bot.set_chat_menu_button( menu_button=MenuButtonWebApp(text="🚀 Dashboard", web_app=WebAppInfo(url=CONFIG["BASE_URL"])) ) logger.info(f"Menu button set to {CONFIG['BASE_URL']}") except Exception as e: logger.error(f"Failed to set menu button: {e}") logger.info("Bot started!") if server: logger.info("Starting Web App on port 8000") await asyncio.gather( dp.start_polling(bot), server.serve() ) else: await dp.start_polling(bot) finally: await marzban.close_session() await bot.session.close() if __name__ == "__main__": try: asyncio.run(main()) except (KeyboardInterrupt, SystemExit): logger.info("Bot stopped!")