diff --git a/config.yaml.example b/config.yaml.example index a9d78b0..68f0539 100644 --- a/config.yaml.example +++ b/config.yaml.example @@ -166,11 +166,13 @@ identities: # node_name: "RepeaterCompanion" # tcp_port: 5000 # bind_address: "0.0.0.0" + # tcp_timeout: 120 # seconds; default 120 when omitted; 0 = disable (no timeout) # - name: "BotCompanion" # identity_key: "another_companion_identity_key_hex" # settings: # node_name: "meshcore-bot" # tcp_port: 5001 + # tcp_timeout: 120 # seconds; default 120 when omitted; 0 = disable (no timeout) # Radio hardware type # Supported: diff --git a/repeater/companion/frame_server.py b/repeater/companion/frame_server.py index 3af96d0..0d528ba 100644 --- a/repeater/companion/frame_server.py +++ b/repeater/companion/frame_server.py @@ -33,6 +33,7 @@ class CompanionFrameServer(_BaseFrameServer): companion_hash: str, port: int = 5000, bind_address: str = "0.0.0.0", + client_idle_timeout_sec: Optional[int] = 120, sqlite_handler=None, local_hash: Optional[int] = None, stats_getter=None, @@ -43,6 +44,7 @@ class CompanionFrameServer(_BaseFrameServer): companion_hash=companion_hash, port=port, bind_address=bind_address, + client_idle_timeout_sec=client_idle_timeout_sec, device_model="pyMC-Repeater-Companion", device_version=None, # use FIRMWARE_VER_CODE from pyMC_core build_date="13 Feb 2026", diff --git a/repeater/main.py b/repeater/main.py index 1450703..83ae8ec 100644 --- a/repeater/main.py +++ b/repeater/main.py @@ -432,6 +432,8 @@ class RepeaterDaemon: node_name = settings.get("node_name", name) tcp_port = settings.get("tcp_port", 5000) bind_address = settings.get("bind_address", "0.0.0.0") + tcp_timeout_raw = settings.get("tcp_timeout", 120) + client_idle_timeout_sec = None if tcp_timeout_raw == 0 else int(tcp_timeout_raw) def _make_sync_node_name_to_config(companion_name: str): """Return a callback that syncs node_name to config for this companion (binds name at creation).""" @@ -525,6 +527,7 @@ class RepeaterDaemon: companion_hash=companion_hash_str, port=tcp_port, bind_address=bind_address, + client_idle_timeout_sec=client_idle_timeout_sec, sqlite_handler=sqlite_handler, local_hash=self.local_hash, stats_getter=self._get_companion_stats, @@ -544,7 +547,7 @@ class RepeaterDaemon: logger.info( f"Loaded companion '{name}': hash=0x{companion_hash:02x}, " - f"port={tcp_port}, bind={bind_address}" + f"port={tcp_port}, bind={bind_address}, client_idle_timeout_sec={client_idle_timeout_sec}" ) except Exception as e: @@ -609,6 +612,8 @@ class RepeaterDaemon: node_name = settings.get("node_name", name) tcp_port = settings.get("tcp_port", 5000) bind_address = settings.get("bind_address", "0.0.0.0") + tcp_timeout_raw = settings.get("tcp_timeout", 120) + client_idle_timeout_sec = None if tcp_timeout_raw == 0 else int(tcp_timeout_raw) bridge = RepeaterCompanionBridge( identity=identity, @@ -675,6 +680,7 @@ class RepeaterDaemon: companion_hash=companion_hash_str, port=tcp_port, bind_address=bind_address, + client_idle_timeout_sec=client_idle_timeout_sec, sqlite_handler=sqlite_handler, local_hash=self.local_hash, stats_getter=self._get_companion_stats, @@ -694,7 +700,7 @@ class RepeaterDaemon: logger.info( f"Hot-reload: Loaded companion '{name}': hash=0x{companion_hash:02x}, " - f"port={tcp_port}, bind={bind_address}" + f"port={tcp_port}, bind={bind_address}, client_idle_timeout_sec={client_idle_timeout_sec}" ) async def _on_raw_rx_for_companions(self, data: bytes, rssi: int, snr: float) -> None: diff --git a/repeater/web/api_endpoints.py b/repeater/web/api_endpoints.py index 54999e4..71be4d7 100644 --- a/repeater/web/api_endpoints.py +++ b/repeater/web/api_endpoints.py @@ -2411,6 +2411,8 @@ class APIEndpoints: "tcp_port": settings.get("tcp_port", 5000), "bind_address": settings.get("bind_address", "0.0.0.0"), } + if "tcp_timeout" in settings: + comp_settings["tcp_timeout"] = settings["tcp_timeout"] new_identity = { "name": name, "identity_key": identity_key, @@ -2609,7 +2611,7 @@ class APIEndpoints: identity["settings"] = {} # Only allow companion settings for k, v in data["settings"].items(): - if k in ("node_name", "tcp_port", "bind_address"): + if k in ("node_name", "tcp_port", "bind_address", "tcp_timeout"): identity["settings"][k] = v companions[identity_index] = identity