mirror of
https://github.com/BEDOLAGA-DEV/remnawave-bedolaga-telegram-bot.git
synced 2026-01-20 03:40:26 +00:00
164 lines
5.5 KiB
Python
164 lines
5.5 KiB
Python
import asyncio
|
|
import logging
|
|
import sys
|
|
import os
|
|
from aiogram import Bot, Dispatcher
|
|
from aiogram.fsm.storage.memory import MemoryStorage
|
|
from aiogram.client.default import DefaultBotProperties
|
|
from aiogram.enums import ParseMode
|
|
|
|
# Import our modules
|
|
from config import load_config
|
|
from database import Database
|
|
from remnawave_api import RemnaWaveAPI
|
|
from middlewares import DatabaseMiddleware, UserMiddleware, LoggingMiddleware, ThrottlingMiddleware, WorkflowDataMiddleware, BotMiddleware
|
|
from handlers import router
|
|
from admin_handlers import admin_router
|
|
|
|
# Configure logging
|
|
logging.basicConfig(
|
|
level=logging.INFO,
|
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
|
|
handlers=[
|
|
logging.FileHandler('bot.log'),
|
|
logging.StreamHandler(sys.stdout)
|
|
]
|
|
)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
async def main():
|
|
"""Main function"""
|
|
try:
|
|
# Load configuration
|
|
config = load_config()
|
|
|
|
# Validate required environment variables
|
|
if not config.BOT_TOKEN:
|
|
logger.error("BOT_TOKEN is required")
|
|
return
|
|
|
|
if not config.REMNAWAVE_URL or not config.REMNAWAVE_TOKEN:
|
|
logger.error("REMNAWAVE_URL and REMNAWAVE_TOKEN are required")
|
|
return
|
|
|
|
logger.info("Starting RemnaWave Bot...")
|
|
logger.info(f"RemnaWave URL: {config.REMNAWAVE_URL}")
|
|
logger.info(f"Admin IDs: {config.ADMIN_IDS}")
|
|
|
|
# Initialize database
|
|
db = Database(config.DATABASE_URL)
|
|
|
|
# Try to initialize database with retry logic
|
|
max_retries = 3
|
|
for attempt in range(max_retries):
|
|
try:
|
|
await db.init_db()
|
|
logger.info("Database initialized successfully")
|
|
break
|
|
except Exception as e:
|
|
logger.error(f"Database initialization attempt {attempt + 1} failed: {e}")
|
|
if attempt == max_retries - 1:
|
|
logger.error("Failed to initialize database after all retries")
|
|
return
|
|
await asyncio.sleep(2) # Wait before retry
|
|
|
|
# Initialize RemnaWave API
|
|
api = RemnaWaveAPI(config.REMNAWAVE_URL, config.REMNAWAVE_TOKEN, config.SUBSCRIPTION_BASE_URL)
|
|
logger.info("RemnaWave API initialized")
|
|
|
|
# Test API connection (optional - don't fail if it doesn't work)
|
|
try:
|
|
system_stats = await api.get_system_stats()
|
|
if system_stats:
|
|
logger.info("RemnaWave API connection successful")
|
|
else:
|
|
logger.warning("RemnaWave API connection test failed - continuing anyway")
|
|
except Exception as e:
|
|
logger.warning(f"RemnaWave API connection error: {e} - continuing anyway")
|
|
|
|
# Initialize bot and dispatcher
|
|
bot = Bot(
|
|
token=config.BOT_TOKEN,
|
|
default=DefaultBotProperties(parse_mode=ParseMode.HTML)
|
|
)
|
|
|
|
storage = MemoryStorage()
|
|
dp = Dispatcher(storage=storage)
|
|
|
|
# Store config, api, and db in dispatcher workflow_data for access in handlers
|
|
dp.workflow_data.update({
|
|
"config": config,
|
|
"api": api,
|
|
"db": db
|
|
})
|
|
|
|
# Setup middlewares in correct order
|
|
dp.message.middleware(LoggingMiddleware())
|
|
dp.callback_query.middleware(LoggingMiddleware())
|
|
|
|
dp.message.middleware(ThrottlingMiddleware(rate_limit=0.5))
|
|
dp.callback_query.middleware(ThrottlingMiddleware(rate_limit=0.3))
|
|
|
|
dp.message.middleware(WorkflowDataMiddleware())
|
|
dp.callback_query.middleware(WorkflowDataMiddleware())
|
|
|
|
dp.message.middleware(BotMiddleware(bot))
|
|
dp.callback_query.middleware(BotMiddleware(bot))
|
|
|
|
dp.message.middleware(DatabaseMiddleware(db))
|
|
dp.callback_query.middleware(DatabaseMiddleware(db))
|
|
|
|
dp.message.middleware(UserMiddleware(db, config))
|
|
dp.callback_query.middleware(UserMiddleware(db, config))
|
|
|
|
# Register routers
|
|
dp.include_router(router)
|
|
dp.include_router(admin_router)
|
|
|
|
# Setup shutdown handler
|
|
async def on_shutdown():
|
|
logger.info("Shutting down bot...")
|
|
try:
|
|
await api.close()
|
|
except Exception as e:
|
|
logger.error(f"Error closing API: {e}")
|
|
|
|
try:
|
|
await db.close()
|
|
except Exception as e:
|
|
logger.error(f"Error closing database: {e}")
|
|
|
|
logger.info("Bot shutdown complete")
|
|
|
|
# Test bot token before starting
|
|
try:
|
|
bot_info = await bot.get_me()
|
|
logger.info(f"Bot started: @{bot_info.username} ({bot_info.first_name})")
|
|
except Exception as e:
|
|
logger.error(f"Invalid bot token or network error: {e}")
|
|
return
|
|
|
|
# Start polling
|
|
logger.info("Bot polling started successfully")
|
|
try:
|
|
await dp.start_polling(bot)
|
|
finally:
|
|
await on_shutdown()
|
|
|
|
except KeyboardInterrupt:
|
|
logger.info("Bot stopped by user (Ctrl+C)")
|
|
except Exception as e:
|
|
logger.error(f"Critical error in main: {e}")
|
|
import traceback
|
|
traceback.print_exc()
|
|
raise
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
asyncio.run(main())
|
|
except KeyboardInterrupt:
|
|
logger.info("Bot stopped by user")
|
|
except Exception as e:
|
|
logger.error(f"Fatal error: {e}")
|
|
sys.exit(1)
|