Files
Gilles Soulier c67befc549 addon
2026-01-05 16:08:01 +01:00

164 lines
4.7 KiB
Python
Executable File

"""
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)