feat: bind monitors by base url hash
This commit is contained in:
@@ -82,4 +82,6 @@ aliases exist: `id < slow < fast < sfast`. The table shows `sfast` first, then
|
|||||||
|
|
||||||
When `--status-url` is configured, the status line shows channel monitor
|
When `--status-url` is configured, the status line shows channel monitor
|
||||||
health, and the selected account detail shows the matching monitor status when
|
health, and the selected account detail shows the matching monitor status when
|
||||||
one exists.
|
one exists. Monitor binding first uses the shared `base_url_hash` emitted by
|
||||||
|
the account API and `sub2api-status`; name-token matching remains only as a
|
||||||
|
fallback for older status payloads.
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "shusub2"
|
name = "shusub2"
|
||||||
version = "0.1.2"
|
version = "0.1.3"
|
||||||
description = "Terminal UI for Sub2API account quota and daily usage"
|
description = "Terminal UI for Sub2API account quota and daily usage"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.11"
|
requires-python = ">=3.11"
|
||||||
|
|||||||
@@ -226,6 +226,11 @@ def text_tokens(value: Any) -> set[str]:
|
|||||||
|
|
||||||
|
|
||||||
def matching_monitor(row: dict[str, Any], status_payload: dict[str, Any]) -> dict[str, Any] | None:
|
def matching_monitor(row: dict[str, Any], status_payload: dict[str, Any]) -> dict[str, Any] | None:
|
||||||
|
base_url_hash = str(row.get("base_url_hash") or "").strip()
|
||||||
|
if base_url_hash:
|
||||||
|
for item in monitor_items(status_payload):
|
||||||
|
if str(item.get("base_url_hash") or "").strip() == base_url_hash:
|
||||||
|
return item
|
||||||
account_tokens = text_tokens(row.get("name"))
|
account_tokens = text_tokens(row.get("name"))
|
||||||
if not account_tokens:
|
if not account_tokens:
|
||||||
return None
|
return None
|
||||||
@@ -324,6 +329,7 @@ def normalize_account_rows(payload: dict[str, Any], filter_text: str = "") -> li
|
|||||||
"id": as_int(account.get("id")),
|
"id": as_int(account.get("id")),
|
||||||
"name": str(account.get("name") or ""),
|
"name": str(account.get("name") or ""),
|
||||||
"routing_group": routing_group,
|
"routing_group": routing_group,
|
||||||
|
"base_url_hash": str(account.get("base_url_hash") or ""),
|
||||||
"provider": provider_label(account),
|
"provider": provider_label(account),
|
||||||
"kind": str(account.get("kind") or "unknown"),
|
"kind": str(account.get("kind") or "unknown"),
|
||||||
"kind_label": kind_label(account.get("kind")),
|
"kind_label": kind_label(account.get("kind")),
|
||||||
|
|||||||
@@ -174,6 +174,31 @@ class Sub2APIQuotaTUITests(unittest.TestCase):
|
|||||||
self.assertIn("monitors 5 ok / 0 failed / 1 unknown", mod.monitor_summary(status_payload))
|
self.assertIn("monitors 5 ok / 0 failed / 1 unknown", mod.monitor_summary(status_payload))
|
||||||
self.assertIn("monitor operational 2606ms", mod.monitor_detail(row, status_payload))
|
self.assertIn("monitor operational 2606ms", mod.monitor_detail(row, status_payload))
|
||||||
|
|
||||||
|
def test_monitor_match_prefers_base_url_hash_over_name_tokens(self) -> None:
|
||||||
|
mod = load_module()
|
||||||
|
status_payload = {
|
||||||
|
"channel_monitors": {
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"name": "input responses",
|
||||||
|
"base_url_hash": "wrong-hash",
|
||||||
|
"latest_status": "operational",
|
||||||
|
"latency_ms": 111,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "unrelated responses",
|
||||||
|
"base_url_hash": "right-hash",
|
||||||
|
"latest_status": "degraded",
|
||||||
|
"latency_ms": 222,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
row = {"name": "input 300", "base_url_hash": "right-hash"}
|
||||||
|
|
||||||
|
self.assertEqual(mod.matching_monitor(row, status_payload)["name"], "unrelated responses")
|
||||||
|
self.assertIn("monitor degraded 222ms", mod.monitor_detail(row, status_payload))
|
||||||
|
|
||||||
def test_monitor_error_is_non_blocking_in_once_output(self) -> None:
|
def test_monitor_error_is_non_blocking_in_once_output(self) -> None:
|
||||||
mod = load_module()
|
mod = load_module()
|
||||||
payload = {
|
payload = {
|
||||||
|
|||||||
Reference in New Issue
Block a user