feat(webui): режим console (только RS232-консоль, питание отключено)

- ATXPI_MODE=console: /api/power/* → 403, кнопки питания скрыты в UI
- /api/status отдаёт mode; env-шаблон и install.sh учитывают ATXPI_MODE
- нужно для безопасного запуска панели на серверах-«управленцах» без риска питания
This commit is contained in:
toros
2026-09-08 23:34:23 +05:00
parent e3f7865ce6
commit 49b6cf89f4
5 changed files with 30 additions and 6 deletions
+14 -1
View File
@@ -22,7 +22,7 @@ import os
import time
from pathlib import Path
from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Request
from fastapi import FastAPI, WebSocket, WebSocketDisconnect, Request, HTTPException
from fastapi.responses import FileResponse, JSONResponse
from fastapi.staticfiles import StaticFiles
@@ -34,9 +34,16 @@ logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(mess
STATIC = os.path.join(os.path.dirname(os.path.abspath(__file__)), "static")
WEB_TOKEN = os.environ.get("ATXPI_WEB_TOKEN", "")
MODE = os.environ.get("ATXPI_MODE", "full") # full | console (только консоль, питание отключено)
AUDIT = os.environ.get("ATXPI_AUDIT", "/etc/atxpi/audit.jsonl")
def _power_guard():
"""В режиме console питание выключено — деструктивные действия запрещены."""
if MODE == "console":
raise HTTPException(status_code=403, detail="console-only mode: power disabled")
def audit(action: str, **kw):
"""Логируем действие в jsonl (для /api/history)."""
entry = {"t": time.time(), "action": action, **kw}
@@ -77,29 +84,34 @@ async def auth_mw(request: Request, call_next):
# ── REST: питание ──────────────────────────────────────────────────────────
@app.get("/api/power")
async def api_power_status():
_power_guard()
return power_mod.status()
@app.post("/api/power/on")
async def api_power_on():
_power_guard()
audit("power_on")
return power_mod.press_power()
@app.post("/api/power/off")
async def api_power_off():
_power_guard()
audit("power_off")
return power_mod.force_off()
@app.post("/api/power/reset")
async def api_power_reset():
_power_guard()
audit("power_reset")
return power_mod.press_reset()
@app.post("/api/power/cycle")
async def api_power_cycle():
_power_guard()
audit("power_cycle")
return power_mod.cycle()
@@ -113,6 +125,7 @@ async def api_status():
"driver": DRIVER,
"serial_port": SERIAL_PORT,
"serial_baud": SERIAL_BAUD,
"mode": MODE,
}