mirror of
https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
synced 2026-05-14 13:26:06 +02:00
Merge pull request #253 from MartinFournier/feature/community-mqtt-websocket-path
Add WebSocket path config for community MQTT
This commit is contained in:
@@ -61,6 +61,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:
|
||||
@@ -363,7 +364,7 @@ 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"] = "/"
|
||||
kwargs["websocket_path"] = (s.community_mqtt_websocket_path or "").strip() or "/"
|
||||
return kwargs
|
||||
|
||||
def _on_connected(self, settings: object) -> tuple[str, str]:
|
||||
|
||||
@@ -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", "/"),
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -1548,6 +1548,24 @@ function MqttCommunityConfigEditor({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{((config.transport as string) || DEFAULT_COMMUNITY_TRANSPORT) === 'websockets' && (
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
||||
<div className="space-y-2">
|
||||
<Label htmlFor="fanout-comm-ws-path">WebSocket Path</Label>
|
||||
<Input
|
||||
id="fanout-comm-ws-path"
|
||||
type="text"
|
||||
placeholder="/"
|
||||
value={(config.websocket_path as string | undefined) ?? ''}
|
||||
onChange={(e) => onChange({ ...config, websocket_path: e.target.value })}
|
||||
/>
|
||||
<p className="text-[0.8125rem] text-muted-foreground">
|
||||
Defaults to <code>/</code> — use <code>/mqtt</code> for brokers that require a path
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<p className="text-[0.8125rem] text-muted-foreground">
|
||||
LetsMesh uses <code>token</code> auth. MeshRank uses <code>none</code>.
|
||||
</p>
|
||||
|
||||
@@ -70,6 +70,7 @@ def _make_community_settings(**overrides) -> SimpleNamespace:
|
||||
"community_mqtt_iata": "",
|
||||
"community_mqtt_email": "",
|
||||
"community_mqtt_token_audience": "mqtt-us-v1.letsmesh.net",
|
||||
"community_mqtt_websocket_path": "/",
|
||||
}
|
||||
defaults.update(overrides)
|
||||
return SimpleNamespace(**defaults)
|
||||
@@ -738,6 +739,44 @@ class TestLwtAndStatusPublish:
|
||||
assert kwargs["tls_context"] is not None
|
||||
assert kwargs["username"] == f"v1_{pubkey_hex}"
|
||||
|
||||
def test_build_client_kwargs_custom_websocket_path(self):
|
||||
pub = CommunityMqttPublisher()
|
||||
private_key, public_key = _make_test_keys()
|
||||
settings = _make_community_settings(
|
||||
community_mqtt_iata="MTL",
|
||||
community_mqtt_websocket_path="/mqtt",
|
||||
)
|
||||
|
||||
with (
|
||||
patch("app.keystore.get_private_key", return_value=private_key),
|
||||
patch("app.keystore.get_public_key", return_value=public_key),
|
||||
patch("app.radio.radio_manager") as mock_radio,
|
||||
):
|
||||
mock_radio.meshcore = None
|
||||
kwargs = pub._build_client_kwargs(settings)
|
||||
|
||||
assert kwargs["websocket_path"] == "/mqtt"
|
||||
|
||||
def test_build_client_kwargs_empty_websocket_path_defaults_to_root(self):
|
||||
pub = CommunityMqttPublisher()
|
||||
private_key, public_key = _make_test_keys()
|
||||
|
||||
for empty_value in ("", " ", None):
|
||||
settings = _make_community_settings(
|
||||
community_mqtt_iata="MTL",
|
||||
community_mqtt_websocket_path=empty_value,
|
||||
)
|
||||
|
||||
with (
|
||||
patch("app.keystore.get_private_key", return_value=private_key),
|
||||
patch("app.keystore.get_public_key", return_value=public_key),
|
||||
patch("app.radio.radio_manager") as mock_radio,
|
||||
):
|
||||
mock_radio.meshcore = None
|
||||
kwargs = pub._build_client_kwargs(settings)
|
||||
|
||||
assert kwargs["websocket_path"] == "/", f"Failed for {empty_value!r}"
|
||||
|
||||
def test_build_client_kwargs_supports_tcp_transport_and_custom_audience(self):
|
||||
pub = CommunityMqttPublisher()
|
||||
private_key, public_key = _make_test_keys()
|
||||
|
||||
Reference in New Issue
Block a user