diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-08-29 18:42:43 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-08-29 18:52:53 +0200 |
| commit | 1f8a52484412b48205e5ff6aac506428e2fb77ed (patch) | |
| tree | 5598419ee4caef21f607876de6af2d30d6452191 /packages/meshbay-node/src/meshbay_node/ui/app.py | |
| parent | 8de80b7e19738b716d9973c0b4ba3b42085f7359 (diff) | |
| download | meshbay-1f8a52484412b48205e5ff6aac506428e2fb77ed.tar.gz | |
feat(node): editable node settings in the Node page (D5)
Expose invite_ttl_hours, pair_ttl_hours, device_request_ttl_minutes,
max_concurrent_streams and transcode_incompatible_video in the Node
management panel. Changes are applied immediately via roster.db and
written back to node.toml so they survive a DB wipe. On startup,
roster overrides take precedence over node.toml defaults.
Draft v6 §2.11 documents the design; MNP gains node_settings_set /
node_settings_set_ack for the browser path.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'packages/meshbay-node/src/meshbay_node/ui/app.py')
| -rw-r--r-- | packages/meshbay-node/src/meshbay_node/ui/app.py | 32 |
1 files changed, 32 insertions, 0 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/ui/app.py b/packages/meshbay-node/src/meshbay_node/ui/app.py index 514a143..b25b36a 100644 --- a/packages/meshbay-node/src/meshbay_node/ui/app.py +++ b/packages/meshbay-node/src/meshbay_node/ui/app.py @@ -291,6 +291,13 @@ def create_ui_app(state: dict) -> FastAPI: "quic_port": config.node.quic_port, "ui_port": config.node.ui_port, "data_dir": str(config.data_dir), + "settings": { + "invite_ttl_hours": config.node.invite_ttl_hours, + "pair_ttl_hours": config.node.pair_ttl_hours, + "device_request_ttl_minutes": config.node.device_request_ttl_minutes, + "max_concurrent_streams": config.node.max_concurrent_streams, + "transcode_incompatible_video": config.node.transcode_incompatible_video, + }, "groups": [ { "id": g.id, @@ -438,6 +445,12 @@ def create_ui_app(state: dict) -> FastAPI: # seconds, on a real library) — see ops.start_reload for why. return await _op(lambda: ops.start_reload(state)) + # ── Node settings (operator only, localhost) ─────────────────────────── + + @app.put("/api/node-settings") + async def update_node_settings(payload: dict): + return await _op(lambda: ops.set_node_settings(state, payload)) + # ── Chat endpoints ─────────────────────────────────────────────────────── _chat_subscribers: list[WebSocket] = [] @@ -521,6 +534,24 @@ def _fmt_size(n: int) -> str: return f"{n / (1024 * 1024 * 1024):.2f} GB" +def _render_node_settings(config) -> str: + if not config: + return "" + nd = config.node + transcode = "on" if nd.transcode_incompatible_video else "off" + return f""" + <table style="margin-top:10px"> + <thead><tr><th>Setting</th><th>Value</th></tr></thead> + <tbody> + <tr><td>Invitation TTL</td><td>{nd.invite_ttl_hours} hours</td></tr> + <tr><td>Pairing code TTL</td><td>{nd.pair_ttl_hours} hours</td></tr> + <tr><td>Device request TTL</td><td>{nd.device_request_ttl_minutes} minutes</td></tr> + <tr><td>Max concurrent streams</td><td>{nd.max_concurrent_streams}</td></tr> + <tr><td>Transcode incompatible video</td><td>{transcode}</td></tr> + </tbody> + </table>""" + + def _render_roster(roster_view: dict | None) -> str: """ Who this node recognises, and which keys are theirs. @@ -766,6 +797,7 @@ def _render_page(state: dict, roster_view: dict | None = None, <p><b>Hub:</b> {state.get("hub_url", "—")}</p> <p><b>QUIC port:</b> {state.get("quic_port", "—")}</p> <p><b>Node ID:</b> <code>{state.get("endpoint_hint") or "—"}</code></p> + {_render_node_settings(config)} </div> <h2>Maintenance</h2> |