Files

66 lines
2.1 KiB
Python
Raw Permalink Normal View History

2026-03-29 06:57:34 -04:00
import logging
from contextlib import asynccontextmanager
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from app.config import settings
from app.routers import analytics, auth, distractions, proactive, sessions, steps, tasks
from app.services.db import close_pool, get_pool
logger = logging.getLogger(__name__)
@asynccontextmanager
async def lifespan(app: FastAPI):
await get_pool()
print(f"APNs config → KEY_ID={settings.APNS_KEY_ID or '(empty)'!r} "
f"TEAM_ID={settings.APNS_TEAM_ID or '(empty)'!r} "
f"P8_PATH={settings.APNS_P8_PATH or '(empty)'!r} "
f"SANDBOX={settings.APNS_SANDBOX} "
f"BUNDLE={settings.APPLE_BUNDLE_ID}")
yield
await close_pool()
app = FastAPI(
title="LockInBro API",
version="1.0.0",
root_path="/api/v1",
lifespan=lifespan,
)
@app.exception_handler(Exception)
async def llm_error_handler(request: Request, exc: Exception):
# Surface LLM provider errors as 502 instead of 500
exc_name = type(exc).__name__
if "ClientError" in exc_name or "APIError" in exc_name or "APIConnectionError" in exc_name:
return JSONResponse(status_code=502, content={"detail": f"LLM provider error: {exc}"})
if isinstance(exc, RuntimeError) and "No LLM API key" in str(exc):
return JSONResponse(status_code=503, content={"detail": str(exc)})
raise exc
@app.middleware("http")
async def log_client_info(request: Request, call_next):
real_ip = request.headers.get("cf-connecting-ip", request.headers.get("x-forwarded-for", "unknown"))
ua = request.headers.get("user-agent", "unknown")
response = await call_next(request)
if request.url.path != "/api/v1/health":
print(f"[REQ] {request.method} {request.url.path}{response.status_code} | ip={real_ip} ua={ua[:80]}")
return response
app.include_router(auth.router)
app.include_router(tasks.router)
app.include_router(steps.router)
app.include_router(sessions.router)
app.include_router(distractions.router)
app.include_router(proactive.router)
app.include_router(analytics.router)
@app.get("/health")
async def health():
return {"status": "ok"}