daily-briefing/server/main.py

110 lines
3.3 KiB
Python
Raw Normal View History

"""Daily Briefing Dashboard — FastAPI Application."""
from __future__ import annotations
import logging
from contextlib import asynccontextmanager
from pathlib import Path
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from server.config import settings
from server.services import news_service
from server.services.mqtt_service import mqtt_service
logger = logging.getLogger("daily-briefing")
logging.basicConfig(
level=logging.DEBUG if settings.debug else logging.INFO,
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
)
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Startup / shutdown lifecycle."""
logger.info("Starting Daily Briefing Dashboard...")
logger.info(
"Unraid servers configured: %d",
len(settings.unraid_servers),
)
# Initialize database pool
try:
await news_service.init_pool(
host=settings.db_host,
port=settings.db_port,
dbname=settings.db_name,
user=settings.db_user,
password=settings.db_password,
)
logger.info("Database pool initialized")
except Exception:
logger.exception("Failed to initialize database pool — news will be unavailable")
# Start MQTT service
if settings.mqtt_host:
try:
await mqtt_service.start(
host=settings.mqtt_host,
port=settings.mqtt_port,
username=settings.mqtt_username or None,
password=settings.mqtt_password or None,
topics=settings.mqtt_topics,
client_id=settings.mqtt_client_id,
)
logger.info("MQTT service started (broker %s:%d)", settings.mqtt_host, settings.mqtt_port)
except Exception:
logger.exception("Failed to start MQTT service — MQTT will be unavailable")
else:
logger.info("MQTT disabled — set MQTT_HOST to enable")
yield
# Shutdown
logger.info("Shutting down...")
await mqtt_service.stop()
await news_service.close_pool()
app = FastAPI(
title="Daily Briefing",
version="2.0.0",
lifespan=lifespan,
)
# CORS — allow frontend dev server
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# --- Register Routers ---
from server.routers import dashboard, homeassistant, mqtt, news, servers, tasks, weather # noqa: E402
app.include_router(weather.router)
app.include_router(news.router)
app.include_router(servers.router)
app.include_router(homeassistant.router)
app.include_router(tasks.router)
app.include_router(mqtt.router)
app.include_router(dashboard.router)
# --- Serve static frontend (production) ---
static_dir = Path(__file__).parent.parent / "static"
if static_dir.is_dir():
app.mount("/", StaticFiles(directory=str(static_dir), html=True), name="static")
logger.info("Serving static frontend from %s", static_dir)
else:
@app.get("/")
async def root():
return {
"status": "ok",
"message": "Daily Briefing API — Frontend not built yet",
"endpoints": ["/api/all", "/api/weather", "/api/news", "/api/servers", "/api/ha", "/api/tasks"],
}