Fix OpenWrt SSH data parsing
This commit is contained in:
@@ -22,10 +22,13 @@ def _format_load(load: list[Any] | None) -> str:
|
|||||||
values = []
|
values = []
|
||||||
for raw in load[:3]:
|
for raw in load[:3]:
|
||||||
try:
|
try:
|
||||||
values.append(float(raw) / 65536.0)
|
values.append(float(raw))
|
||||||
except (TypeError, ValueError):
|
except (TypeError, ValueError):
|
||||||
values.append(0.0)
|
values.append(0.0)
|
||||||
return " ".join(f"{val:.2f}" for val in values)
|
scale = 1.0
|
||||||
|
if values and max(values) > 1000:
|
||||||
|
scale = 1 / 65536.0
|
||||||
|
return " ".join(f"{val * scale:.2f}" for val in values)
|
||||||
|
|
||||||
|
|
||||||
def _format_rate(rate: Any) -> str:
|
def _format_rate(rate: Any) -> str:
|
||||||
@@ -62,17 +65,27 @@ def _extract_wifi_clients(wireless: dict[str, Any]) -> list[str]:
|
|||||||
if not isinstance(iface, dict):
|
if not isinstance(iface, dict):
|
||||||
continue
|
continue
|
||||||
ifname = iface.get("ifname") or "wifi"
|
ifname = iface.get("ifname") or "wifi"
|
||||||
assoclist = iface.get("assoclist") or {}
|
assoclist = iface.get("assoclist")
|
||||||
if not isinstance(assoclist, dict):
|
stations = iface.get("stations")
|
||||||
continue
|
if isinstance(assoclist, dict):
|
||||||
for mac, meta in assoclist.items():
|
for mac, meta in assoclist.items():
|
||||||
if not isinstance(meta, dict):
|
if not isinstance(meta, dict):
|
||||||
continue
|
continue
|
||||||
signal = meta.get("signal")
|
signal = meta.get("signal")
|
||||||
rx = _format_rate((meta.get("rx") or {}).get("rate"))
|
rx = _format_rate((meta.get("rx") or {}).get("rate"))
|
||||||
tx = _format_rate((meta.get("tx") or {}).get("rate"))
|
tx = _format_rate((meta.get("tx") or {}).get("rate"))
|
||||||
sig = f"{signal}dBm" if isinstance(signal, (int, float)) else "?"
|
sig = f"{signal}dBm" if isinstance(signal, (int, float)) else "?"
|
||||||
clients.append(f"{ifname} {mac} {sig} rx:{rx} tx:{tx}")
|
clients.append(f"{ifname} {mac} {sig} rx:{rx} tx:{tx}")
|
||||||
|
elif isinstance(stations, list):
|
||||||
|
for meta in stations:
|
||||||
|
if not isinstance(meta, dict):
|
||||||
|
continue
|
||||||
|
mac = meta.get("mac") or "?"
|
||||||
|
signal = meta.get("signal")
|
||||||
|
rx = _format_rate((meta.get("rx") or {}).get("rate"))
|
||||||
|
tx = _format_rate((meta.get("tx") or {}).get("rate"))
|
||||||
|
sig = f"{signal}dBm" if isinstance(signal, (int, float)) else "?"
|
||||||
|
clients.append(f"{ifname} {mac} {sig} rx:{rx} tx:{tx}")
|
||||||
return clients
|
return clients
|
||||||
|
|
||||||
|
|
||||||
@@ -91,6 +104,36 @@ def _extract_leases(leases: dict[str, Any]) -> list[str]:
|
|||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_proc_fallback(raw: str) -> tuple[int | None, list[float] | None]:
|
||||||
|
uptime = None
|
||||||
|
load = None
|
||||||
|
for line in raw.splitlines():
|
||||||
|
parts = line.split()
|
||||||
|
if len(parts) >= 2 and uptime is None:
|
||||||
|
try:
|
||||||
|
uptime = int(float(parts[0]))
|
||||||
|
except ValueError:
|
||||||
|
uptime = None
|
||||||
|
if len(parts) >= 3 and load is None:
|
||||||
|
try:
|
||||||
|
load = [float(parts[0]), float(parts[1]), float(parts[2])]
|
||||||
|
except ValueError:
|
||||||
|
load = None
|
||||||
|
return uptime, load
|
||||||
|
|
||||||
|
|
||||||
|
def _parse_leases_fallback(raw: str) -> list[str]:
|
||||||
|
out = []
|
||||||
|
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.append(f"{ipaddr} {host} ({mac})")
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
async def get_openwrt_status(cfg: dict[str, Any]) -> str:
|
async def get_openwrt_status(cfg: dict[str, Any]) -> str:
|
||||||
ow_cfg = cfg.get("openwrt", {})
|
ow_cfg = cfg.get("openwrt", {})
|
||||||
host = ow_cfg.get("host")
|
host = ow_cfg.get("host")
|
||||||
@@ -109,6 +152,8 @@ async def get_openwrt_status(cfg: dict[str, Any]) -> str:
|
|||||||
"BatchMode=yes",
|
"BatchMode=yes",
|
||||||
"-o",
|
"-o",
|
||||||
f"ConnectTimeout={timeout_sec}",
|
f"ConnectTimeout={timeout_sec}",
|
||||||
|
"-o",
|
||||||
|
"LogLevel=ERROR",
|
||||||
]
|
]
|
||||||
if not strict:
|
if not strict:
|
||||||
ssh_cmd += ["-o", "StrictHostKeyChecking=no", "-o", "UserKnownHostsFile=/dev/null"]
|
ssh_cmd += ["-o", "StrictHostKeyChecking=no", "-o", "UserKnownHostsFile=/dev/null"]
|
||||||
@@ -117,10 +162,12 @@ async def get_openwrt_status(cfg: dict[str, Any]) -> str:
|
|||||||
ssh_cmd += ["-p", str(port), f"{user}@{host}"]
|
ssh_cmd += ["-p", str(port), f"{user}@{host}"]
|
||||||
|
|
||||||
remote = (
|
remote = (
|
||||||
"ubus call system info; echo __SEP__;"
|
"if ubus call system info >/tmp/ow_sys.json 2>/dev/null; then "
|
||||||
|
"cat /tmp/ow_sys.json; else cat /proc/uptime; echo; cat /proc/loadavg; fi; echo __SEP__;"
|
||||||
"ubus call network.interface.wan status; echo __SEP__;"
|
"ubus call network.interface.wan status; echo __SEP__;"
|
||||||
"ubus call network.wireless status; echo __SEP__;"
|
"ubus call network.wireless status; echo __SEP__;"
|
||||||
"ubus call dhcp ipv4leases"
|
"if ubus call dhcp ipv4leases >/tmp/ow_leases.json 2>/dev/null; then "
|
||||||
|
"cat /tmp/ow_leases.json; else cat /tmp/dhcp.leases; fi"
|
||||||
)
|
)
|
||||||
cmd = ssh_cmd + ["sh", "-c", remote]
|
cmd = ssh_cmd + ["sh", "-c", remote]
|
||||||
rc, out = await run_cmd(cmd, timeout=timeout_sec + 5)
|
rc, out = await run_cmd(cmd, timeout=timeout_sec + 5)
|
||||||
@@ -131,22 +178,40 @@ async def get_openwrt_status(cfg: dict[str, Any]) -> str:
|
|||||||
if len(parts) < 4:
|
if len(parts) < 4:
|
||||||
return "⚠️ OpenWrt response incomplete"
|
return "⚠️ OpenWrt response incomplete"
|
||||||
|
|
||||||
|
sys_info = None
|
||||||
|
wan_status = None
|
||||||
|
wireless = None
|
||||||
|
leases = None
|
||||||
try:
|
try:
|
||||||
sys_info = json.loads(parts[0])
|
sys_info = json.loads(parts[0])
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
sys_info = None
|
||||||
|
try:
|
||||||
wan_status = json.loads(parts[1])
|
wan_status = json.loads(parts[1])
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
wan_status = {}
|
||||||
|
try:
|
||||||
wireless = json.loads(parts[2])
|
wireless = json.loads(parts[2])
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
wireless = {}
|
||||||
|
try:
|
||||||
leases = json.loads(parts[3])
|
leases = json.loads(parts[3])
|
||||||
except json.JSONDecodeError:
|
except json.JSONDecodeError:
|
||||||
return "⚠️ OpenWrt response parse error"
|
leases = None
|
||||||
|
|
||||||
uptime = _format_uptime(sys_info.get("uptime") if isinstance(sys_info, dict) else None)
|
if isinstance(sys_info, dict):
|
||||||
load = _format_load(sys_info.get("load") if isinstance(sys_info, dict) else None)
|
uptime_raw = sys_info.get("uptime")
|
||||||
|
load_raw = sys_info.get("load")
|
||||||
|
else:
|
||||||
|
uptime_raw, load_raw = _parse_proc_fallback(parts[0])
|
||||||
|
uptime = _format_uptime(uptime_raw)
|
||||||
|
load = _format_load(load_raw)
|
||||||
wan_ip = _extract_wan_ip(wan_status) or "unknown"
|
wan_ip = _extract_wan_ip(wan_status) or "unknown"
|
||||||
wan_up = wan_status.get("up") if isinstance(wan_status, dict) else None
|
wan_up = wan_status.get("up") if isinstance(wan_status, dict) else None
|
||||||
wan_state = "up" if wan_up else "down"
|
wan_state = "up" if wan_up else "down"
|
||||||
|
|
||||||
wifi_clients = _extract_wifi_clients(wireless)
|
wifi_clients = _extract_wifi_clients(wireless)
|
||||||
leases_list = _extract_leases(leases)
|
leases_list = _extract_leases(leases) if leases else _parse_leases_fallback(parts[3])
|
||||||
|
|
||||||
lines = [
|
lines = [
|
||||||
"📡 OpenWrt",
|
"📡 OpenWrt",
|
||||||
|
|||||||
Reference in New Issue
Block a user