diff --git a/gateway/platforms/feishu.py b/gateway/platforms/feishu.py index de4d97e647..3048393235 100644 --- a/gateway/platforms/feishu.py +++ b/gateway/platforms/feishu.py @@ -270,6 +270,8 @@ class FeishuAdapterSettings: webhook_host: str webhook_port: int webhook_path: str + ws_reconnect_nonce: int = 30 + ws_reconnect_interval: int = 120 @dataclass @@ -358,6 +360,22 @@ def _strip_markdown_to_plain_text(text: str) -> str: return plain.strip() +def _coerce_non_negative_int(value: Any, default: int) -> int: + try: + parsed = int(value) + except (TypeError, ValueError): + return default + return parsed if parsed >= 0 else default + + +def _coerce_positive_int(value: Any, default: int) -> int: + try: + parsed = int(value) + except (TypeError, ValueError): + return default + return parsed if parsed >= 1 else default + + # --------------------------------------------------------------------------- # Post payload builders and parsers # --------------------------------------------------------------------------- @@ -1040,6 +1058,8 @@ class FeishuAdapter(BasePlatformAdapter): str(extra.get("webhook_path") or os.getenv("FEISHU_WEBHOOK_PATH", _DEFAULT_WEBHOOK_PATH)).strip() or _DEFAULT_WEBHOOK_PATH ), + ws_reconnect_nonce=_coerce_non_negative_int(extra.get("ws_reconnect_nonce"), 30), + ws_reconnect_interval=_coerce_positive_int(extra.get("ws_reconnect_interval"), 120), ) def _apply_settings(self, settings: FeishuAdapterSettings) -> None: @@ -1062,6 +1082,8 @@ class FeishuAdapter(BasePlatformAdapter): self._webhook_host = settings.webhook_host self._webhook_port = settings.webhook_port self._webhook_path = settings.webhook_path + self._ws_reconnect_nonce = settings.ws_reconnect_nonce + self._ws_reconnect_interval = settings.ws_reconnect_interval def _build_event_handler(self) -> Any: if EventDispatcherHandler is None: @@ -3032,6 +3054,11 @@ class FeishuAdapter(BasePlatformAdapter): event_handler=self._event_handler, domain=domain, ) + try: + setattr(self._ws_client, "_reconnect_nonce", self._ws_reconnect_nonce) + setattr(self._ws_client, "_reconnect_interval", self._ws_reconnect_interval) + except Exception: + logger.debug("[Feishu] Failed to override websocket reconnect settings", exc_info=True) self._ws_future = loop.run_in_executor( None, _run_official_feishu_ws_client, diff --git a/tests/gateway/test_feishu.py b/tests/gateway/test_feishu.py index 41f92d60a0..db532ba799 100644 --- a/tests/gateway/test_feishu.py +++ b/tests/gateway/test_feishu.py @@ -283,7 +283,7 @@ class TestFeishuAdapterMessaging(unittest.TestCase): from gateway.platforms.feishu import FeishuAdapter adapter = FeishuAdapter(PlatformConfig()) - ws_client = object() + ws_client = SimpleNamespace() with ( patch("gateway.platforms.feishu.FEISHU_AVAILABLE", True), @@ -367,7 +367,7 @@ class TestFeishuAdapterMessaging(unittest.TestCase): from gateway.platforms.feishu import FeishuAdapter adapter = FeishuAdapter(PlatformConfig()) - ws_client = object() + ws_client = SimpleNamespace() sleeps = [] with ( @@ -561,6 +561,32 @@ class TestAdapterModule(unittest.TestCase): self.assertIn("register_p2_im_message_reaction_deleted_v1", source) self.assertIn("register_p2_card_action_trigger", source) + def test_load_settings_uses_sdk_defaults_for_invalid_ws_reconnect_values(self): + from gateway.platforms.feishu import FeishuAdapter + + settings = FeishuAdapter._load_settings( + { + "ws_reconnect_nonce": -1, + "ws_reconnect_interval": "bad", + } + ) + + self.assertEqual(settings.ws_reconnect_nonce, 30) + self.assertEqual(settings.ws_reconnect_interval, 120) + + def test_load_settings_accepts_custom_ws_reconnect_values(self): + from gateway.platforms.feishu import FeishuAdapter + + settings = FeishuAdapter._load_settings( + { + "ws_reconnect_nonce": 0, + "ws_reconnect_interval": 3, + } + ) + + self.assertEqual(settings.ws_reconnect_nonce, 0) + self.assertEqual(settings.ws_reconnect_interval, 3) + class TestAdapterBehavior(unittest.TestCase): @patch.dict(os.environ, {}, clear=True)