Initial scaffold: React+TS+Vite frontend, FastAPI backend, config system
This commit is contained in:
44
backend/main.py
Normal file
44
backend/main.py
Normal file
@@ -0,0 +1,44 @@
|
||||
import logging
|
||||
from contextlib import asynccontextmanager
|
||||
from pathlib import Path
|
||||
|
||||
from fastapi import FastAPI
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.responses import FileResponse
|
||||
|
||||
from config import load_config
|
||||
from mqtt_bridge import start_mqtt
|
||||
from routes.config_routes import router as config_router
|
||||
from routes.ws_routes import router as ws_router
|
||||
|
||||
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s: %(message)s")
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
FRONTEND_DIR = Path(__file__).parent.parent / "frontend" / "dist"
|
||||
|
||||
|
||||
@asynccontextmanager
|
||||
async def lifespan(app: FastAPI):
|
||||
config = load_config()
|
||||
logger.info(f"Loaded config: {config.title} with {len(config.cameras)} cameras")
|
||||
start_mqtt()
|
||||
yield
|
||||
|
||||
|
||||
app = FastAPI(title="Camera Viewer", lifespan=lifespan)
|
||||
|
||||
app.include_router(config_router)
|
||||
app.include_router(ws_router)
|
||||
|
||||
# Serve frontend static files
|
||||
if FRONTEND_DIR.exists():
|
||||
app.mount("/assets", StaticFiles(directory=FRONTEND_DIR / "assets"), name="assets")
|
||||
|
||||
@app.get("/{full_path:path}")
|
||||
async def serve_frontend(full_path: str):
|
||||
# Try to serve the exact file first
|
||||
file_path = FRONTEND_DIR / full_path
|
||||
if full_path and file_path.exists() and file_path.is_file():
|
||||
return FileResponse(file_path)
|
||||
# Fall back to index.html for SPA routing
|
||||
return FileResponse(FRONTEND_DIR / "index.html")
|
||||
Reference in New Issue
Block a user