summaryrefslogtreecommitdiffstats
path: root/packages/meshbay-node/src/meshbay_node/ops.py
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-node/src/meshbay_node/ops.py')
-rw-r--r--packages/meshbay-node/src/meshbay_node/ops.py55
1 files changed, 46 insertions, 9 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/ops.py b/packages/meshbay-node/src/meshbay_node/ops.py
index d1314f0..2ab6753 100644
--- a/packages/meshbay-node/src/meshbay_node/ops.py
+++ b/packages/meshbay-node/src/meshbay_node/ops.py
@@ -332,6 +332,7 @@ async def list_groups(state: dict) -> dict:
members = await roster.list_members()
has_operator = any(m["role"] == "operator" and m["status"] == "active"
for m in members)
+ from meshbay_node.config import DEFAULT_STUN_SERVERS
nd = config.node if config else None
defaults = {
"invite_ttl_hours": nd.invite_ttl_hours if nd else 168,
@@ -339,6 +340,7 @@ async def list_groups(state: dict) -> dict:
"device_request_ttl_minutes": nd.device_request_ttl_minutes if nd else 60,
"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),
}
if roster:
settings = await roster.node_settings(defaults)
@@ -511,6 +513,14 @@ def _update_node_toml(conf_path: Path, updates: dict) -> None:
node_start = len(lines) - 1
node_end = len(lines)
+ def _format_value(key, value):
+ if isinstance(value, bool):
+ return f"{key} = {'true' if value else 'false'}"
+ if isinstance(value, list):
+ items = ", ".join(f'"{v}"' for v in value)
+ return f"{key} = [{items}]"
+ return f"{key} = {value}"
+
remaining = dict(updates)
for i in range(node_start + 1, node_end):
for key in list(remaining):
@@ -518,18 +528,11 @@ def _update_node_toml(conf_path: Path, updates: dict) -> None:
r'^(\s*#?\s*)' + re.escape(key) + r'\s*=\s*.*$')
if pattern.match(lines[i]):
value = remaining.pop(key)
- if isinstance(value, bool):
- lines[i] = f"{key} = {'true' if value else 'false'}"
- else:
- lines[i] = f"{key} = {value}"
+ lines[i] = _format_value(key, value)
break
for key, value in remaining.items():
- if isinstance(value, bool):
- insert_line = f"{key} = {'true' if value else 'false'}"
- else:
- insert_line = f"{key} = {value}"
- lines.insert(node_end, insert_line)
+ lines.insert(node_end, _format_value(key, value))
node_end += 1
conf_path.write_text("\n".join(lines))
@@ -783,6 +786,24 @@ async def set_member_upload(state: dict, group_id: str, allowed: bool) -> dict:
# ── Node settings ────────────────────────────────────────────────────────────
+async def get_node_settings(state: dict) -> dict:
+ """Return current effective node settings."""
+ from meshbay_node.config import DEFAULT_STUN_SERVERS
+ roster = _roster(state)
+ config = _config(state)
+ nd = config.node
+ defaults = {
+ "invite_ttl_hours": nd.invite_ttl_hours,
+ "pair_ttl_hours": nd.pair_ttl_hours,
+ "device_request_ttl_minutes": nd.device_request_ttl_minutes,
+ "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),
+ }
+ if roster:
+ return await roster.node_settings(defaults)
+ return defaults
+
async def set_node_settings(state: dict, settings: dict) -> dict:
"""Update node-level daemon settings. Writes to both roster.db and node.toml."""
roster = _roster(state)
@@ -796,6 +817,7 @@ 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),
}
set_by = state.get("node_user_id", "")
@@ -819,6 +841,17 @@ 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":
+ 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:)")
+ setattr(nd, key, v)
+ await roster.set_node_setting(setting_key, _json.dumps(v), set_by)
+ updated[key] = v
if updated:
_update_node_toml(conf_path, updated)
@@ -826,6 +859,10 @@ async def set_node_settings(state: dict, settings: dict) -> dict:
webrtc = state.get("webrtc")
if webrtc and hasattr(webrtc, '_stream_sem'):
webrtc._stream_sem = asyncio.Semaphore(updated["max_concurrent_streams"])
+ if "stun_servers" in updated:
+ webrtc = state.get("webrtc")
+ if webrtc and hasattr(webrtc, '_stun'):
+ webrtc._stun = updated["stun_servers"]
log.info("Node settings updated: %s", updated)
return {"updated": updated}