3
from contextlib import asynccontextmanager
4
from dataclasses import dataclass
9
from fastapi import FastAPI, Request, Depends
10
from fastapi.middleware import Middleware
11
from fastapi.middleware.cors import CORSMiddleware
12
from fastapi.responses import JSONResponse
13
from fastapi.staticfiles import StaticFiles
14
from starlette.requests import HTTPConnection
15
from starlette.types import ASGIApp, Scope, Receive, Send
16
from app.front.tkq import broker
17
from app.front.front_router import front_router
19
from core.helpers.broker import list_brocker
20
from core.db_config import config
21
from core.env import Env
22
from app.basic import __domain__ as basic_domain
23
from app.inventory import __domain__ as inventory_domain
24
from app.prescription import __domain__ as prescription_domain
25
from core.exceptions import CustomException
26
from core.fastapi.dependencies import Logging
27
from core.fastapi.middlewares import (
28
AuthenticationMiddleware,
30
SQLAlchemyMiddleware, AuthBackend,
32
from core.helpers.cache import Cache, CustomKeyMaker
33
from core.helpers.cache import RedisBackend
34
from core.utils.timeit import add_timing_middleware
35
from app.front.front_config import config as cf
37
logging.basicConfig(level=logging.INFO)
38
logger = logging.getLogger(__name__)
44
hx_current_url: str = None
45
hx_request: bool = None
50
Адартер кладется в request для удобства htmx переменных
53
def __init__(self, app: ASGIApp, *args, **kwargs):
56
async def __call__(self, scope: Scope, receive: Receive, send: Send):
57
if scope['type'] in ("http", "websocket"):
58
conn = HTTPConnection(scope)
60
hx_target=conn.headers.get('hx-target'),
61
hx_current_url=conn.headers.get('hx-current-url'),
62
hx_request=True if conn.headers.get('hx-request') == 'true' else False
64
await self.app(scope, receive, send)
70
Адартер кладется в request для удобства обращений к обьектам сервисов
72
def __init__(self, app: ASGIApp, *args, **kwargs):
75
async def __call__(self, scope: Scope, receive: Receive, send: Send):
77
if scope['type'] in ("http", "websocket"):
78
conn = HTTPConnection(scope)
80
env = Env([inventory_domain, basic_domain, prescription_domain], conn, broker=list_brocker)
87
await self.app(scope, receive, send)
90
def init_routers(app_: FastAPI) -> None:
91
app_.include_router(front_router)
94
def init_listeners(app_: FastAPI) -> None:
96
@app_.exception_handler(CustomException)
97
async def custom_exception_handler(request: Request, exc: CustomException):
100
content={"error_code": exc.error_code, "message": exc.message},
104
def on_auth_error(request: Request, exc: Exception):
105
status_code, error_code, message = 401, None, str(exc)
106
if isinstance(exc, CustomException):
107
status_code = int(exc.code)
108
error_code = exc.error_code
109
message = exc.message
112
status_code=status_code,
113
content={"error_code": error_code, "message": message},
117
def make_middleware() -> List[Middleware]:
119
Middleware(EnvMidlleWare),
120
Middleware(HTMXMidlleWare),
124
allow_credentials=False,
129
AuthenticationMiddleware,
130
backend=AuthBackend(),
131
on_error=on_auth_error,
133
Middleware(SQLAlchemyMiddleware),
139
def init_cache() -> None:
140
Cache.init(backend=RedisBackend(), key_maker=CustomKeyMaker())
143
def fake_answer_to_everything_ml_model(x: float):
147
async def lifespan(app: FastAPI):
151
setattr(broker, 'env', env)
152
await broker.startup()
157
await broker.shutdown()
159
def create_app() -> FastAPI:
163
description="Hide API",
165
docs_url=None if config.ENV == "production" else "/docs",
166
redoc_url=None if config.ENV == "production" else "/redoc",
167
dependencies=[Depends(Logging)],
168
middleware=make_middleware(),
170
init_routers(app_=app_)
171
init_listeners(app_=app_)
176
path = os.path.dirname(os.path.abspath(__file__))
177
add_timing_middleware(app, record=logger.info, prefix="front", exclude="untimed")
178
app.mount(f"/static", StaticFiles(directory=f"{path}/static"), name="static")