gsproremote/backend/app/main.py

116 lines
3.3 KiB
Python
Raw Normal View History

"""
Main FastAPI application for GSPro Remote backend.
"""
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 .api import actions, config, system, vision
from .core.config import AppConfig, get_config
from .core.mdns import MDNSService
# Configure logging
logging.basicConfig(level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s")
logger = logging.getLogger(__name__)
@asynccontextmanager
async def lifespan(app: FastAPI):
"""
Application lifespan manager for startup/shutdown tasks.
"""
# Startup
logger.info("Starting GSPro Remote backend v0.1.0")
# Load configuration
config = get_config()
logger.info(f"Configuration loaded from {config.config_path}")
# Start mDNS service if enabled
mdns_service = None
if config.server.mdns_enabled:
try:
mdns_service = MDNSService(name="gsproapp", port=config.server.port, service_type="_http._tcp.local.")
mdns_service.start()
logger.info(f"mDNS service started: gsproapp.local:{config.server.port}")
except Exception as e:
logger.warning(f"Failed to start mDNS service: {e}")
yield
# Shutdown
logger.info("Shutting down GSPro Remote backend")
# Stop mDNS service
if mdns_service:
mdns_service.stop()
logger.info("mDNS service stopped")
# Save configuration
config.save()
logger.info("Configuration saved")
def create_app() -> FastAPI:
"""
Create and configure the FastAPI application.
"""
app = FastAPI(
title="GSPro Remote",
version="0.1.0",
description="Remote control API for GSPro golf simulator",
docs_url="/api/docs",
redoc_url="/api/redoc",
openapi_url="/api/openapi.json",
lifespan=lifespan,
)
# Configure CORS
app.add_middleware(
CORSMiddleware,
allow_origins=["*"], # In production, specify actual origins
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Mount API routers
app.include_router(actions.router, prefix="/api/actions", tags=["Actions"])
app.include_router(config.router, prefix="/api/config", tags=["Configuration"])
app.include_router(vision.router, prefix="/api/vision", tags=["Vision"])
app.include_router(system.router, prefix="/api/system", tags=["System"])
# Serve frontend UI if built
ui_path = Path(__file__).parent.parent / "ui"
if ui_path.exists():
app.mount("/ui", StaticFiles(directory=str(ui_path), html=True), name="ui")
logger.info(f"Serving UI from {ui_path}")
# Root redirect
@app.get("/")
async def root():
return {
"name": "GSPro Remote",
"version": "0.1.0",
"status": "running",
"ui": "/ui" if ui_path.exists() else None,
"docs": "/api/docs",
}
return app
# Create the application instance
app = create_app()
if __name__ == "__main__":
import uvicorn
config = get_config()
uvicorn.run("app.main:app", host=config.server.host, port=config.server.port, reload=True, log_level="info")