""" Linux BenchTools - Main Application """ from fastapi import FastAPI, Depends from fastapi.middleware.cors import CORSMiddleware from contextlib import asynccontextmanager from sqlalchemy.orm import Session from datetime import datetime import os import shutil from app.core.config import settings from app.db.init_db import init_db from app.db.session import get_db from app.api import benchmark, devices, links, docs from app.api.endpoints import peripherals, locations @asynccontextmanager async def lifespan(app: FastAPI): """Lifespan events""" # Startup print("🚀 Starting Linux BenchTools...") init_db() print("✅ Linux BenchTools started successfully") yield # Shutdown print("🛑 Shutting down Linux BenchTools...") # Create FastAPI app app = FastAPI( title=settings.APP_NAME, description=settings.APP_DESCRIPTION, version=settings.APP_VERSION, lifespan=lifespan ) # Configure CORS app.add_middleware( CORSMiddleware, allow_origins=settings.CORS_ORIGINS, allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) # Include routers app.include_router(benchmark.router, prefix=settings.API_PREFIX, tags=["Benchmarks"]) app.include_router(devices.router, prefix=settings.API_PREFIX, tags=["Devices"]) app.include_router(links.router, prefix=settings.API_PREFIX, tags=["Links"]) app.include_router(docs.router, prefix=settings.API_PREFIX, tags=["Documents"]) # Peripherals module (if enabled) if settings.PERIPHERALS_MODULE_ENABLED: app.include_router(peripherals.router, prefix=f"{settings.API_PREFIX}/peripherals", tags=["Peripherals"]) app.include_router(locations.router, prefix=f"{settings.API_PREFIX}/locations", tags=["Locations"]) # Root endpoint @app.get("/") async def root(): """Root endpoint""" return { "app": settings.APP_NAME, "version": settings.APP_VERSION, "description": settings.APP_DESCRIPTION, "api_docs": f"{settings.API_PREFIX}/docs" } # Health check @app.get(f"{settings.API_PREFIX}/health") async def health_check(): """Health check endpoint""" return {"status": "ok"} # Stats endpoint (for dashboard) @app.get(f"{settings.API_PREFIX}/stats") async def get_stats(db: Session = Depends(get_db)): """Get global statistics""" from app.models.device import Device from app.models.benchmark import Benchmark from sqlalchemy import func total_devices = db.query(Device).count() total_benchmarks = db.query(Benchmark).count() # Get average score avg_score = db.query(func.avg(Benchmark.global_score)).scalar() # Get last benchmark date last_bench = db.query(Benchmark).order_by(Benchmark.run_at.desc()).first() last_bench_date = last_bench.run_at.isoformat() if last_bench else None return { "total_devices": total_devices, "total_benchmarks": total_benchmarks, "avg_global_score": round(avg_score, 2) if avg_score else 0, "last_benchmark_at": last_bench_date } # Config endpoint (for frontend to get API token and server info) @app.get(f"{settings.API_PREFIX}/config") async def get_config(): """Get frontend configuration (API token, server URLs, etc.)""" return { "api_token": settings.API_TOKEN, "iperf_server": "10.0.0.50" } def _sqlite_path(url: str) -> str: if url.startswith("sqlite:////"): return url.replace("sqlite:////", "/") if url.startswith("sqlite:///"): return url.replace("sqlite:///", "") return "" @app.post(f"{settings.API_PREFIX}/backup") async def backup_databases(): """Create timestamped backups of the main and peripherals databases.""" timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") backups = [] main_db = _sqlite_path(settings.DATABASE_URL) peripherals_db = _sqlite_path(settings.PERIPHERALS_DB_URL) db_paths = { "main": main_db, "peripherals": peripherals_db } # Use main DB directory for backups base_dir = os.path.dirname(main_db) if main_db else "/app/data" backup_dir = os.path.join(base_dir, "backups") os.makedirs(backup_dir, exist_ok=True) for key, path in db_paths.items(): if not path or not os.path.exists(path): continue filename = f"{key}_backup_{timestamp}.db" dest = os.path.join(backup_dir, filename) shutil.copy2(path, dest) backups.append({ "name": key, "source": path, "destination": dest, "filename": filename }) return { "success": True, "timestamp": timestamp, "backup_dir": backup_dir, "backups": backups } if __name__ == "__main__": import uvicorn uvicorn.run("app.main:app", host="0.0.0.0", port=8007, reload=True)