171 lines
5.2 KiB
Python
171 lines
5.2 KiB
Python
"""
|
||
Unified entry point for bot and web interface
|
||
"""
|
||
import asyncio
|
||
import logging
|
||
from pyrogram import Client
|
||
from shared.config import settings
|
||
from shared.database.session import init_db
|
||
from bot.modules.message_handler.commands import register_commands
|
||
from bot.modules.message_handler.callbacks import register_callbacks
|
||
from bot.modules.access_control.middleware import setup_middleware
|
||
from bot.modules.task_scheduler.executor import task_executor, set_app_client
|
||
from bot.modules.task_scheduler.queue import task_queue
|
||
from bot.utils.logger import setup_logger
|
||
from web.app import app as web_app
|
||
import uvicorn
|
||
|
||
# Setup logging
|
||
setup_logger()
|
||
logger = logging.getLogger(__name__)
|
||
|
||
|
||
async def run_web_server():
|
||
"""Run web server in the same event loop"""
|
||
config = uvicorn.Config(
|
||
app=web_app,
|
||
host=settings.WEB_HOST,
|
||
port=settings.WEB_PORT,
|
||
log_level="info",
|
||
loop="asyncio"
|
||
)
|
||
server = uvicorn.Server(config)
|
||
logger.info(f"Starting web server on {settings.WEB_HOST}:{settings.WEB_PORT}")
|
||
await server.serve()
|
||
|
||
|
||
async def run_bot():
|
||
"""Run Telegram bot"""
|
||
logger.info("Starting Telegram bot...")
|
||
|
||
# Check cookies file if configured
|
||
from shared.config import settings
|
||
if settings.COOKIES_FILE:
|
||
from pathlib import Path
|
||
import os
|
||
cookies_paths = [
|
||
Path(settings.COOKIES_FILE),
|
||
Path(__file__).parent / settings.COOKIES_FILE,
|
||
Path(os.getcwd()) / settings.COOKIES_FILE,
|
||
]
|
||
cookies_found = False
|
||
for path in cookies_paths:
|
||
if path.exists() and path.is_file():
|
||
logger.info(f"✅ Cookies file found: {path} (configured as: {settings.COOKIES_FILE})")
|
||
cookies_found = True
|
||
break
|
||
if not cookies_found:
|
||
logger.warning(
|
||
f"⚠️ Cookies file not found: {settings.COOKIES_FILE}. "
|
||
f"Searched in: {[str(p) for p in cookies_paths]}. "
|
||
f"Instagram downloads may fail without cookies."
|
||
)
|
||
else:
|
||
logger.info("ℹ️ No cookies file configured (COOKIES_FILE not set)")
|
||
|
||
# Initialize database
|
||
await init_db()
|
||
logger.info("Database initialized")
|
||
|
||
# Initialize task queue
|
||
await task_queue.initialize()
|
||
logger.info("Task queue initialized")
|
||
|
||
# Create Pyrogram client
|
||
app = Client(
|
||
"tgloader_bot",
|
||
api_id=settings.TELEGRAM_API_ID,
|
||
api_hash=settings.TELEGRAM_API_HASH,
|
||
bot_token=settings.BOT_TOKEN,
|
||
)
|
||
|
||
# Setup middleware for access control
|
||
setup_middleware(app)
|
||
|
||
# Set client for task executor
|
||
set_app_client(app)
|
||
|
||
# Register handlers
|
||
register_commands(app)
|
||
register_callbacks(app)
|
||
|
||
logger.info("Bot ready")
|
||
|
||
# Start bot
|
||
await app.start()
|
||
logger.info(f"Bot started. Owner ID: {settings.OWNER_ID}")
|
||
|
||
# Start task executor AFTER bot is started
|
||
await task_executor.start()
|
||
logger.info("Task executor started")
|
||
|
||
# Start background task for cleaning old files
|
||
from bot.utils.file_cleanup import cleanup_files_periodically
|
||
cleanup_task = asyncio.create_task(cleanup_files_periodically())
|
||
logger.info("File cleanup task started")
|
||
|
||
# Start background task for updating user information
|
||
from bot.utils.user_info_updater import update_users_without_info_periodically
|
||
user_info_task = asyncio.create_task(update_users_without_info_periodically())
|
||
logger.info("User info update task started")
|
||
|
||
return app
|
||
|
||
|
||
async def main():
|
||
"""Main startup function"""
|
||
logger.info("=" * 50)
|
||
logger.info("Starting TGLoader (Bot + Web Interface)")
|
||
logger.info("=" * 50)
|
||
|
||
# Start bot
|
||
bot_app = await run_bot()
|
||
|
||
# Start web server in the same event loop
|
||
web_task = asyncio.create_task(run_web_server())
|
||
logger.info("Web server started in the same event loop")
|
||
|
||
# Wait for completion (running in parallel)
|
||
try:
|
||
# Wait for web server to complete (runs indefinitely)
|
||
await web_task
|
||
except KeyboardInterrupt:
|
||
logger.info("Received stop signal (Ctrl+C)")
|
||
except asyncio.CancelledError:
|
||
logger.info("Received cancellation signal")
|
||
finally:
|
||
logger.info("Starting graceful shutdown...")
|
||
|
||
# Stop web server
|
||
web_task.cancel()
|
||
try:
|
||
await web_task
|
||
except asyncio.CancelledError:
|
||
pass
|
||
|
||
# Stop task executor
|
||
try:
|
||
await task_executor.stop()
|
||
logger.info("Task executor stopped")
|
||
except Exception as e:
|
||
logger.error(f"Error stopping executor: {e}")
|
||
|
||
# Stop bot
|
||
try:
|
||
await bot_app.stop()
|
||
logger.info("Bot stopped")
|
||
except Exception as e:
|
||
logger.error(f"Error stopping bot: {e}")
|
||
|
||
logger.info("Application terminated")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
try:
|
||
asyncio.run(main())
|
||
except KeyboardInterrupt:
|
||
logger.info("Получен сигнал остановки (KeyboardInterrupt)")
|
||
except Exception as e:
|
||
logger.error(f"Критическая ошибка: {e}", exc_info=True)
|
||
|