Files
SmartUp/backend/app/main.py
T
2026-05-12 17:51:53 +08:00

94 lines
2.6 KiB
Python

"""SmartUp FastAPI application entry point."""
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 fastapi.responses import FileResponse
from app.config import get_settings
from app.database import init_db
from app.models.admin_user import AdminUser
from app.database import SessionLocal
from app.utils.auth import hash_password
from app.services.scheduler import start_scheduler, stop_scheduler
from app.routers import auth, upstreams, webhooks, logs, custom_pages
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(name)s %(message)s")
logger = logging.getLogger(__name__)
def _init_admin() -> None:
settings = get_settings()
if not settings.admin_password:
logger.warning("ADMIN_PASSWORD not set, skip admin init")
return
db = SessionLocal()
try:
exists = db.query(AdminUser).filter(AdminUser.email == settings.admin_email).first()
if not exists:
user = AdminUser(
email=settings.admin_email,
password_hash=hash_password(settings.admin_password),
)
db.add(user)
db.commit()
logger.info("admin user created: %s", settings.admin_email)
else:
logger.info("admin user already exists: %s", settings.admin_email)
finally:
db.close()
@asynccontextmanager
async def lifespan(app: FastAPI):
init_db()
_init_admin()
start_scheduler()
yield
stop_scheduler()
app = FastAPI(
title="SmartUp",
description="API 上游管理与 Webhook 通知系统",
version="1.0.0",
lifespan=lifespan,
docs_url="/api/docs",
redoc_url="/api/redoc",
openapi_url="/api/openapi.json",
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# API routers
app.include_router(auth.router)
app.include_router(upstreams.router)
app.include_router(webhooks.router)
app.include_router(logs.router)
app.include_router(custom_pages.router)
@app.get("/healthz")
def health():
return {"status": "ok"}
# Serve frontend static files
STATIC_DIR = Path(__file__).parent.parent / "static"
if STATIC_DIR.exists():
app.mount("/assets", StaticFiles(directory=str(STATIC_DIR / "assets")), name="assets")
@app.get("/{full_path:path}")
def serve_spa(full_path: str):
index = STATIC_DIR / "index.html"
return FileResponse(str(index))