"""rssKeeper - FastAPI 入口""" import os from contextlib import asynccontextmanager from fastapi import FastAPI from fastapi.staticfiles import StaticFiles from starlette.middleware.cors import CORSMiddleware from database import init_db, SessionLocal from scheduler import init_feed_jobs, stop_scheduler from routers import feeds, articles, dashboard, external_api import config @asynccontextmanager async def lifespan(app: FastAPI): """应用生命周期管理""" # 启动时:初始化数据库 + 注册定时任务 init_db() db = SessionLocal() try: init_feed_jobs(db) finally: db.close() yield # 关闭时:停止调度器 stop_scheduler() app = FastAPI( title="rssKeeper", description="RSS 抓取、管理与检索系统", version="1.0.0", lifespan=lifespan, ) # CORS — 仅允许同源和开发环境 app.add_middleware( CORSMiddleware, allow_origins=[ "http://localhost:7329", "http://localhost:7330", "http://127.0.0.1:7329", ], allow_credentials=False, allow_methods=["GET", "POST", "PUT", "DELETE"], allow_headers=["Content-Type", "Authorization", "X-API-Key"], ) # API 路由 app.include_router(feeds.router, prefix=config.API_PREFIX) app.include_router(articles.router, prefix=config.API_PREFIX) app.include_router(dashboard.router, prefix=config.API_PREFIX) app.include_router(external_api.router, prefix=config.EXTERNAL_API_PREFIX) @app.get("/api/health") def health_check(): """健康检查""" return {"status": "ok", "service": "rssKeeper"} # 静态文件服务(前端构建产物)— 必须放在最后,API 路由优先匹配 static_dir = os.path.join(config.BASE_DIR, "static") if os.path.exists(static_dir): app.mount("/", StaticFiles(directory=static_dir, html=True), name="static")