diff --git a/app/fanout/community_mqtt.py b/app/fanout/community_mqtt.py index 1c8228d..b728971 100644 --- a/app/fanout/community_mqtt.py +++ b/app/fanout/community_mqtt.py @@ -59,6 +59,7 @@ class CommunityMqttSettings(Protocol): community_mqtt_iata: str community_mqtt_email: str community_mqtt_token_audience: str + community_mqtt_websocket_path: str def _base64url_encode(data: bytes) -> str: @@ -361,7 +362,8 @@ class CommunityMqttPublisher(BaseMqttPublisher): kwargs["username"] = s.community_mqtt_username or None kwargs["password"] = s.community_mqtt_password or None if transport == "websockets": - kwargs["websocket_path"] = "/" + ws_path = getattr(s, "community_mqtt_websocket_path", None) + kwargs["websocket_path"] = ws_path.strip() if ws_path and ws_path.strip() else "/" return kwargs def _on_connected(self, settings: object) -> tuple[str, str]: diff --git a/app/fanout/mqtt_community.py b/app/fanout/mqtt_community.py index 9c4dc13..fdd833c 100644 --- a/app/fanout/mqtt_community.py +++ b/app/fanout/mqtt_community.py @@ -62,6 +62,7 @@ def _config_to_settings(config: dict) -> SimpleNamespace: community_mqtt_iata=config.get("iata", ""), community_mqtt_email=config.get("email", ""), community_mqtt_token_audience=config.get("token_audience", ""), + community_mqtt_websocket_path=config.get("websocket_path", "/"), ) diff --git a/frontend/src/components/settings/SettingsFanoutSection.tsx b/frontend/src/components/settings/SettingsFanoutSection.tsx index 3efe9c1..78e89a3 100644 --- a/frontend/src/components/settings/SettingsFanoutSection.tsx +++ b/frontend/src/components/settings/SettingsFanoutSection.tsx @@ -1548,6 +1548,24 @@ function MqttCommunityConfigEditor({ + {((config.transport as string) || DEFAULT_COMMUNITY_TRANSPORT) === 'websockets' && ( +
+ Defaults to / — use /mqtt for brokers that require a path
+
LetsMesh uses token auth. MeshRank uses none.