import asyncio import logging import socket 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.fsm.storage.memory import MemoryStorage from aiohttp import TCPConnector, ClientTimeout, ClientSession, web from config import BOT_TOKEN, TELEGRAM_API_URL from database.db import init_db from handlers import user, payment, admin # ─────────────────── LOGGING ─────────────────── logging.basicConfig( level=logging.INFO, format="%(asctime)s | %(levelname)s | %(name)s | %(message)s", datefmt="%Y-%m-%d %H:%M:%S" ) logger = logging.getLogger(__name__) class IPv4OnlyAiohttpSession(AiohttpSession): """Hugging Face Spaces-da IPv6 ulanish xatolarini chetlab o'tish uchun faqat IPv4-ni ishlatuvchi session. Cloudflare Worker orqali Telegram API'ga ulanganda timeout'ni oshiramiz, chunki Worker javoblari ba'zan sekinroq keladi. """ async def create_session(self) -> ClientSession: if self._session is None or self._session.closed: self._session = ClientSession( connector=TCPConnector(family=socket.AF_INET), timeout=ClientTimeout(total=60, connect=30, sock_connect=30, sock_read=30), json_serialize=self.json_dumps ) return self._session async def start_web_server(): """Hugging Face Spaces port tekshiruvidan o'tishi uchun dummy web server.""" async def handle(request): return web.Response(text="Bot is running!") app = web.Application() app.router.add_get('/', handle) runner = web.AppRunner(app) await runner.setup() site = web.TCPSite(runner, '0.0.0.0', 7860) await site.start() logger.info("✅ Web server 7860-portda ishga tushdi.") async def main(): logger.info("🚀 Bot ishga tushmoqda...") # Ma'lumotlar bazasini yaratish/tekshirish await init_db() logger.info("✅ Ma'lumotlar bazasi tayyor.") # Hugging Face-da IPv6 ulanish xatolarining oldini olish uchun faqat IPv4 ni majburlaymiz session = IPv4OnlyAiohttpSession() # Telegram API manzilini tanlash: # - Standart: https://api.telegram.org (HF bunda bloklaydi) # - Worker orqali: TELEGRAM_API_URL (masalan, https://tg-proxy.xxx.workers.dev) api_to_use = TELEGRAM_API_URL if TELEGRAM_API_URL != "https://api.telegram.org" else None # Bot va Dispatcher yaratish bot = Bot( token=BOT_TOKEN, session=session, api=api_to_use, default=DefaultBotProperties(parse_mode=ParseMode.HTML) ) dp = Dispatcher(storage=MemoryStorage()) # Routerlarni ulash (tartib muhim: admin birinchi) dp.include_router(admin.router) dp.include_router(payment.router) dp.include_router(user.router) logger.info("✅ Routerlar ulandi.") # Web-serverni ishga tushirish try: await start_web_server() except Exception as e: logger.error(f"❌ Web-serverni ishga tushirishda xato: {e}") # Boshlash — Worker ulanishi sekin bo'lishi mumkin, shu sababli # birinchi so'rovni 3 marta qayta urinib ko'ramiz. max_retries = 3 started = False try: for attempt in range(1, max_retries + 1): try: await bot.delete_webhook(drop_pending_updates=True) logger.info("🤖 Bot polling rejimida ishga tushdi.") started = True await dp.start_polling(bot, allowed_updates=dp.resolve_used_update_types()) break except Exception as e: logger.error(f"❌ Bot xatosi (urinish {attempt}/{max_retries}): {e}") if attempt < max_retries: logger.info("⏳ 5 soniyadan so'ng qayta uriniladi...") await asyncio.sleep(5) else: logger.error("❌ Bot ishga tushmadi — barcha urinishlar tugadi.", exc_info=True) if not started: logger.error("🔴 Bot Telegram'ga ulana olmadi.") finally: await bot.session.close() logger.info("🔴 Bot to'xtatildi.") if __name__ == "__main__": asyncio.run(main())