72 lines
2.0 KiB
Python
72 lines
2.0 KiB
Python
from __future__ import annotations
|
|
|
|
from contextlib import asynccontextmanager
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
from fastapi import FastAPI, HTTPException
|
|
from fastapi.responses import FileResponse, HTMLResponse
|
|
from fastapi.staticfiles import StaticFiles
|
|
from pydantic import BaseModel
|
|
|
|
from app.service import KvmSwitcherService
|
|
|
|
|
|
PROJECT_ROOT = Path(__file__).resolve().parent.parent
|
|
STATIC_DIR = PROJECT_ROOT / "static"
|
|
INDEX_PATH = STATIC_DIR / "index.html"
|
|
|
|
|
|
class SettingsPayload(BaseModel):
|
|
device_role: str
|
|
device_port: str
|
|
|
|
|
|
def create_app(
|
|
service: KvmSwitcherService | None = None,
|
|
manage_lifecycle: bool = True,
|
|
) -> FastAPI:
|
|
active_service = service or KvmSwitcherService()
|
|
|
|
lifespan = None
|
|
if manage_lifecycle:
|
|
@asynccontextmanager
|
|
async def lifespan(app_instance: FastAPI):
|
|
del app_instance
|
|
active_service.start()
|
|
try:
|
|
yield
|
|
finally:
|
|
active_service.stop()
|
|
|
|
app = FastAPI(title="Internal KVM Switch", version="0.1.0", lifespan=lifespan)
|
|
app.state.kvm_service = active_service
|
|
|
|
if STATIC_DIR.exists():
|
|
app.mount("/static", StaticFiles(directory=STATIC_DIR), name="static")
|
|
|
|
@app.get("/")
|
|
async def root() -> Any:
|
|
if INDEX_PATH.exists():
|
|
return FileResponse(INDEX_PATH)
|
|
return HTMLResponse("<h1>Internal KVM Switch</h1><p>Dashboard file not found.</p>")
|
|
|
|
@app.get("/api/status")
|
|
async def get_status() -> dict[str, Any]:
|
|
return active_service.get_status()
|
|
|
|
@app.post("/api/settings")
|
|
async def post_settings(payload: SettingsPayload) -> dict[str, Any]:
|
|
try:
|
|
return active_service.save_settings(
|
|
device_role=payload.device_role,
|
|
device_port=payload.device_port,
|
|
)
|
|
except ValueError as exc:
|
|
raise HTTPException(status_code=400, detail=str(exc)) from exc
|
|
|
|
return app
|
|
|
|
|
|
app = create_app()
|