diff --git a/netx_api/oclaw_alarm_forwarder.py b/netx_api/oclaw_alarm_forwarder.py index 164806b..2739115 100644 --- a/netx_api/oclaw_alarm_forwarder.py +++ b/netx_api/oclaw_alarm_forwarder.py @@ -12,9 +12,33 @@ from typing import Any import websocket from .config import settings +from .runtime_task_messages import fwd_state_code _log = logging.getLogger("netx.oclaw.alarm_forwarder") + +def _normalize_bridge_error(exc: BaseException | str) -> str: + """Map low-level WS errors to stable fwd:* codes for UI i18n.""" + raw = str(exc or "").strip() + low = raw.lower() + name = type(exc).__name__ if isinstance(exc, BaseException) else "" + if ( + "10061" in raw + or "actively refused" in low + or "积极拒绝" in raw + or "connection refused" in low + or name == "ConnectionRefusedError" + ): + return fwd_state_code("connect_refused") + if "timed out" in low or "timeout" in low or name in {"TimeoutError", "socket.timeout"}: + return fwd_state_code("connect_timeout") + if "auth failed" in low or "auth-fail" in low or "invalid_token" in low: + return fwd_state_code("auth_failed") + if raw: + return raw[:200] + return fwd_state_code("disconnected") + + _OUTBOUND_Q: "queue.Queue[dict[str, Any]] | None" = None _Q_LOCK = threading.Lock() _STOP_EVENT = threading.Event() @@ -274,8 +298,8 @@ def _run_loop() -> None: _outbound_q().task_done() except Exception as exc: _CONNECTED.clear() - err = str(exc)[:200] - _log.warning("oclaw netx-bridge disconnected: %s", err) + err = _normalize_bridge_error(exc) + _log.warning("oclaw netx-bridge disconnected: %s", str(exc)[:200]) _notify_status(err) time.sleep(backoff_s) backoff_s = min(backoff_s * 1.5, 60.0) diff --git a/web/src/i18n/en.ts b/web/src/i18n/en.ts index 3e6b254..d07f4f4 100644 --- a/web/src/i18n/en.ts +++ b/web/src/i18n/en.ts @@ -1081,6 +1081,10 @@ const en = { disabled: "Disabled", connecting: "Connecting", connected: "Connected", + connect_refused: "OClaw gateway down or port 8787 refused", + connect_timeout: "Timed out connecting to OClaw gateway", + auth_failed: "OClaw netx-bridge auth failed (check shared token)", + disconnected: "OClaw WSS disconnected", }, runtimeTask: { token_keepalive: "UME token keepalive", diff --git a/web/src/i18n/zh.ts b/web/src/i18n/zh.ts index eb5bc49..75b685d 100644 --- a/web/src/i18n/zh.ts +++ b/web/src/i18n/zh.ts @@ -1074,6 +1074,10 @@ const zh = { disabled: "未启用", connecting: "连接中", connected: "已连接", + connect_refused: "OClaw 网关未启动或 8787 拒绝连接", + connect_timeout: "连接 OClaw 网关超时", + auth_failed: "OClaw netx-bridge 鉴权失败(检查共享 token)", + disconnected: "OClaw WSS 已断开", }, runtimeTask: { token_keepalive: "UME Token 保活",