summaryrefslogtreecommitdiffstats
path: root/packages
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-08-30 22:36:56 +0200
committerChristophe Besson <cbesson@gmail.com>2026-08-30 22:36:56 +0200
commit2d6c276734fd19f80edf84cdb95f91a929df6365 (patch)
tree41a697eb9c048218e0d800cbcb7fa39f4ede2b1d /packages
parent07e6e4271ea3a45e9cd364eb6ec05801a653d9e8 (diff)
downloadmeshbay-2d6c276734fd19f80edf84cdb95f91a929df6365.tar.gz
feat(ui): configurable ICE interfaces in the Node page
The ice_interfaces setting (auto-exclude vs explicit whitelist) is now editable from the Node page, persisted via the settings API and roster, and hot-swapped at runtime by re-installing the aioice filter. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'packages')
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/de.js11
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/en.js11
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/es.js11
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js11
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/it.js11
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js11
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js11
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js11
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js11
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js11
-rw-r--r--packages/meshbay-hub/src/meshbay_hub/static/node-page.js81
-rw-r--r--packages/meshbay-node/src/meshbay_node/daemon.py1
-rw-r--r--packages/meshbay-node/src/meshbay_node/ops.py17
-rw-r--r--packages/meshbay-node/src/meshbay_node/roster.py22
14 files changed, 217 insertions, 14 deletions
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js
index 604be3c..b61d93c 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/de.js
@@ -757,4 +757,15 @@ export default {
'node.stun_empty': 'No STUN servers configured. NAT traversal will not work.',
'node.stun_duplicate': 'This server is already in the list.',
'node.stun_invalid': 'STUN URL must start with stun:',
+ 'node.ice_interfaces': 'ICE Interfaces',
+ 'node.ice_auto_hint': 'Auto mode — virtual and VPN interfaces (Tailscale, Docker, libvirt, etc.) are excluded automatically.',
+ 'node.ice_manual_hint': 'Manual mode — only the listed interfaces are used for ICE candidate gathering.',
+ 'node.ice_add': 'Add',
+ 'node.ice_add_placeholder': 'e.g. eth0, wlp0s20f3',
+ 'node.ice_remove': 'Remove',
+ 'node.ice_save': 'Save',
+ 'node.ice_saving': 'Saving…',
+ 'node.ice_saved': 'ICE interfaces saved.',
+ 'node.ice_reset_auto': 'Switch to auto',
+ 'node.ice_duplicate': 'This interface is already in the list.',
};
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js
index a58619e..851911c 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/en.js
@@ -736,4 +736,15 @@ export default {
'node.stun_empty': 'No STUN servers configured. NAT traversal will not work.',
'node.stun_duplicate': 'This server is already in the list.',
'node.stun_invalid': 'STUN URL must start with stun:',
+ 'node.ice_interfaces': 'ICE Interfaces',
+ 'node.ice_auto_hint': 'Auto mode — virtual and VPN interfaces (Tailscale, Docker, libvirt, etc.) are excluded automatically.',
+ 'node.ice_manual_hint': 'Manual mode — only the listed interfaces are used for ICE candidate gathering.',
+ 'node.ice_add': 'Add',
+ 'node.ice_add_placeholder': 'e.g. eth0, wlp0s20f3',
+ 'node.ice_remove': 'Remove',
+ 'node.ice_save': 'Save',
+ 'node.ice_saving': 'Saving…',
+ 'node.ice_saved': 'ICE interfaces saved.',
+ 'node.ice_reset_auto': 'Switch to auto',
+ 'node.ice_duplicate': 'This interface is already in the list.',
};
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js
index bcb0b93..84af4cd 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/es.js
@@ -753,4 +753,15 @@ export default {
'node.stun_empty': 'No STUN servers configured. NAT traversal will not work.',
'node.stun_duplicate': 'This server is already in the list.',
'node.stun_invalid': 'STUN URL must start with stun:',
+ 'node.ice_interfaces': 'ICE Interfaces',
+ 'node.ice_auto_hint': 'Auto mode — virtual and VPN interfaces (Tailscale, Docker, libvirt, etc.) are excluded automatically.',
+ 'node.ice_manual_hint': 'Manual mode — only the listed interfaces are used for ICE candidate gathering.',
+ 'node.ice_add': 'Add',
+ 'node.ice_add_placeholder': 'e.g. eth0, wlp0s20f3',
+ 'node.ice_remove': 'Remove',
+ 'node.ice_save': 'Save',
+ 'node.ice_saving': 'Saving…',
+ 'node.ice_saved': 'ICE interfaces saved.',
+ 'node.ice_reset_auto': 'Switch to auto',
+ 'node.ice_duplicate': 'This interface is already in the list.',
};
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js
index 2e3e4d6..e540b4b 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/fr.js
@@ -769,4 +769,15 @@ export default {
'node.stun_empty': 'No STUN servers configured. NAT traversal will not work.',
'node.stun_duplicate': 'This server is already in the list.',
'node.stun_invalid': 'STUN URL must start with stun:',
+ 'node.ice_interfaces': 'ICE Interfaces',
+ 'node.ice_auto_hint': 'Auto mode — virtual and VPN interfaces (Tailscale, Docker, libvirt, etc.) are excluded automatically.',
+ 'node.ice_manual_hint': 'Manual mode — only the listed interfaces are used for ICE candidate gathering.',
+ 'node.ice_add': 'Add',
+ 'node.ice_add_placeholder': 'e.g. eth0, wlp0s20f3',
+ 'node.ice_remove': 'Remove',
+ 'node.ice_save': 'Save',
+ 'node.ice_saving': 'Saving…',
+ 'node.ice_saved': 'ICE interfaces saved.',
+ 'node.ice_reset_auto': 'Switch to auto',
+ 'node.ice_duplicate': 'This interface is already in the list.',
};
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js
index dc1d16f..b009460 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/it.js
@@ -767,4 +767,15 @@ export default {
'node.stun_empty': 'No STUN servers configured. NAT traversal will not work.',
'node.stun_duplicate': 'This server is already in the list.',
'node.stun_invalid': 'STUN URL must start with stun:',
+ 'node.ice_interfaces': 'ICE Interfaces',
+ 'node.ice_auto_hint': 'Auto mode — virtual and VPN interfaces (Tailscale, Docker, libvirt, etc.) are excluded automatically.',
+ 'node.ice_manual_hint': 'Manual mode — only the listed interfaces are used for ICE candidate gathering.',
+ 'node.ice_add': 'Add',
+ 'node.ice_add_placeholder': 'e.g. eth0, wlp0s20f3',
+ 'node.ice_remove': 'Remove',
+ 'node.ice_save': 'Save',
+ 'node.ice_saving': 'Saving…',
+ 'node.ice_saved': 'ICE interfaces saved.',
+ 'node.ice_reset_auto': 'Switch to auto',
+ 'node.ice_duplicate': 'This interface is already in the list.',
};
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js
index 90a5f24..9b317a1 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/ja.js
@@ -751,4 +751,15 @@ export default {
'node.stun_empty': 'No STUN servers configured. NAT traversal will not work.',
'node.stun_duplicate': 'This server is already in the list.',
'node.stun_invalid': 'STUN URL must start with stun:',
+ 'node.ice_interfaces': 'ICE Interfaces',
+ 'node.ice_auto_hint': 'Auto mode — virtual and VPN interfaces (Tailscale, Docker, libvirt, etc.) are excluded automatically.',
+ 'node.ice_manual_hint': 'Manual mode — only the listed interfaces are used for ICE candidate gathering.',
+ 'node.ice_add': 'Add',
+ 'node.ice_add_placeholder': 'e.g. eth0, wlp0s20f3',
+ 'node.ice_remove': 'Remove',
+ 'node.ice_save': 'Save',
+ 'node.ice_saving': 'Saving…',
+ 'node.ice_saved': 'ICE interfaces saved.',
+ 'node.ice_reset_auto': 'Switch to auto',
+ 'node.ice_duplicate': 'This interface is already in the list.',
};
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js
index 3347087..0436a31 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/nl.js
@@ -769,4 +769,15 @@ export default {
'node.stun_empty': 'No STUN servers configured. NAT traversal will not work.',
'node.stun_duplicate': 'This server is already in the list.',
'node.stun_invalid': 'STUN URL must start with stun:',
+ 'node.ice_interfaces': 'ICE Interfaces',
+ 'node.ice_auto_hint': 'Auto mode — virtual and VPN interfaces (Tailscale, Docker, libvirt, etc.) are excluded automatically.',
+ 'node.ice_manual_hint': 'Manual mode — only the listed interfaces are used for ICE candidate gathering.',
+ 'node.ice_add': 'Add',
+ 'node.ice_add_placeholder': 'e.g. eth0, wlp0s20f3',
+ 'node.ice_remove': 'Remove',
+ 'node.ice_save': 'Save',
+ 'node.ice_saving': 'Saving…',
+ 'node.ice_saved': 'ICE interfaces saved.',
+ 'node.ice_reset_auto': 'Switch to auto',
+ 'node.ice_duplicate': 'This interface is already in the list.',
};
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js
index 499a54f..391b8cd 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/pl.js
@@ -796,4 +796,15 @@ export default {
'node.stun_empty': 'No STUN servers configured. NAT traversal will not work.',
'node.stun_duplicate': 'This server is already in the list.',
'node.stun_invalid': 'STUN URL must start with stun:',
+ 'node.ice_interfaces': 'ICE Interfaces',
+ 'node.ice_auto_hint': 'Auto mode — virtual and VPN interfaces (Tailscale, Docker, libvirt, etc.) are excluded automatically.',
+ 'node.ice_manual_hint': 'Manual mode — only the listed interfaces are used for ICE candidate gathering.',
+ 'node.ice_add': 'Add',
+ 'node.ice_add_placeholder': 'e.g. eth0, wlp0s20f3',
+ 'node.ice_remove': 'Remove',
+ 'node.ice_save': 'Save',
+ 'node.ice_saving': 'Saving…',
+ 'node.ice_saved': 'ICE interfaces saved.',
+ 'node.ice_reset_auto': 'Switch to auto',
+ 'node.ice_duplicate': 'This interface is already in the list.',
};
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js
index 03a9f6e..16e0559 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/pt-BR.js
@@ -754,4 +754,15 @@ export default {
'node.stun_empty': 'No STUN servers configured. NAT traversal will not work.',
'node.stun_duplicate': 'This server is already in the list.',
'node.stun_invalid': 'STUN URL must start with stun:',
+ 'node.ice_interfaces': 'ICE Interfaces',
+ 'node.ice_auto_hint': 'Auto mode — virtual and VPN interfaces (Tailscale, Docker, libvirt, etc.) are excluded automatically.',
+ 'node.ice_manual_hint': 'Manual mode — only the listed interfaces are used for ICE candidate gathering.',
+ 'node.ice_add': 'Add',
+ 'node.ice_add_placeholder': 'e.g. eth0, wlp0s20f3',
+ 'node.ice_remove': 'Remove',
+ 'node.ice_save': 'Save',
+ 'node.ice_saving': 'Saving…',
+ 'node.ice_saved': 'ICE interfaces saved.',
+ 'node.ice_reset_auto': 'Switch to auto',
+ 'node.ice_duplicate': 'This interface is already in the list.',
};
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js b/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js
index 8004868..edd9edc 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/locales/zh-CN.js
@@ -738,4 +738,15 @@ export default {
'node.stun_empty': 'No STUN servers configured. NAT traversal will not work.',
'node.stun_duplicate': 'This server is already in the list.',
'node.stun_invalid': 'STUN URL must start with stun:',
+ 'node.ice_interfaces': 'ICE Interfaces',
+ 'node.ice_auto_hint': 'Auto mode — virtual and VPN interfaces (Tailscale, Docker, libvirt, etc.) are excluded automatically.',
+ 'node.ice_manual_hint': 'Manual mode — only the listed interfaces are used for ICE candidate gathering.',
+ 'node.ice_add': 'Add',
+ 'node.ice_add_placeholder': 'e.g. eth0, wlp0s20f3',
+ 'node.ice_remove': 'Remove',
+ 'node.ice_save': 'Save',
+ 'node.ice_saving': 'Saving…',
+ 'node.ice_saved': 'ICE interfaces saved.',
+ 'node.ice_reset_auto': 'Switch to auto',
+ 'node.ice_duplicate': 'This interface is already in the list.',
};
diff --git a/packages/meshbay-hub/src/meshbay_hub/static/node-page.js b/packages/meshbay-hub/src/meshbay_hub/static/node-page.js
index 87a9815..82fc56e 100644
--- a/packages/meshbay-hub/src/meshbay_hub/static/node-page.js
+++ b/packages/meshbay-hub/src/meshbay_hub/static/node-page.js
@@ -105,6 +105,9 @@ export function NodePage({ groups }) {
const [editStun, setEditStun] = useState(null);
const [savingStun, setSavingStun] = useState(false);
const [stunInput, setStunInput] = useState('');
+ const [editIce, setEditIce] = useState(null);
+ const [savingIce, setSavingIce] = useState(false);
+ const [iceInput, setIceInput] = useState('');
const [operatorPaired, setOperatorPaired] = useState(false);
const [pairBusy, setPairBusy] = useState(false);
const [pairStatus, setPairStatus] = useState('');
@@ -135,6 +138,7 @@ export function NodePage({ groups }) {
useEffect(() => {
if (nodeSettings && !editSettings) setEditSettings({ ...nodeSettings });
if (nodeSettings && !editStun) setEditStun([...(nodeSettings.stun_servers || [])]);
+ if (nodeSettings && !editIce) setEditIce([...(nodeSettings.ice_interfaces || [])]);
}, [nodeSettings]);
const refresh = useCallback(async () => {
@@ -350,6 +354,42 @@ export function NodePage({ groups }) {
setActionMsg('');
}, []);
+ const saveIce = useCallback(async () => {
+ if (!editIce) return;
+ setSavingIce(true);
+ setActionMsg('');
+ try {
+ await nodeCall('PUT', '/api/node-settings', { ice_interfaces: editIce });
+ setNodeSettings(s => s ? { ...s, ice_interfaces: [...editIce] } : s);
+ setActionMsg(t('node.ice_saved'));
+ } catch (err) {
+ setActionMsg(platform.bridgeMessage(err));
+ } finally {
+ setSavingIce(false);
+ }
+ }, [editIce]);
+
+ const addIceInterface = useCallback(() => {
+ const name = iceInput.trim();
+ if (!name) return;
+ if (editIce && editIce.includes(name)) {
+ setActionMsg(t('node.ice_duplicate'));
+ return;
+ }
+ setEditIce(s => [...(s || []), name]);
+ setIceInput('');
+ setActionMsg('');
+ }, [iceInput, editIce]);
+
+ const removeIceInterface = useCallback((idx) => {
+ setEditIce(s => s.filter((_, i) => i !== idx));
+ }, []);
+
+ const resetIceAuto = useCallback(() => {
+ setEditIce([]);
+ setActionMsg('');
+ }, []);
+
const doPairOperator = useCallback(async () => {
setPairBusy(true);
setPairStatus('');
@@ -663,6 +703,47 @@ export function NodePage({ groups }) {
</div>
</div>
`}
+
+ ${editIce && html`
+ <div class="node-group">
+ <span class="settings-heading">${t('node.ice_interfaces')}</span>
+ <p class="node-hint">${editIce.length === 0
+ ? t('node.ice_auto_hint')
+ : t('node.ice_manual_hint')}</p>
+ ${editIce.length > 0 && html`
+ <div class="stun-server-list">
+ ${editIce.map((name, idx) => html`
+ <div class="stun-server-entry" key=${name + idx}>
+ <span class="stun-server-url">${name}</span>
+ <div class="stun-server-actions">
+ <button class="btn btn-small btn-danger btn-icon"
+ onClick=${() => removeIceInterface(idx)}
+ title=${t('node.ice_remove')}>✕</button>
+ </div>
+ </div>
+ `)}
+ </div>
+ `}
+ <div class="stun-add-row">
+ <input type="text" placeholder=${t('node.ice_add_placeholder')}
+ value=${iceInput}
+ onInput=${e => setIceInput(e.target.value)}
+ onKeyDown=${e => { if (e.key === 'Enter') addIceInterface(); }} />
+ <button class="btn btn-small btn-secondary" onClick=${addIceInterface}>
+ ${t('node.ice_add')}</button>
+ </div>
+ <div class="node-settings-actions">
+ <button class="btn btn-primary btn-small" disabled=${savingIce || busy}
+ onClick=${saveIce}>
+ ${savingIce ? t('node.ice_saving') : t('node.ice_save')}</button>
+ ${editIce.length > 0 && html`
+ <button class="btn btn-small btn-secondary" disabled=${savingIce || busy}
+ onClick=${resetIceAuto}>
+ ${t('node.ice_reset_auto')}</button>
+ `}
+ </div>
+ </div>
+ `}
</div>
`;
}
diff --git a/packages/meshbay-node/src/meshbay_node/daemon.py b/packages/meshbay-node/src/meshbay_node/daemon.py
index 51f78b7..5c6d86c 100644
--- a/packages/meshbay-node/src/meshbay_node/daemon.py
+++ b/packages/meshbay-node/src/meshbay_node/daemon.py
@@ -278,6 +278,7 @@ class NodeDaemon:
"max_concurrent_streams": nd.max_concurrent_streams,
"transcode_incompatible_video": nd.transcode_incompatible_video,
"stun_servers": nd.stun_servers if nd.stun_servers else list(DEFAULT_STUN_SERVERS),
+ "ice_interfaces": nd.ice_interfaces,
}
effective = await self._roster.node_settings(defaults)
for k, v in effective.items():
diff --git a/packages/meshbay-node/src/meshbay_node/ops.py b/packages/meshbay-node/src/meshbay_node/ops.py
index 2ab6753..07579cd 100644
--- a/packages/meshbay-node/src/meshbay_node/ops.py
+++ b/packages/meshbay-node/src/meshbay_node/ops.py
@@ -341,6 +341,7 @@ async def list_groups(state: dict) -> dict:
"max_concurrent_streams": nd.max_concurrent_streams if nd else 8,
"transcode_incompatible_video": nd.transcode_incompatible_video if nd else True,
"stun_servers": nd.stun_servers if nd and nd.stun_servers else list(DEFAULT_STUN_SERVERS),
+ "ice_interfaces": nd.ice_interfaces if nd else [],
}
if roster:
settings = await roster.node_settings(defaults)
@@ -799,6 +800,7 @@ async def get_node_settings(state: dict) -> dict:
"max_concurrent_streams": nd.max_concurrent_streams,
"transcode_incompatible_video": nd.transcode_incompatible_video,
"stun_servers": nd.stun_servers if nd.stun_servers else list(DEFAULT_STUN_SERVERS),
+ "ice_interfaces": nd.ice_interfaces,
}
if roster:
return await roster.node_settings(defaults)
@@ -817,7 +819,8 @@ async def set_node_settings(state: dict, settings: dict) -> dict:
"device_request_ttl_minutes": ("int", roster.SETTING_DEVICE_TTL),
"max_concurrent_streams": ("int", roster.SETTING_MAX_STREAMS),
"transcode_incompatible_video": ("bool", roster.SETTING_TRANSCODE),
- "stun_servers": ("list", roster.SETTING_STUN_SERVERS),
+ "stun_servers": ("stun_list", roster.SETTING_STUN_SERVERS),
+ "ice_interfaces": ("list", roster.SETTING_ICE_INTERFACES),
}
set_by = state.get("node_user_id", "")
@@ -841,14 +844,15 @@ async def set_node_settings(state: dict, settings: dict) -> dict:
setattr(nd, key, v)
await roster.set_node_setting(setting_key, "1" if v else "0", set_by)
updated[key] = v
- elif kind == "list":
+ elif kind in ("list", "stun_list"):
import json as _json
if not isinstance(value, list):
raise OpError(f"{key} must be a list")
v = [str(s) for s in value]
- for s in v:
- if not s.startswith("stun:"):
- raise OpError(f"Invalid STUN server: {s} (must start with stun:)")
+ if kind == "stun_list":
+ for s in v:
+ if not s.startswith("stun:"):
+ raise OpError(f"Invalid STUN server: {s} (must start with stun:)")
setattr(nd, key, v)
await roster.set_node_setting(setting_key, _json.dumps(v), set_by)
updated[key] = v
@@ -863,6 +867,9 @@ async def set_node_settings(state: dict, settings: dict) -> dict:
webrtc = state.get("webrtc")
if webrtc and hasattr(webrtc, '_stun'):
webrtc._stun = updated["stun_servers"]
+ if "ice_interfaces" in updated:
+ from meshbay_node.transport.ice_filter import install as install_ice_filter
+ install_ice_filter(updated["ice_interfaces"] or None)
log.info("Node settings updated: %s", updated)
return {"updated": updated}
diff --git a/packages/meshbay-node/src/meshbay_node/roster.py b/packages/meshbay-node/src/meshbay_node/roster.py
index 5bdb5ee..5af2b55 100644
--- a/packages/meshbay-node/src/meshbay_node/roster.py
+++ b/packages/meshbay-node/src/meshbay_node/roster.py
@@ -765,6 +765,7 @@ class Roster:
SETTING_MAX_STREAMS = "max_concurrent_streams"
SETTING_TRANSCODE = "transcode_incompatible_video"
SETTING_STUN_SERVERS = "stun_servers"
+ SETTING_ICE_INTERFACES = "ice_interfaces"
async def node_settings(self, defaults: dict) -> dict:
"""Current effective settings: roster override if present, else config default."""
@@ -785,15 +786,18 @@ class Roster:
result[key] = int(stored)
else:
result[key] = defaults.get(key)
- stored = await self.get_setting(self.NODE_WIDE_GROUP_ID,
- self.SETTING_STUN_SERVERS)
- if stored is not None:
- try:
- result["stun_servers"] = _json.loads(stored)
- except (ValueError, TypeError):
- result["stun_servers"] = defaults.get("stun_servers", [])
- else:
- result["stun_servers"] = defaults.get("stun_servers", [])
+ for list_key, setting in [
+ ("stun_servers", self.SETTING_STUN_SERVERS),
+ ("ice_interfaces", self.SETTING_ICE_INTERFACES),
+ ]:
+ stored = await self.get_setting(self.NODE_WIDE_GROUP_ID, setting)
+ if stored is not None:
+ try:
+ result[list_key] = _json.loads(stored)
+ except (ValueError, TypeError):
+ result[list_key] = defaults.get(list_key, [])
+ else:
+ result[list_key] = defaults.get(list_key, [])
return result
async def set_node_setting(self, key: str, value: str,