99 lines
3.7 KiB
Python
99 lines
3.7 KiB
Python
|
|
import os
|
|
import httpx
|
|
from typing import Callable
|
|
from fastapi import APIRouter
|
|
from starlette.responses import StreamingResponse
|
|
from fastapi.responses import FileResponse
|
|
from utils import DEBUG, ON_DOCKER, ROUTERS_DIR, list_files, run_func
|
|
from utils.models import ResetRequest
|
|
import asyncio
|
|
import traceback
|
|
|
|
REACT_BUILD_DIR: str = "../frontend/build/" if not ON_DOCKER else "frontend/"
|
|
REACT_HTML_PATH: str = os.path.join(REACT_BUILD_DIR,"index.html")
|
|
|
|
async def frontend_debug_proxy(path):
|
|
httpc = httpx.AsyncClient()
|
|
req = httpc.build_request("GET",f"http://127.0.0.1:{os.getenv('F_PORT','5173')}/"+path)
|
|
resp = await httpc.send(req, stream=True)
|
|
return StreamingResponse(resp.aiter_bytes(),status_code=resp.status_code, headers=resp.headers)
|
|
|
|
async def react_deploy(path):
|
|
file_request = os.path.join(REACT_BUILD_DIR, path)
|
|
if not os.path.isfile(file_request):
|
|
return FileResponse(REACT_HTML_PATH, media_type='text/html')
|
|
else:
|
|
return FileResponse(file_request)
|
|
|
|
def frontend_deploy(app):
|
|
@app.get("/{full_path:path}", include_in_schema=False)
|
|
async def catch_all(full_path:str):
|
|
if DEBUG:
|
|
try:
|
|
return await frontend_debug_proxy(full_path)
|
|
except Exception:
|
|
return {"details":"Frontend not started at "+f"http://127.0.0.1:{os.getenv('F_PORT','5173')}"}
|
|
else:
|
|
return await react_deploy(full_path)
|
|
|
|
def list_routers():
|
|
return [ele[:-3] for ele in list_files(ROUTERS_DIR) if ele != "__init__.py" and " " not in ele and ele.endswith(".py")]
|
|
|
|
class RouterModule():
|
|
router: APIRouter|None = None
|
|
reset: Callable|None = None
|
|
startup: Callable|None = None
|
|
shutdown: Callable|None = None
|
|
name: str
|
|
|
|
def __init__(self, router: APIRouter, reset: Callable, startup: Callable, shutdown: Callable, name:str):
|
|
self.router = router
|
|
self.reset = reset
|
|
self.startup = startup
|
|
self.shutdown = shutdown
|
|
self.name = name
|
|
|
|
def __repr__(self):
|
|
return f"RouterModule(router={self.router}, reset={self.reset}, startup={self.startup}, shutdown={self.shutdown})"
|
|
|
|
def get_router_modules():
|
|
res: list[RouterModule] = []
|
|
for route in list_routers():
|
|
try:
|
|
module = getattr(__import__(f"routers.{route}"), route, None)
|
|
if module:
|
|
res.append(RouterModule(
|
|
router=getattr(module, "app", None),
|
|
reset=getattr(module, "reset", None),
|
|
startup=getattr(module, "startup", None),
|
|
shutdown=getattr(module, "shutdown", None),
|
|
name=route
|
|
))
|
|
except Exception as e:
|
|
traceback.print_exc()
|
|
print(f"Router {route} failed to load: {e}")
|
|
return res
|
|
|
|
def load_routers(app):
|
|
resets, startups, shutdowns = [], [], []
|
|
for router in get_router_modules():
|
|
if router.router:
|
|
app.include_router(router.router, prefix=f"/{router.name}", tags=[router.name])
|
|
else:
|
|
print(f"Router {router.name} is not loaded")
|
|
continue
|
|
if router.reset:
|
|
resets.append(router.reset)
|
|
if router.startup:
|
|
startups.append(router.startup)
|
|
if router.shutdown:
|
|
shutdowns.append(router.shutdown)
|
|
async def reset(reset_option:ResetRequest):
|
|
await asyncio.gather(*[run_func(func, reset_option) for func in resets])
|
|
async def startup():
|
|
await asyncio.gather(*[run_func(func) for func in startups])
|
|
async def shutdown():
|
|
await asyncio.gather(*[run_func(func) for func in shutdowns])
|
|
return reset, startup, shutdown
|