-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathmain.py
112 lines (93 loc) · 3.19 KB
/
main.py
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
import logging
import asyncio
import uvicorn
from pathlib import Path
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.exceptions import RequestValidationError
from fastapi.routing import APIRoute
from app.handler.utils.log import logger
from fastapi.exception_handlers import (
http_exception_handler,
request_validation_exception_handler,
)
from contextlib import asynccontextmanager
from app.handler.jobs import stop_scheduler, start_scheduler
from app.handler.routers import sub
from fastapi_responses import custom_openapi
from starlette.exceptions import HTTPException as StarletteHTTPException
from app.handler.utils.config import (
UVICORN_HOST,
UVICORN_PORT,
UVICORN_UDS,
UVICORN_SSL_CERTFILE,
UVICORN_SSL_KEYFILE,
DOCS,
)
__version__ = "0.1.0"
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Manage application startup and shutdown events."""
await start_scheduler()
logger.info("Application started successfully.")
yield # App will be running during this period
await stop_scheduler()
logger.info("Application shut down successfully.")
def create_app() -> FastAPI:
"""Create and configure FastAPI application instance."""
app = FastAPI(
title="Migration",
description="API to proxy sub requests between users and backend system",
version=__version__,
docs_url="/docs" if DOCS else None,
redoc_url="/redoc" if DOCS else None,
lifespan=lifespan, # Set the lifespan context manager
)
app.openapi = custom_openapi(app)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
@app.exception_handler(StarletteHTTPException)
async def custom_http_exception_handler(request, exc):
logger.error(f"An HTTP error!: {repr(exc)}")
return await http_exception_handler(request, exc)
@app.exception_handler(RequestValidationError)
async def validation_exception_handler(request, exc):
logger.error(f"The client sent invalid data!: {exc}")
return await request_validation_exception_handler(request, exc)
for route in app.routes:
if isinstance(route, APIRoute):
route.operation_id = route.name
# Include the router
app.include_router(sub.router)
return app
async def main():
"""Main function to run the application."""
app = create_app()
config = uvicorn.Config(
app,
host=UVICORN_HOST,
port=UVICORN_PORT,
uds=UVICORN_UDS,
ssl_certfile=UVICORN_SSL_CERTFILE,
ssl_keyfile=UVICORN_SSL_KEYFILE,
workers=1,
log_level=logging.INFO,
)
server = uvicorn.Server(config)
await server.serve()
if __name__ == "__main__":
file_path = Path("exceptions.json")
if not file_path.exists():
logger.error(f"Marzban exceptions data file not found at: {file_path}")
else:
try:
asyncio.run(main())
except FileNotFoundError as e:
logger.error(f"FileNotFoundError: {e}")
except Exception as e:
logger.error(f"An error occurred: {e}")