clean up firebase_website: offload cpu_percent to thread, cache fastfetch, fix regex, drop processes
This commit is contained in:
1 parent
ab3265667c
commit
7c2fd2a1ac
3 files changed
+86
-46
No files matched your search
@@ -11,9 +11,11 @@ from .config import get_db, SYSINFO_INTERVAL
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
FASTFETCH_CACHE_SECS = 300 # refresh fastfetch every 5 minutes
|
||||
|
||||
def _fmt_bytes(b: int) -> str:
|
||||
"""Format a byte count as a human-readable string (e.g. '1.2 GB')."""
|
||||
|
||||
def _fmt_size(b: int) -> str:
|
||||
"""Bytes → human-readable string (auto-scales B → TB)."""
|
||||
for unit in ("B", "KB", "MB", "GB", "TB"):
|
||||
if abs(b) < 1024:
|
||||
return f"{b:.1f} {unit}"
|
||||
@@ -22,12 +24,14 @@ def _fmt_bytes(b: int) -> str:
|
||||
|
||||
|
||||
class SysInfoSync:
|
||||
"""Background task that collects system stats and pushes them to Firestore."""
|
||||
"""Background task: collect system stats and push to Firestore."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self._task: asyncio.Task | None = None
|
||||
self._fastfetch: str = ""
|
||||
self._fastfetch_ts: float = 0
|
||||
|
||||
# ── public API ──────────────────────────────────────────────────────────
|
||||
# ── public ──────────────────────────────────────────────────────────
|
||||
|
||||
def start(self) -> None:
|
||||
if self._task is not None:
|
||||
@@ -42,7 +46,7 @@ class SysInfoSync:
|
||||
self._task = None
|
||||
log.info("SysInfo → Firestore sync stopped")
|
||||
|
||||
# ── internals ───────────────────────────────────────────────────────────
|
||||
# ── loop ────────────────────────────────────────────────────────────
|
||||
|
||||
async def _run(self) -> None:
|
||||
while True:
|
||||
@@ -51,51 +55,81 @@ class SysInfoSync:
|
||||
except asyncio.CancelledError:
|
||||
return
|
||||
except Exception:
|
||||
log.debug("SysInfo Firestore push failed", exc_info=True)
|
||||
log.warning("SysInfo push failed", exc_info=True)
|
||||
await asyncio.sleep(SYSINFO_INTERVAL)
|
||||
|
||||
# ── push ────────────────────────────────────────────────────────────
|
||||
|
||||
async def _push(self) -> None:
|
||||
cpu = psutil.cpu_percent(interval=1)
|
||||
mem = psutil.virtual_memory()
|
||||
disk = psutil.disk_usage("/")
|
||||
uptime_seconds = int(time.time() - psutil.boot_time())
|
||||
|
||||
days, r = divmod(uptime_seconds, 86400)
|
||||
hours, r = divmod(r, 3600)
|
||||
minutes, _ = divmod(r, 60)
|
||||
uptime_str = f"{days}d {hours}h {minutes}m" if days > 0 else f"{hours}h {minutes}m"
|
||||
|
||||
load1, load5, load15 = psutil.getloadavg()
|
||||
net = psutil.net_io_counters()
|
||||
swap = psutil.swap_memory()
|
||||
stats = await self._collect_stats()
|
||||
fetch = await self._get_fastfetch()
|
||||
|
||||
payload = {
|
||||
"online": True,
|
||||
"cpu": round(cpu, 1),
|
||||
"ram": round(mem.percent, 1),
|
||||
"ramUsed": f"{mem.used // (1024 ** 2)}MB",
|
||||
"ramTotal": f"{mem.total // (1024 ** 2)}MB",
|
||||
"disk": round(disk.percent, 1),
|
||||
"diskUsed": f"{disk.used // (1024 ** 3)}GB",
|
||||
"diskTotal": f"{disk.total // (1024 ** 3)}GB",
|
||||
"swap": round(swap.percent, 1),
|
||||
"swapUsed": f"{swap.used // (1024 ** 2)}MB",
|
||||
"swapTotal": f"{swap.total // (1024 ** 2)}MB",
|
||||
"uptime": uptime_str,
|
||||
"load1": round(load1, 1),
|
||||
"load5": round(load5, 1),
|
||||
"load15": round(load15, 1),
|
||||
"netSent": _fmt_bytes(net.bytes_sent),
|
||||
"netRecv": _fmt_bytes(net.bytes_recv),
|
||||
"processes": len(psutil.pids()),
|
||||
"fetch": await self._get_fastfetch(),
|
||||
"cpu": stats["cpu"],
|
||||
"ram": stats["ram"],
|
||||
"ramUsed": stats["ram_used"],
|
||||
"ramTotal": stats["ram_total"],
|
||||
"disk": stats["disk"],
|
||||
"diskUsed": stats["disk_used"],
|
||||
"diskTotal": stats["disk_total"],
|
||||
"swap": stats["swap"],
|
||||
"swapUsed": stats["swap_used"],
|
||||
"swapTotal": stats["swap_total"],
|
||||
"uptime": stats["uptime"],
|
||||
"load1": stats["load1"],
|
||||
"load5": stats["load5"],
|
||||
"load15": stats["load15"],
|
||||
"netSent": stats["net_sent"],
|
||||
"netRecv": stats["net_recv"],
|
||||
"fetch": fetch,
|
||||
}
|
||||
|
||||
db = get_db()
|
||||
await db.collection("sysinfo").document("server").set(payload, merge=True)
|
||||
|
||||
@staticmethod
|
||||
async def _get_fastfetch() -> str:
|
||||
# ── collectors ──────────────────────────────────────────────────────
|
||||
|
||||
async def _collect_stats(self) -> dict:
|
||||
"""Gather all psutil stats; offloads blocking calls to a thread."""
|
||||
cpu = await asyncio.to_thread(psutil.cpu_percent, interval=1)
|
||||
mem = psutil.virtual_memory()
|
||||
disk = psutil.disk_usage("/")
|
||||
swap = psutil.swap_memory()
|
||||
load1, load5, load15 = psutil.getloadavg()
|
||||
net = psutil.net_io_counters()
|
||||
uptime_seconds = int(time.time() - psutil.boot_time())
|
||||
|
||||
days, r = divmod(uptime_seconds, 86400)
|
||||
hours, r = divmod(r, 3600)
|
||||
minutes, _ = divmod(r, 60)
|
||||
uptime_str = f"{days}d {hours}h {minutes}m" if days else f"{hours}h {minutes}m"
|
||||
|
||||
return {
|
||||
"cpu": round(cpu, 1),
|
||||
"ram": round(mem.percent, 1),
|
||||
"ram_used": _fmt_size(mem.used),
|
||||
"ram_total": _fmt_size(mem.total),
|
||||
"disk": round(disk.percent, 1),
|
||||
"disk_used": _fmt_size(disk.used),
|
||||
"disk_total": _fmt_size(disk.total),
|
||||
"swap": round(swap.percent, 1),
|
||||
"swap_used": _fmt_size(swap.used),
|
||||
"swap_total": _fmt_size(swap.total),
|
||||
"uptime": uptime_str,
|
||||
"load1": round(load1, 1),
|
||||
"load5": round(load5, 1),
|
||||
"load15": round(load15, 1),
|
||||
"net_sent": _fmt_size(net.bytes_sent),
|
||||
"net_recv": _fmt_size(net.bytes_recv),
|
||||
}
|
||||
|
||||
async def _get_fastfetch(self) -> str:
|
||||
"""Return cached fastfetch output; refreshed every 5 minutes."""
|
||||
now = time.monotonic()
|
||||
if self._fastfetch and (now - self._fastfetch_ts) < FASTFETCH_CACHE_SECS:
|
||||
return self._fastfetch
|
||||
|
||||
try:
|
||||
proc = await asyncio.create_subprocess_exec(
|
||||
"fastfetch", "--pipe", "--logo", "none",
|
||||
@@ -103,8 +137,11 @@ class SysInfoSync:
|
||||
stderr=asyncio.subprocess.DEVNULL,
|
||||
)
|
||||
stdout, _ = await asyncio.wait_for(proc.communicate(), timeout=5)
|
||||
clean = re.sub(r"\x1b\[[0-9;]*[a-zA-Z]|\[[0-9]+[A-Z]", "", stdout.decode())
|
||||
clean = re.sub(r"\x1b\[[0-9;]*[a-zA-Z]", "", stdout.decode())
|
||||
lines = [line for line in clean.strip().splitlines() if line.strip()]
|
||||
return "\n".join(lines[:15])
|
||||
self._fastfetch = "\n".join(lines[:15])
|
||||
self._fastfetch_ts = now
|
||||
except Exception:
|
||||
return ""
|
||||
if not self._fastfetch:
|
||||
self._fastfetch = ""
|
||||
return self._fastfetch
|
||||
Reference in new issue
Block a user