BESS-SCADA-Data / app /main.py
pourmousavi's picture
Cache-bust CSS/JS on every container start
9f09117
Raw
History Blame Contribute Delete
2.19 kB
import logging
import time
import traceback
from contextlib import asynccontextmanager
from pathlib import Path
from fastapi import FastAPI, Request
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import HTMLResponse, JSONResponse
from fastapi.staticfiles import StaticFiles
from app.routers.api import router as api_router
from app.services.analytics import init_db
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
@asynccontextmanager
async def lifespan(app: FastAPI):
init_db()
yield
app = FastAPI(
title="NEM Battery SCADA Data Explorer",
description="Explore 4-second BESS SCADA data from Australia's National Electricity Market.",
version="1.0.0",
lifespan=lifespan,
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_methods=["GET"],
allow_headers=["*"],
)
app.include_router(api_router)
@app.exception_handler(Exception)
async def unhandled_exception_handler(request: Request, exc: Exception) -> JSONResponse:
"""
Catch-all for any exception not already handled by a specific handler or
HTTPException. Logs the full traceback so silent 500s become visible in
the application log, then returns a JSON 500 response.
"""
logger.error(
"Unhandled exception on %s %s\n%s",
request.method,
request.url,
traceback.format_exc(),
)
return JSONResponse(
status_code=500,
content={"detail": "An internal server error occurred. Please try again."},
)
STATIC_DIR = Path(__file__).parent / "static"
app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static")
# Bust the browser cache for /static/js/app.js and /static/css/style.css on
# every container start so deploys don't get served stale assets. Each new
# container produces a new __VERSION__ value; the HTML is rendered once at
# startup and served from memory.
_BUILD_VERSION = str(int(time.time()))
_INDEX_HTML = (
(STATIC_DIR / "index.html")
.read_text()
.replace("__VERSION__", _BUILD_VERSION)
)
@app.get("/", include_in_schema=False)
async def index():
return HTMLResponse(content=_INDEX_HTML)