117 lines
4.5 KiB
Python
117 lines
4.5 KiB
Python
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=CONFIG["WEB_APP_PORT"], 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["WEB_APP_URL"]:
|
|
try:
|
|
await bot.set_chat_menu_button(
|
|
menu_button=MenuButtonWebApp(text="🚀 Dashboard", web_app=WebAppInfo(url=CONFIG["WEB_APP_URL"]))
|
|
)
|
|
logger.info(f"Menu button set to {CONFIG['WEB_APP_URL']}")
|
|
except Exception as e:
|
|
logger.error(f"Failed to set menu button: {e}")
|
|
else:
|
|
# Если URL не задан, сбрасываем кнопку (чтобы не осталась старая ссылка)
|
|
await bot.delete_chat_menu_button()
|
|
logger.info("WEB_APP_URL not found, menu button reset to default.")
|
|
|
|
logger.info(f"Config: BASE_URL={CONFIG['BASE_URL']}, WEB_APP_URL={CONFIG['WEB_APP_URL']}")
|
|
|
|
logger.info("Bot started!")
|
|
|
|
if server:
|
|
logger.info(f"Starting Web App on port {CONFIG['WEB_APP_PORT']}")
|
|
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!") |