gitscope
https://dev.kronoz.win/r/marzneshin.git
app/marzneshin.py · v0.3.1
Source
1 f7af2b3 Dawsh 2y ago import asyncio
2 f7af2b3 Dawsh 2y ago import logging
3 d377c4c Dawsh 2y ago from contextlib import asynccontextmanager
4 f7af2b3 Dawsh 2y ago from datetime import datetime as dt
5 f7af2b3 Dawsh 2y ago from datetime import timedelta as td
6 f4fecee Dawsh 2y ago from typing import AsyncGenerator
7 f4fecee Dawsh 2y ago
8 f7af2b3 Dawsh 2y ago from apscheduler.schedulers.asyncio import AsyncIOScheduler
9 f7af2b3 Dawsh 2y ago from fastapi import FastAPI, Request, status
10 f7af2b3 Dawsh 2y ago from fastapi.encoders import jsonable_encoder
11 f7af2b3 Dawsh 2y ago from fastapi.exceptions import RequestValidationError
12 f7af2b3 Dawsh 2y ago from fastapi.middleware.cors import CORSMiddleware
13 eafb4a4 Mrdn 2y ago from fastapi.responses import HTMLResponse, JSONResponse
14 d4ec019 Dawsh 2y ago from fastapi_pagination import add_pagination
15 f7af2b3 Dawsh 2y ago from starlette.staticfiles import StaticFiles
16 eafb4a4 Mrdn 2y ago from uvicorn import Config, Server
17 f7af2b3 Dawsh 2y ago
18 8111eb7 Dawsh 2y ago from app.config.env import (
19 01cdf2e Dawsh 2y ago DEBUG,
20 01cdf2e Dawsh 2y ago DOCS,
21 01cdf2e Dawsh 2y ago HOME_PAGE_TEMPLATE,
22 01cdf2e Dawsh 2y ago UVICORN_HOST,
23 01cdf2e Dawsh 2y ago UVICORN_PORT,
24 01cdf2e Dawsh 2y ago UVICORN_SSL_CERTFILE,
25 01cdf2e Dawsh 2y ago UVICORN_SSL_KEYFILE,
26 01cdf2e Dawsh 2y ago UVICORN_UDS,
27 a0e778c Mrdn 2y ago DASHBOARD_PATH,
28 8111eb7 Dawsh 2y ago WEBHOOK_ADDRESS,
29 01cdf2e Dawsh 2y ago )
30 8111eb7 Dawsh 2y ago from app.templates import render_template
31 f7af2b3 Dawsh 2y ago from . import __version__, telegram
32 2de9d72 Dawsh 2y ago from .routes import api_router
33 01cdf2e Dawsh 2y ago from .tasks import (
34 01cdf2e Dawsh 2y ago delete_expired_reminders,
35 01cdf2e Dawsh 2y ago nodes_startup,
36 01cdf2e Dawsh 2y ago record_realtime_bandwidth,
37 01cdf2e Dawsh 2y ago record_user_usages,
38 01cdf2e Dawsh 2y ago reset_user_data_usage,
39 01cdf2e Dawsh 2y ago review_users,
40 01cdf2e Dawsh 2y ago send_notifications,
41 01cdf2e Dawsh 2y ago )
42 f7af2b3 Dawsh 2y ago
43 f7af2b3 Dawsh 2y ago logger = logging.getLogger(__name__)
44 f7af2b3 Dawsh 2y ago
45 f4fecee Dawsh 2y ago
46 f4fecee Dawsh 2y ago @asynccontextmanager
47 f4fecee Dawsh 2y ago async def lifespan(app: FastAPI) -> AsyncGenerator[None, None]:
48 f4fecee Dawsh 2y ago await nodes_startup()
49 f4fecee Dawsh 2y ago yield
50 f4fecee Dawsh 2y ago scheduler.shutdown()
51 f4fecee Dawsh 2y ago logger.info("Sending pending notifications before shutdown...")
52 f4fecee Dawsh 2y ago await send_notifications()
53 f4fecee Dawsh 2y ago
54 f4fecee Dawsh 2y ago
55 f7af2b3 Dawsh 2y ago app = FastAPI(
56 f7af2b3 Dawsh 2y ago title="MarzneshinAPI",
57 f7af2b3 Dawsh 2y ago description="Unified GUI Censorship Resistant Solution Powered by Xray",
58 f7af2b3 Dawsh 2y ago version=__version__,
59 f4fecee Dawsh 2y ago lifespan=lifespan,
60 f7af2b3 Dawsh 2y ago docs_url="/docs" if DOCS else None,
61 f7af2b3 Dawsh 2y ago redoc_url="/redoc" if DOCS else None,
62 f7af2b3 Dawsh 2y ago )
63 f7af2b3 Dawsh 2y ago
64 2de9d72 Dawsh 2y ago app.include_router(api_router)
65 d4ec019 Dawsh 2y ago add_pagination(app)
66 f7af2b3 Dawsh 2y ago
67 f7af2b3 Dawsh 2y ago
68 f7af2b3 Dawsh 2y ago @app.get("/", response_class=HTMLResponse)
69 2de9d72 Dawsh 2y ago def home_page():
70 f7af2b3 Dawsh 2y ago return render_template(HOME_PAGE_TEMPLATE)
71 f7af2b3 Dawsh 2y ago
72 f7af2b3 Dawsh 2y ago
73 f7af2b3 Dawsh 2y ago app.add_middleware(
74 f7af2b3 Dawsh 2y ago CORSMiddleware,
75 f7af2b3 Dawsh 2y ago allow_origins=["*"],
76 f7af2b3 Dawsh 2y ago allow_credentials=True,
77 f7af2b3 Dawsh 2y ago allow_methods=["*"],
78 f7af2b3 Dawsh 2y ago allow_headers=["*"],
79 f7af2b3 Dawsh 2y ago )
80 f7af2b3 Dawsh 2y ago
81 f7af2b3 Dawsh 2y ago scheduler = AsyncIOScheduler(timezone="UTC")
82 eafb4a4 Mrdn 2y ago scheduler.add_job(record_user_usages, "interval", coalesce=True, seconds=30)
83 f1ab16c Dawsh 2y ago scheduler.add_job(
84 d377c4c Dawsh 2y ago review_users, "interval", seconds=30, coalesce=True, max_instances=1
85 f1ab16c Dawsh 2y ago )
86 eafb4a4 Mrdn 2y ago scheduler.add_job(reset_user_data_usage, "interval", coalesce=True, hours=1)
87 eafb4a4 Mrdn 2y ago scheduler.add_job(
88 f1ab16c Dawsh 2y ago record_realtime_bandwidth,
89 f1ab16c Dawsh 2y ago "interval",
90 f1ab16c Dawsh 2y ago seconds=1,
91 f1ab16c Dawsh 2y ago coalesce=True,
92 f1ab16c Dawsh 2y ago max_instances=1,
93 eafb4a4 Mrdn 2y ago )
94 f7af2b3 Dawsh 2y ago
95 8111eb7 Dawsh 2y ago if WEBHOOK_ADDRESS:
96 f1ab16c Dawsh 2y ago scheduler.add_job(
97 f1ab16c Dawsh 2y ago send_notifications, "interval", seconds=30, replace_existing=True
98 f1ab16c Dawsh 2y ago )
99 eafb4a4 Mrdn 2y ago scheduler.add_job(
100 eafb4a4 Mrdn 2y ago delete_expired_reminders,
101 eafb4a4 Mrdn 2y ago "interval",
102 eafb4a4 Mrdn 2y ago hours=2,
103 eafb4a4 Mrdn 2y ago start_date=dt.utcnow() + td(minutes=1),
104 eafb4a4 Mrdn 2y ago )
105 f7af2b3 Dawsh 2y ago
106 f7af2b3 Dawsh 2y ago
107 f7af2b3 Dawsh 2y ago @app.exception_handler(RequestValidationError)
108 f1ab16c Dawsh 2y ago def validation_exception_handler(
109 f1ab16c Dawsh 2y ago request: Request, exc: RequestValidationError
110 f1ab16c Dawsh 2y ago ):
111 f7af2b3 Dawsh 2y ago details = {}
112 f7af2b3 Dawsh 2y ago for error in exc.errors():
113 f7af2b3 Dawsh 2y ago details[error["loc"][-1]] = error.get("msg")
114 f7af2b3 Dawsh 2y ago return JSONResponse(
115 f7af2b3 Dawsh 2y ago status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
116 f7af2b3 Dawsh 2y ago content=jsonable_encoder({"detail": details}),
117 f7af2b3 Dawsh 2y ago )
118 f7af2b3 Dawsh 2y ago
119 f7af2b3 Dawsh 2y ago
120 f7af2b3 Dawsh 2y ago async def main():
121 eafb4a4 Mrdn 2y ago if not DEBUG:
122 f7af2b3 Dawsh 2y ago app.mount(
123 a0e778c Mrdn 2y ago DASHBOARD_PATH,
124 4466347 Mrdn 2y ago StaticFiles(directory="dashboard/dist", html=True),
125 4466347 Mrdn 2y ago name="dashboard",
126 f7af2b3 Dawsh 2y ago )
127 a0e778c Mrdn 2y ago app.mount(
128 a0e778c Mrdn 2y ago "/static/",
129 a0e778c Mrdn 2y ago StaticFiles(directory="dashboard/dist/static"),
130 a0e778c Mrdn 2y ago name="static",
131 a0e778c Mrdn 2y ago )
132 a0e778c Mrdn 2y ago app.mount(
133 a0e778c Mrdn 2y ago "/locales/",
134 a0e778c Mrdn 2y ago StaticFiles(directory="dashboard/dist/locales"),
135 a0e778c Mrdn 2y ago name="locales",
136 a0e778c Mrdn 2y ago )
137 f7af2b3 Dawsh 2y ago scheduler.start()
138 f7af2b3 Dawsh 2y ago asyncio.create_task(telegram.start_bot())
139 f7af2b3 Dawsh 2y ago cfg = Config(
140 f7af2b3 Dawsh 2y ago app=app,
141 f7af2b3 Dawsh 2y ago host=UVICORN_HOST,
142 f7af2b3 Dawsh 2y ago port=UVICORN_PORT,
143 f7af2b3 Dawsh 2y ago uds=(None if DEBUG else UVICORN_UDS),
144 f7af2b3 Dawsh 2y ago ssl_certfile=UVICORN_SSL_CERTFILE,
145 f7af2b3 Dawsh 2y ago ssl_keyfile=UVICORN_SSL_KEYFILE,
146 f7af2b3 Dawsh 2y ago workers=1,
147 f7af2b3 Dawsh 2y ago reload=DEBUG,
148 f7af2b3 Dawsh 2y ago log_level=logging.DEBUG if DEBUG else logging.INFO,
149 f7af2b3 Dawsh 2y ago )
150 f7af2b3 Dawsh 2y ago server = Server(cfg)
151 f7af2b3 Dawsh 2y ago await server.serve()