From 0a761e57994e882affee5d9c573e8e27b6b13b1e Mon Sep 17 00:00:00 2001 From: benya Date: Sun, 8 Feb 2026 03:48:04 +0300 Subject: [PATCH] Fix OpenWrt rate/lease mapping and queue pending --- services/openwrt.py | 20 +++++++++++++++++++- services/queue.py | 46 +++++++++++++++++++++++++++++---------------- 2 files changed, 49 insertions(+), 17 deletions(-) diff --git a/services/openwrt.py b/services/openwrt.py index 408e33b..e070eab 100644 --- a/services/openwrt.py +++ b/services/openwrt.py @@ -38,7 +38,11 @@ def _format_rate(rate: Any) -> str: return "?" if val <= 0: return "?" - return f"{val / 1000:.1f}M" + if val >= 1_000_000: + return f"{val / 1_000_000:.1f}M" + if val >= 1_000: + return f"{val / 1_000:.1f}K" + return f"{val:.0f}b" def _extract_wan_ip(wan: dict[str, Any]) -> str | None: @@ -128,6 +132,18 @@ def _extract_lease_name_map(leases: Any) -> dict[str, str]: return out +def _extract_lease_name_map_fallback(raw: str) -> dict[str, str]: + out: dict[str, str] = {} + for line in raw.splitlines(): + parts = line.strip().split() + if len(parts) < 4: + continue + _expiry, mac, _ipaddr, host = parts[:4] + host = host if host != "*" else "unknown" + out[str(mac).lower()] = str(host) + return out + + def _extract_ifnames(wireless: dict[str, Any]) -> list[str]: ifnames: list[str] = [] if not isinstance(wireless, dict): @@ -360,6 +376,8 @@ async def get_openwrt_status(cfg: dict[str, Any]) -> str: ifnames.extend(_extract_hostapd_ifnames(out_l)) ifnames = sorted({name for name in ifnames if name}) lease_name_map = _extract_lease_name_map(leases or {}) + if leases_fallback: + lease_name_map.update(_extract_lease_name_map_fallback(leases_fallback)) if ifnames: for ifname in ifnames: cmd_clients = ssh_cmd + ["ubus", "call", f"hostapd.{ifname}", "get_clients"] diff --git a/services/queue.py b/services/queue.py index 291dbb9..0566f9a 100644 --- a/services/queue.py +++ b/services/queue.py @@ -1,22 +1,34 @@ import asyncio import time +from collections import deque from typing import Awaitable, Callable, Any _queue: asyncio.Queue = asyncio.Queue() _current_label: str | None = None _current_meta: dict[str, Any] | None = None +_pending: deque[tuple[str, float]] = deque() async def enqueue(label: str, job: Callable[[], Awaitable[None]]) -> int: - await _queue.put((label, job, time.time())) - return _queue.qsize() + enqueued_at = time.time() + await _queue.put((label, job, enqueued_at)) + _pending.append((label, enqueued_at)) + return len(_pending) async def worker(): global _current_label, _current_meta while True: label, job, enqueued_at = await _queue.get() + if _pending: + if _pending[0] == (label, enqueued_at): + _pending.popleft() + else: + try: + _pending.remove((label, enqueued_at)) + except ValueError: + pass _current_label = label _current_meta = {"enqueued_at": enqueued_at, "started_at": time.time()} try: @@ -28,31 +40,33 @@ async def worker(): def format_status() -> str: - pending = list(_queue._queue) - lines = ["๐Ÿงพ Queue"] - lines.append(f"๐Ÿ”„ Running: {_current_label or 'idle'}") - lines.append(f"โณ Pending: {len(pending)}") + pending = list(_pending) + lines = ["?? Queue"] + lines.append(f"?? Running: {_current_label or 'idle'}") + lines.append(f"? Pending: {len(pending)}") if pending: preview = ", ".join([p[0] for p in pending[:5]]) - lines.append(f"โžก๏ธ Next: {preview}") - return "\n".join(lines) + lines.append(f"?? Next: {preview}") + return " +".join(lines) def format_details(limit: int = 10) -> str: now = time.time() - lines = ["๐Ÿงพ Queue details"] + lines = ["?? Queue details"] if _current_label: started_at = _current_meta.get("started_at") if _current_meta else None runtime = f"{int(now - started_at)}s" if started_at else "n/a" - lines.append(f"๐Ÿ”„ Running: {_current_label} ({runtime})") + lines.append(f"?? Running: {_current_label} ({runtime})") else: - lines.append("๐Ÿ”„ Running: idle") + lines.append("?? Running: idle") - pending = list(_queue._queue) - lines.append(f"โณ Pending: {len(pending)}") + pending = list(_pending) + lines.append(f"? Pending: {len(pending)}") if pending: - lines.append("๐Ÿ”ข Position | Label | Wait") - for i, (label, _job, enqueued_at) in enumerate(pending[:limit], start=1): + lines.append("?? Position | Label | Wait") + for i, (label, enqueued_at) in enumerate(pending[:limit], start=1): wait = int(now - enqueued_at) lines.append(f"{i:>3} | {label} | {wait}s") - return "\n".join(lines) + return " +".join(lines)