mirror of
https://github.com/lrnselfreliance/wrolpi.git
synced 2026-10-26 02:48:38 -04:00
167 lines
5.6 KiB
Python
167 lines
5.6 KiB
Python
"""
|
|
Stats API endpoints for WROLPi Controller.
|
|
|
|
Endpoints read from cached status data collected by the background worker.
|
|
Individual endpoints remain for backwards compatibility.
|
|
New aggregated /api/stats endpoint returns all status at once.
|
|
|
|
This endpoint provides system-level stats. App-level status (flags, downloads,
|
|
wrol_mode) remain in the main WROLPi API at /api/status.
|
|
"""
|
|
|
|
from fastapi import APIRouter, Request
|
|
from fastapi.responses import JSONResponse
|
|
|
|
from controller.lib.admin import get_hotspot_status, get_throttle_status, HotspotStatus
|
|
from controller.lib.config import is_docker_mode, is_rpi, is_rpi4, is_rpi5
|
|
from controller.lib.status import (
|
|
get_cpu_status,
|
|
get_load_status,
|
|
get_memory_status,
|
|
get_network_status,
|
|
get_power_status,
|
|
get_primary_drive_status,
|
|
)
|
|
|
|
router = APIRouter(prefix="/api/stats", tags=["stats"])
|
|
|
|
|
|
def get_cached_status(request: Request) -> dict:
|
|
"""Get cached status from app.state, or empty dict if not yet available."""
|
|
return getattr(request.app.state, "cached_status", {})
|
|
|
|
|
|
def get_system_info() -> dict:
|
|
"""
|
|
Get static system info that doesn't need frequent updates.
|
|
These are collected on each request as they rarely change.
|
|
"""
|
|
from controller.lib.config import get_config
|
|
|
|
hotspot_status = get_hotspot_status()
|
|
throttle_status = get_throttle_status()
|
|
|
|
# Get hotspot SSID from config if hotspot is connected
|
|
config = get_config()
|
|
hotspot_config = config.get("hotspot", {})
|
|
hotspot_ssid = hotspot_config.get("ssid", "WROLPi") if hotspot_status == HotspotStatus.connected else None
|
|
|
|
return {
|
|
"dockerized": is_docker_mode(),
|
|
"is_rpi": is_rpi(),
|
|
"is_rpi4": is_rpi4(),
|
|
"is_rpi5": is_rpi5(),
|
|
"hotspot_status": hotspot_status.name,
|
|
"hotspot_ssid": hotspot_ssid,
|
|
"throttle_status": throttle_status.name,
|
|
}
|
|
|
|
|
|
@router.get("")
|
|
@router.get("/")
|
|
async def get_all_stats(request: Request):
|
|
"""
|
|
Get all system status at once (cached data + system info).
|
|
|
|
Returns aggregated CPU, memory, load, drives, network, power, iostat,
|
|
processes, disk_bandwidth stats along with system info (dockerized,
|
|
is_rpi, hotspot, throttle).
|
|
|
|
This endpoint returns O(1) cached data updated every ~5 seconds,
|
|
plus system info collected on each request.
|
|
"""
|
|
cached = get_cached_status(request)
|
|
|
|
if not cached:
|
|
# Fallback to on-demand collection if cache not yet populated
|
|
from controller.lib.status_worker import collect_all_status
|
|
cached = await collect_all_status()
|
|
|
|
# Add system info to response
|
|
response = {**cached, **get_system_info()}
|
|
return JSONResponse(content=response)
|
|
|
|
|
|
@router.get("/cpu")
|
|
async def get_cpu(request: Request):
|
|
"""Get CPU status (usage, frequency, temperature)."""
|
|
cached = get_cached_status(request)
|
|
if cached and cached.get("cpu_stats"):
|
|
return JSONResponse(content=cached["cpu_stats"])
|
|
return JSONResponse(content=get_cpu_status())
|
|
|
|
|
|
@router.get("/memory")
|
|
async def get_memory(request: Request):
|
|
"""Get memory usage statistics."""
|
|
cached = get_cached_status(request)
|
|
if cached and cached.get("memory_stats"):
|
|
return JSONResponse(content=cached["memory_stats"])
|
|
return JSONResponse(content=get_memory_status())
|
|
|
|
|
|
@router.get("/load")
|
|
async def get_load(request: Request):
|
|
"""Get system load averages."""
|
|
cached = get_cached_status(request)
|
|
if cached and cached.get("load_stats"):
|
|
return JSONResponse(content=cached["load_stats"])
|
|
return JSONResponse(content=get_load_status())
|
|
|
|
|
|
@router.get("/drives/primary")
|
|
async def get_primary_drive(request: Request):
|
|
"""Get status of the primary WROLPi drive."""
|
|
cached = get_cached_status(request)
|
|
if cached and cached.get("drives_stats"):
|
|
# Find primary drive from cached drives
|
|
for drive in cached["drives_stats"]:
|
|
if drive.get("mount") == "/media/wrolpi":
|
|
return JSONResponse(content={"mounted": True, **drive})
|
|
return JSONResponse(content={"mounted": False})
|
|
|
|
# Fallback to direct call
|
|
status = get_primary_drive_status()
|
|
if status is None:
|
|
return JSONResponse(content={"mounted": False})
|
|
return JSONResponse(content={"mounted": True, **status})
|
|
|
|
|
|
@router.get("/network")
|
|
async def get_network(request: Request):
|
|
"""Get network interface statistics."""
|
|
cached = get_cached_status(request)
|
|
if cached and cached.get("nic_bandwidth_stats"):
|
|
return JSONResponse(content=cached["nic_bandwidth_stats"])
|
|
return JSONResponse(content=get_network_status())
|
|
|
|
|
|
@router.get("/power")
|
|
async def get_power(request: Request):
|
|
"""Get power status (undervoltage, throttling)."""
|
|
cached = get_cached_status(request)
|
|
if cached and cached.get("power_stats"):
|
|
return JSONResponse(content=cached["power_stats"])
|
|
return JSONResponse(content=get_power_status())
|
|
|
|
|
|
@router.get("/iostat")
|
|
async def get_iostat(request: Request):
|
|
"""Get IO statistics (iowait, user, system, idle percentages)."""
|
|
cached = get_cached_status(request)
|
|
if cached and cached.get("iostat_stats"):
|
|
return JSONResponse(content=cached["iostat_stats"])
|
|
# Fallback to direct call
|
|
from controller.lib.status import get_iostat_status
|
|
return JSONResponse(content=get_iostat_status())
|
|
|
|
|
|
@router.get("/uptime")
|
|
async def get_uptime(request: Request):
|
|
"""Get system uptime information."""
|
|
cached = get_cached_status(request)
|
|
if cached and cached.get("uptime_stats"):
|
|
return JSONResponse(content=cached["uptime_stats"])
|
|
# Fallback to direct call
|
|
from controller.lib.status import get_uptime_status
|
|
return JSONResponse(content=get_uptime_status())
|