kv-tiktok/backend/main.py

82 lines
2.8 KiB
Python

from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
from fastapi.responses import FileResponse
from contextlib import asynccontextmanager
from pathlib import Path
from api.routes import auth, feed, download, following, config, user
import sys
import asyncio
# Force Proactor on Windows for Playwright
if sys.platform == "win32":
asyncio.set_event_loop_policy(asyncio.WindowsProactorEventLoopPolicy())
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Startup and shutdown events."""
print("🚀 Starting PureStream API (Network Interception Mode)...")
import asyncio
try:
loop = asyncio.get_running_loop()
print(f"DEBUG: Running event loop: {type(loop)}")
except Exception as e:
print(f"DEBUG: Could not get running loop: {e}")
yield
print("👋 Shutting down PureStream API...")
import asyncio
import sys
app = FastAPI(title="PureStream API", version="2.0.0", lifespan=lifespan)
if __name__ == "__main__":
if sys.platform == "win32":
try:
loop = asyncio.get_event_loop()
print(f"DEBUG: Current event loop: {type(loop)}")
except:
print("DEBUG: No event loop yet")
# CORS middleware
app.add_middleware(
CORSMiddleware,
allow_origins=["http://localhost:5173", "http://127.0.0.1:5173", "*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Include routers
app.include_router(auth.router, prefix="/api/auth", tags=["Authentication"])
app.include_router(feed.router, prefix="/api/feed", tags=["Feed"])
app.include_router(download.router, prefix="/api/download", tags=["Download"])
app.include_router(following.router, prefix="/api/following", tags=["Following"])
app.include_router(config.router, prefix="/api/config", tags=["Config"])
app.include_router(user.router, prefix="/api/user", tags=["User"])
@app.get("/health")
async def health_check():
return {"status": "ok"}
# Serve static frontend files in production
FRONTEND_DIR = Path(__file__).parent.parent / "frontend" / "dist"
if FRONTEND_DIR.exists():
# Mount static assets
app.mount("/assets", StaticFiles(directory=FRONTEND_DIR / "assets"), name="assets")
# Serve index.html for all non-API routes (SPA fallback)
@app.get("/{full_path:path}")
async def serve_spa(full_path: str):
# If requesting a file that exists, serve it
file_path = FRONTEND_DIR / full_path
if file_path.is_file():
return FileResponse(file_path)
# Otherwise serve index.html for SPA routing
return FileResponse(FRONTEND_DIR / "index.html")
if __name__ == "__main__":
import uvicorn
uvicorn.run("main:app", host="0.0.0.0", port=8002, reload=False, loop="asyncio")