Files
vpn-control-panel/app/main.py

105 lines
2.7 KiB
Python

import asyncio
from contextlib import asynccontextmanager
from fastapi import FastAPI, Request
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
from loguru import logger
from app.config import setup_logging
from app.database import engine
from app.settings import settings
@asynccontextmanager
async def lifespan(app: FastAPI):
setup_logging()
logger.info("Starting {} v{}", settings.app_name, "0.1.0")
async with engine.connect() as conn:
await conn.exec_driver_sql("SELECT 1")
logger.info("Database connection established")
from app.bot.dispatcher import create_bot, create_dispatcher
from app.scheduler import setup_scheduler
bot = create_bot()
dp = create_dispatcher()
polling_task = asyncio.create_task(dp.start_polling(bot))
logger.info("Telegram bot started")
scheduler = setup_scheduler()
scheduler.start()
logger.info("Scheduler started")
yield
scheduler.shutdown(wait=True)
logger.info("Scheduler stopped")
polling_task.cancel()
try:
await polling_task
except asyncio.CancelledError:
pass
await bot.session.close()
logger.info("Telegram bot stopped")
await engine.dispose()
logger.info("Database engine disposed")
app = FastAPI(
title=settings.app_name,
version="0.1.0",
debug=settings.debug,
lifespan=lifespan,
docs_url="/docs",
redoc_url="/redoc",
)
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(
request: Request, exc: RequestValidationError
):
logger.warning("Validation error: {}", exc.errors())
body = exc.body
if body is not None and not isinstance(body, (dict, list, str, int, float, bool, type(None))):
body = str(body)
return JSONResponse(
status_code=422,
content={
"detail": exc.errors(),
"body": body,
},
)
@app.exception_handler(Exception)
async def global_exception_handler(request: Request, exc: Exception):
logger.error("Unhandled error: {}", exc)
return JSONResponse(
status_code=500,
content={"detail": "Internal server error"},
)
from app.admin.router import router as admin_router
from app.api.v1.router import router as v1_router
app.include_router(admin_router)
app.include_router(v1_router)
@app.get("/health")
async def health():
try:
async with engine.connect() as conn:
await conn.exec_driver_sql("SELECT 1")
return {"status": "ok", "database": "connected"}
except Exception as e:
logger.error("Health check failed: {}", e)
return JSONResponse(
status_code=503,
content={"status": "error", "database": str(e)},
)