Spaces:
Runtime error
Runtime error
File size: 6,280 Bytes
9a1712b 780f9b7 9a1712b 780f9b7 fae6cf3 9a1712b 780f9b7 fae6cf3 780f9b7 fae6cf3 780f9b7 fae6cf3 780f9b7 78d7683 780f9b7 78d7683 780f9b7 9a1712b 780f9b7 fae6cf3 780f9b7 c31b50d 780f9b7 fae6cf3 9a1712b 780f9b7 fae6cf3 780f9b7 fae6cf3 780f9b7 fae6cf3 780f9b7 78d7683 fae6cf3 780f9b7 78d7683 780f9b7 78d7683 780f9b7 fae6cf3 780f9b7 fae6cf3 780f9b7 78d7683 fae6cf3 780f9b7 fae6cf3 78d7683 fae6cf3 780f9b7 9a1712b 780f9b7 | 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 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 | import asyncio
import logging
import sys
from datetime import datetime
from aiohttp import web
from aiogram import Bot, Dispatcher
from aiogram.client.default import DefaultBotProperties
from aiogram.enums import ParseMode
from aiogram.fsm.storage.memory import MemoryStorage
from aiogram.webhook.aiohttp_server import (
SimpleRequestHandler,
setup_application,
)
from config import config
from database.db import init_db
from handlers import admin, owner, user
# โโโโโโโโโโโโโโโโโโโโโโโโโโโ LOGGING โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
logging.basicConfig(
level=logging.INFO,
format="%(asctime)s | %(levelname)-8s | %(name)s: %(message)s",
datefmt="%Y-%m-%d %H:%M:%S",
stream=sys.stdout,
)
logger = logging.getLogger(__name__)
BOT_STATUS = {"running": False, "started_at": None, "error": None}
# Webhook path โ Telegram will POST updates here
WEBHOOK_PATH = "/webhook"
# โโโโโโโโโโโโโโโโโโโโโโโโโโโ HEALTH ENDPOINTS โโโโโโโโโโโโโโโโโโโโโโโโโโโโ
async def handle_root(request: web.Request) -> web.Response:
status = "โ
running" if BOT_STATUS["running"] else "โณ starting"
error = f"\nโ Last error: {BOT_STATUS['error']}" if BOT_STATUS["error"] else ""
# ู
ูุงุญุธุฉ ููู
ุณุชุฎุฏู
ูู ุงูุตูุญุฉ ุงูุฑุฆูุณูุฉ
manual_notice = "\n\n๐ก Note: Webhook is set manually to bypass HF outbound block."
body = (
f"๐ค Knowledge Base Bot โ {status}\n"
f"๐ Server time : {datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')} UTC\n"
f"๐ Bot started : {BOT_STATUS['started_at'] or 'not yet'}"
f"{error}{manual_notice}"
)
return web.Response(text=body, content_type="text/plain", status=200)
async def handle_health(request: web.Request) -> web.Response:
import json
payload = {
"status" : "ok" if BOT_STATUS["running"] else "starting",
"bot_ok" : BOT_STATUS["running"],
"started": BOT_STATUS["started_at"],
"error" : BOT_STATUS["error"],
}
return web.Response(
text=json.dumps(payload),
content_type="application/json",
status=200,
)
# โโโโโโโโโโโโโโโโโโโโโโโโโโโ DISPATCHER โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
def build_dispatcher() -> Dispatcher:
dp = Dispatcher(storage=MemoryStorage())
dp.include_router(owner.router)
dp.include_router(admin.router)
dp.include_router(user.router)
return dp
# โโโโโโโโโโโโโโโโโโโโโโโโโโโ MAIN โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
async def main() -> None:
print(f"\n{'='*50}")
print(f" Startup at {datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')} UTC")
print(f"{'='*50}\n")
# โโ 1. Validate config โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
try:
config.validate()
except EnvironmentError as e:
logger.critical(str(e))
BOT_STATUS["error"] = str(e)
app = web.Application()
app.router.add_get("/", handle_root)
runner = web.AppRunner(app)
await runner.setup()
await web.TCPSite(runner, config.WEB_HOST, config.WEB_PORT).start()
while True:
await asyncio.sleep(3600)
# โโ 2. Database with retry โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
for attempt in range(1, 6):
try:
logger.info(f"๐ DB connect attempt {attempt}/5โฆ")
await init_db()
logger.info("โ
Database ready.")
break
except Exception as exc:
BOT_STATUS["error"] = str(exc)
logger.error(f"โ DB failed: {exc}")
if attempt < 5:
await asyncio.sleep(5)
else:
logger.critical("๐ฅ DB unavailable.")
break
# โโ 3. Bot Setup โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
bot = Bot(
token=config.BOT_TOKEN,
default=DefaultBotProperties(parse_mode=ParseMode.HTML),
)
dp = build_dispatcher()
# โ ๏ธ ุชู
ุชุนุทูู ุงูุญุฐู ูุงูุชุณุฌูู ุงูุชููุงุฆู ููููุจ ููู ููุง ูุชุฌูุจ ุญุฌุจ HF
# ุงูุชุณุฌูู ูุชู
ูุฏููุงู ู
ู ุงูู
ุชุตูุญ ูู
ุง ูุนูุช ุณุงุจูุงู
logger.info("โน๏ธ Skipping automatic webhook registration (HF compatibility mode).")
BOT_STATUS["running"] = True
BOT_STATUS["started_at"] = datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S UTC")
BOT_STATUS["error"] = None
# โโ 4. aiohttp app with webhook handler โโโโโโโโโโโโโโโโโโโ
app = web.Application()
# Health endpoints
app.router.add_get("/", handle_root)
app.router.add_get("/health", handle_health)
# ุชุณุฌูู ู
ุนุงูุฌ ุงูููุจ ููู (ูุฐุง ูุฌุนู ุงูุจูุช "ูุณู
ุน" ููุฑุณุงุฆู ุงููุงุฏู
ุฉ)
SimpleRequestHandler(dispatcher=dp, bot=bot).register(app, path=WEBHOOK_PATH)
setup_application(app, dp, bot=bot)
# โโ 5. Start server โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
runner = web.AppRunner(app)
await runner.setup()
site = web.TCPSite(runner, host=config.WEB_HOST, port=config.WEB_PORT)
await site.start()
logger.info(f"๐ Server is UP on http://{config.WEB_HOST}:{config.WEB_PORT}/")
logger.info(f"๐ก Waiting for Telegram updates via: {config.WEBHOOK_URL}{WEBHOOK_PATH}")
# Keep running forever
while True:
await asyncio.sleep(3600)
if __name__ == "__main__":
try:
asyncio.run(main())
except KeyboardInterrupt:
logger.info("๐ Shutdown by user.") |