143 lines
4.1 KiB
Python
143 lines
4.1 KiB
Python
from __future__ import annotations
|
|
|
|
import json
|
|
import logging
|
|
import sys
|
|
from contextlib import asynccontextmanager
|
|
from typing import Any, Dict
|
|
|
|
import uvicorn
|
|
from fastapi import FastAPI
|
|
from fastapi.staticfiles import StaticFiles
|
|
from pathlib import Path
|
|
|
|
import vna_system.core.singletons as singletons
|
|
from vna_system.core.processing.sweep_processor import SweepProcessingManager
|
|
from vna_system.api.websockets.websocket_handler import WebSocketManager
|
|
from vna_system.api.endpoints import health, processing, web_ui
|
|
from vna_system.api.websockets import processing as ws_processing
|
|
|
|
|
|
# Configure logging
|
|
logging.basicConfig(
|
|
level=logging.INFO,
|
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
|
)
|
|
|
|
# Disable noisy third-party loggers
|
|
logging.getLogger('kaleido').setLevel(logging.ERROR)
|
|
logging.getLogger('choreographer').setLevel(logging.ERROR)
|
|
logging.getLogger('kaleido.kaleido').setLevel(logging.ERROR)
|
|
logging.getLogger('choreographer.browsers.chromium').setLevel(logging.ERROR)
|
|
logging.getLogger('choreographer.browser_async').setLevel(logging.ERROR)
|
|
logging.getLogger('choreographer.utils._tmpfile').setLevel(logging.ERROR)
|
|
logging.getLogger('kaleido._kaleido_tab').setLevel(logging.ERROR)
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
def load_config(config_path: str = "vna_system/api/api_config.json") -> Dict[str, Any]:
|
|
"""Load API configuration from file."""
|
|
try:
|
|
with open(config_path, 'r') as f:
|
|
config = json.load(f)
|
|
logger.info(f"Loaded API config from {config_path}")
|
|
return config
|
|
except Exception as e:
|
|
logger.error(f"Failed to load config: {e}")
|
|
sys.exit(1)
|
|
|
|
|
|
@asynccontextmanager
|
|
async def lifespan(app: FastAPI):
|
|
"""FastAPI lifespan events."""
|
|
# Startup
|
|
logger.info("Starting VNA API Server...")
|
|
|
|
try:
|
|
# Load config
|
|
config = load_config()
|
|
|
|
# Set log level
|
|
log_level = config.get("logging", {}).get("level", "INFO")
|
|
logging.getLogger().setLevel(getattr(logging, log_level))
|
|
|
|
# Start acquisition
|
|
logger.info("Starting data acquisition...")
|
|
singletons.vna_data_acquisition_instance.start()
|
|
|
|
# Connect processing to acquisition
|
|
singletons.processing_manager.set_sweep_buffer(singletons.vna_data_acquisition_instance.sweep_buffer)
|
|
singletons.processing_manager.start()
|
|
logger.info("Sweep processing started")
|
|
|
|
logger.info("VNA API Server started successfully")
|
|
|
|
yield
|
|
|
|
except Exception as e:
|
|
logger.error(f"Error during startup: {e}")
|
|
raise
|
|
|
|
# Shutdown
|
|
logger.info("Shutting down VNA API Server...")
|
|
|
|
if singletons.processing_manager:
|
|
singletons.processing_manager.stop()
|
|
logger.info("Processing stopped")
|
|
|
|
if singletons.vna_data_acquisition_instance and singletons.vna_data_acquisition_instance.is_running:
|
|
singletons.vna_data_acquisition_instance.stop()
|
|
logger.info("Acquisition stopped")
|
|
|
|
logger.info("VNA API Server shutdown complete")
|
|
|
|
|
|
# Create FastAPI app
|
|
app = FastAPI(
|
|
title="VNA System API",
|
|
description="Real-time VNA data acquisition and processing API",
|
|
version="1.0.0",
|
|
lifespan=lifespan
|
|
)
|
|
|
|
# Mount static files for web UI
|
|
WEB_UI_DIR = Path(__file__).parent.parent / "web_ui"
|
|
STATIC_DIR = WEB_UI_DIR / "static"
|
|
|
|
if STATIC_DIR.exists():
|
|
app.mount("/static", StaticFiles(directory=str(STATIC_DIR)), name="static")
|
|
logger.info(f"Mounted static files from: {STATIC_DIR}")
|
|
else:
|
|
logger.warning(f"Static directory not found: {STATIC_DIR}")
|
|
|
|
# Include routers
|
|
app.include_router(web_ui.router) # Web UI should be first for root path
|
|
app.include_router(health.router)
|
|
app.include_router(processing.router)
|
|
app.include_router(ws_processing.router)
|
|
|
|
|
|
def main():
|
|
"""Main entry point."""
|
|
config = load_config()
|
|
|
|
# Server configuration
|
|
server_config = config.get("server", {})
|
|
host = server_config.get("host", "0.0.0.0")
|
|
port = server_config.get("port", 8000)
|
|
|
|
# Start server
|
|
uvicorn.run(
|
|
"vna_system.api.main:app",
|
|
host=host,
|
|
port=port,
|
|
log_level="info",
|
|
reload=False
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main() |