File size: 4,319 Bytes
d923177
 
 
c55be2e
d923177
 
c55be2e
d923177
 
df1c82c
 
d923177
 
 
 
 
 
 
 
 
 
 
 
52cf66a
df1c82c
 
 
 
 
52cf66a
 
 
 
df1c82c
52cf66a
 
 
 
 
d923177
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
c55be2e
52cf66a
c55be2e
df1c82c
 
 
 
 
d923177
 
 
c55be2e
df1c82c
d923177
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
df1c82c
 
 
 
ff8ed63
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d923177
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
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())