version 5.1.8
Release / release (push) Successful in 5s

- fix: matrix/sms_voipms notifications blocked the event loop on timeout;
  make send_notification async, dispatch all channel drivers as non-blocking
  tasks (asyncio.to_thread for sync drivers, asyncio.wait_for for async);
  update all call sites to fire-and-forget via create_task
- feat: add /about page with version, runtime, uptime counter, and repo link
- fix: hbc_mini plugin data format now matches full hbc client so Host
  Overview displays memory, disk, and network metrics correctly

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Andreas Wrede
2026-05-01 05:33:27 -04:00
parent 64710fd4cd
commit c4f09e9ced
10 changed files with 349 additions and 123 deletions
+36 -22
View File
@@ -233,7 +233,7 @@ class OSInfoPlugin(InfoPlugin):
"machine": platform.machine(),
"architecture": platform.architecture()[0],
"python_version": platform.python_version(),
"hbc_version": "5.1.7",
"hbc_version": "5.1.8",
"hbc_type": "mini",
}
if platform.system() == "Linux":
@@ -531,19 +531,27 @@ class MemoryMonitorPlugin(MonitorPlugin):
return {}
total = mi.get("MemTotal", 0)
avail = mi.get("MemAvailable", mi.get("MemFree", 0))
free = mi.get("MemFree", 0)
used = total - avail
data: Dict[str, Any] = {
"mem_total_kb": total,
"mem_used_kb": used,
"mem_available_kb": avail,
"mem_percent": round(100.0 * used / total, 1) if total else 0.0,
"memory_total": total * 1024,
"memory_used": used * 1024,
"memory_available": avail * 1024,
"memory_free": free * 1024,
"memory_percent": round(100.0 * used / total, 1) if total else 0.0,
}
for field, key in (("Buffers", "memory_buffers"), ("Cached", "memory_cached"),
("Active", "memory_active"), ("Inactive", "memory_inactive")):
if field in mi:
data[key] = mi[field] * 1024
stotal = mi.get("SwapTotal", 0)
if stotal:
sfree = mi.get("SwapFree", 0)
data["swap_total_kb"] = stotal
data["swap_used_kb"] = stotal - sfree
data["swap_percent"] = round(100.0 * (stotal - sfree) / stotal, 1)
sused = stotal - sfree
data["swap_total"] = stotal * 1024
data["swap_used"] = sused * 1024
data["swap_free"] = sfree * 1024
data["swap_percent"] = round(100.0 * sused / stotal, 1)
return data
@@ -579,7 +587,7 @@ class DiskMonitorPlugin(MonitorPlugin):
except Exception as e:
self.logger.warning("df failed: %s", e)
return {}
data: Dict[str, Any] = {}
partitions: Dict[str, Any] = {}
for line in out.decode(errors="replace").splitlines()[1:]:
parts = line.split()
if len(parts) < 6:
@@ -588,14 +596,19 @@ class DiskMonitorPlugin(MonitorPlugin):
if self.mounts and mount not in self.mounts:
continue
try:
key = re.sub(r"[^a-zA-Z0-9_]", "_", mount).strip("_") or "root"
data[f"{key}_total_kb"] = int(parts[1])
data[f"{key}_used_kb"] = int(parts[2])
data[f"{key}_avail_kb"] = int(parts[3])
data[f"{key}_percent"] = int(parts[4].rstrip("%"))
total_kb = int(parts[1])
used_kb = int(parts[2])
avail_kb = int(parts[3])
pct = int(parts[4].rstrip("%"))
partitions[mount] = {
"total": total_kb * 1024,
"used": used_kb * 1024,
"free": avail_kb * 1024,
"percent": pct,
}
except (ValueError, IndexError):
continue
return data
return {"partitions": partitions} if partitions else {}
# ---------------------------------------------------------------------------
@@ -651,17 +664,18 @@ class NetworkMonitorPlugin(MonitorPlugin):
self._prev = (now, curr)
if dt <= 0:
return {}
data: Dict[str, Any] = {}
interfaces: Dict[str, Any] = {}
for iface, (rx, tx) in curr.items():
if iface in self.skip_ifaces or iface not in prev:
continue
prx, ptx = prev[iface]
key = re.sub(r"[^a-zA-Z0-9_]", "_", iface)
data[f"{key}_rx_bps"] = round((rx - prx) / dt)
data[f"{key}_tx_bps"] = round((tx - ptx) / dt)
data[f"{key}_rx_bytes"] = rx
data[f"{key}_tx_bytes"] = tx
return data
interfaces[iface] = {
"bytes_recv": rx,
"bytes_sent": tx,
"bytes_recv_delta": rx - prx,
"bytes_sent_delta": tx - ptx,
}
return {"interfaces": interfaces} if interfaces else {}
# ---------------------------------------------------------------------------