45 lines
1.4 KiB
Python
45 lines
1.4 KiB
Python
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")
|