Starting phase 2

This commit is contained in:
James Ketr 2025-09-04 16:12:07 -07:00
parent 65c1954db5
commit b5d2605d99

View File

@ -58,23 +58,27 @@ if not public_url.endswith("/"):
ADMIN_TOKEN = os.getenv("ADMIN_TOKEN", None)
# Create FastAPI app first
app = FastAPI(
title="AI Voice Bot Server (Refactored)",
description="WebRTC voice chat server with modular architecture",
version="2.0.0",
)
logger.info(f"Starting server with public URL: {public_url}")
# Global managers - these replace the global variables from original main.py
session_manager: SessionManager = None
lobby_manager: LobbyManager = None
auth_manager: AuthManager = None
websocket_manager: WebSocketConnectionManager = None
# API routers
admin_api: AdminAPI = None
session_api: SessionAPI = None
lobby_api: LobbyAPI = None
@asynccontextmanager
async def lifespan(app: FastAPI):
"""Lifespan context manager for startup and shutdown events"""
global session_manager, lobby_manager, auth_manager, websocket_manager
global admin_api, session_api, lobby_api
# Startup
logger.info("Starting AI Voice Bot server with modular architecture...")
@ -88,14 +92,11 @@ async def lifespan(app: FastAPI):
session_manager.load()
# Restore lobbies for existing sessions
# Note: This is a simplified version - full lobby restoration would be more complex
for session in session_manager.get_all_sessions():
for lobby_info in session.lobbies:
# Create lobby if it doesn't exist
lobby = lobby_manager.create_or_get_lobby(
name=lobby_info.name, private=lobby_info.private
)
# Add session to lobby (but don't trigger events during startup)
with lobby.lock:
lobby.sessions[session.id] = session
@ -109,7 +110,7 @@ async def lifespan(app: FastAPI):
auth_manager=auth_manager,
)
# Initialize API routers
# Create and register API routes
admin_api = AdminAPI(
session_manager=session_manager,
lobby_manager=lobby_manager,
@ -126,90 +127,21 @@ async def lifespan(app: FastAPI):
public_url=public_url,
)
# Register API routes
# Register API routes during startup
app.include_router(admin_api.router)
app.include_router(session_api.router)
app.include_router(lobby_api.router)
# Start background tasks
await session_manager.start_background_tasks()
logger.info("AI Voice Bot server started successfully!")
logger.info(f"Server URL: {public_url}")
logger.info(f"Sessions loaded: {session_manager.get_session_count()}")
logger.info(f"Lobbies available: {lobby_manager.get_lobby_count()}")
logger.info(f"Protected names: {auth_manager.get_protection_count()}")
if ADMIN_TOKEN:
logger.info("Admin endpoints protected with token")
else:
logger.warning("Admin endpoints are unprotected")
yield
# Shutdown
logger.info("Shutting down AI Voice Bot server...")
# Stop background tasks
if session_manager:
await session_manager.stop_background_tasks()
logger.info("Server shutdown complete")
# Create FastAPI app
app = FastAPI(
title="AI Voice Bot Server (Refactored)",
description="WebRTC voice chat server with modular architecture",
version="2.0.0",
lifespan=lifespan,
)
logger.info(f"Starting server with public URL: {public_url}")
@app.websocket(f"{public_url}" + "ws/lobby/{lobby_id}/{session_id}")
async def lobby_websocket(
websocket: WebSocket,
lobby_id: str | None = Path(...),
session_id: str | None = Path(...),
):
"""WebSocket endpoint for lobby connections - now uses WebSocketConnectionManager"""
await websocket_manager.handle_connection(websocket, lobby_id, session_id)
# Health check for the new architecture
@app.get(f"{public_url}api/system/health")
def system_health():
"""System health check showing manager status"""
return {
"status": "ok",
"architecture": "modular",
"version": "2.0.0",
"managers": {
"session_manager": "active" if session_manager else "inactive",
"lobby_manager": "active" if lobby_manager else "inactive",
"auth_manager": "active" if auth_manager else "inactive",
"websocket_manager": "active" if websocket_manager else "inactive",
},
"statistics": {
"sessions": session_manager.get_session_count() if session_manager else 0,
"lobbies": lobby_manager.get_lobby_count() if lobby_manager else 0,
"protected_names": auth_manager.get_protection_count()
if auth_manager
else 0,
},
}
# Serve static files or proxy to frontend development server
# Register static file serving AFTER API routes to avoid conflicts
PRODUCTION = os.getenv("PRODUCTION", "false").lower() == "true"
client_build_path = os.path.join(os.path.dirname(__file__), "/client/build")
if PRODUCTION:
logger.info(f"Serving static files from: {client_build_path} at {public_url}")
app.mount(
public_url, StaticFiles(directory=client_build_path, html=True), name="static"
public_url,
StaticFiles(directory=client_build_path, html=True),
name="static",
)
else:
logger.info(f"Proxying static files to http://client:3000 at {public_url}")
@ -233,7 +165,10 @@ else:
# Accept self-signed certs in dev
async with httpx.AsyncClient(verify=False) as client:
proxy_req = client.build_request(
request.method, url, headers=headers, content=await request.body()
request.method,
url,
headers=headers,
content=await request.body(),
)
proxy_resp = await client.send(proxy_req, stream=True)
content = await proxy_resp.aread()
@ -243,7 +178,11 @@ else:
k: v
for k, v in proxy_resp.headers.items()
if k.lower()
not in ["content-encoding", "transfer-encoding", "content-length"]
not in [
"content-encoding",
"transfer-encoding",
"content-length",
]
}
return Response(
content=content,
@ -292,6 +231,69 @@ else:
logger.error(f"REACT: WebSocket proxy error: {e}")
await websocket.close()
# Start background tasks
await session_manager.start_background_tasks()
logger.info("AI Voice Bot server started successfully!")
logger.info(f"Server URL: {public_url}")
logger.info(f"Sessions loaded: {session_manager.get_session_count()}")
logger.info(f"Lobbies available: {lobby_manager.get_lobby_count()}")
logger.info(f"Protected names: {auth_manager.get_protection_count()}")
if ADMIN_TOKEN:
logger.info("Admin endpoints protected with token")
else:
logger.warning("Admin endpoints are unprotected")
yield
# Shutdown
logger.info("Shutting down AI Voice Bot server...")
# Stop background tasks
if session_manager:
await session_manager.stop_background_tasks()
logger.info("Server shutdown complete")
# Set the lifespan
app.router.lifespan_context = lifespan
@app.websocket(f"{public_url}" + "ws/lobby/{lobby_id}/{session_id}")
async def lobby_websocket(
websocket: WebSocket,
lobby_id: str | None = Path(...),
session_id: str | None = Path(...),
):
"""WebSocket endpoint for lobby connections - now uses WebSocketConnectionManager"""
await websocket_manager.handle_connection(websocket, lobby_id, session_id)
# Health check for the new architecture
@app.get(f"{public_url}api/system/health")
def system_health():
"""System health check showing manager status"""
return {
"status": "ok",
"architecture": "modular",
"version": "2.0.0",
"managers": {
"session_manager": "active" if session_manager else "inactive",
"lobby_manager": "active" if lobby_manager else "inactive",
"auth_manager": "active" if auth_manager else "inactive",
"websocket_manager": "active" if websocket_manager else "inactive",
},
"statistics": {
"sessions": session_manager.get_session_count() if session_manager else 0,
"lobbies": lobby_manager.get_lobby_count() if lobby_manager else 0,
"protected_names": auth_manager.get_protection_count()
if auth_manager
else 0,
},
}
if __name__ == "__main__":
import uvicorn