diff options
Diffstat (limited to 'packages/meshbay-node/src/meshbay_node/ui')
| -rw-r--r-- | packages/meshbay-node/src/meshbay_node/ui/app.py | 51 |
1 files changed, 50 insertions, 1 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/ui/app.py b/packages/meshbay-node/src/meshbay_node/ui/app.py index b505f25..d5b3f94 100644 --- a/packages/meshbay-node/src/meshbay_node/ui/app.py +++ b/packages/meshbay-node/src/meshbay_node/ui/app.py @@ -26,6 +26,7 @@ from fastapi.responses import HTMLResponse, JSONResponse from meshbay_node import __version__ from meshbay_node import ops from meshbay_node.config import DEFAULT_CONFIG_PATH +from meshbay_node.indexer.indexer import DirectoryIndexer from meshbay_common.crypto import generate_gek, wrap_gek_aes from meshbay_common.join import ROLE_MEMBER, ROLE_OPERATOR @@ -319,6 +320,39 @@ def create_ui_app(state: dict) -> FastAPI: asyncio.ensure_future(reload_fn()) return result + # asyncio.ensure_future above schedules the reload (and whatever initial + # scan it triggers) on the daemon's own event loop — it has no link to + # this HTTP request or to any browser tab. Closing the client that made + # this call does not cancel it: the scan is the node's own background + # work, not something borrowed from the request that started it. + + @app.get("/api/groups/{group_id}/index-status") + async def index_status(group_id: str): + """ + Polled by the Create Group wizard and by "add a directory" in + Settings — the same source either way, since both just start a scan + on this group's indexer. `current_dir` is a basename only, and is + never sent over MNP (see IndexProgress in indexer.py) — this route + is loopback-only, for the operator's own screen. + + Reads state["indexers"] rather than groups_ctx: a brand-new group is + registered there before its (possibly long) initial scan runs, but + is only added to groups_ctx once that scan finishes (it is not yet + authorized for member connections either way — see _reload_config) + — this is precisely the window the wizard needs to watch. + """ + indexer = state.get("indexers", {}).get(group_id) + progress = indexer.progress if indexer else None + if progress is None: + return {"scanning": False, "scanned_bytes": 0, "total_bytes": 0, + "current_dir": ""} + return { + "scanning": progress.scanning, + "scanned_bytes": progress.scanned_bytes, + "total_bytes": progress.total_bytes, + "current_dir": progress.current_dir, + } + # ── Upload toggle (operator only, localhost) ───────────────────────── @app.put("/api/groups/{group_id}/member-upload") @@ -327,11 +361,26 @@ def create_ui_app(state: dict) -> FastAPI: state, group_id, bool(payload.get("allowed", False)), )) + # ── Scan settings (operator only, localhost) ────────────────────────── + + @app.put("/api/groups/{group_id}/scan-settings") + async def set_scan_settings(group_id: str, payload: dict): + return await _op(lambda: ops.set_scan_settings( + state, group_id, + float(payload.get("reconcile_interval_secs", + DirectoryIndexer.DEFAULT_RECONCILE_SECS)), + float(payload.get("debounce_secs", + DirectoryIndexer.DEFAULT_DEBOUNCE_SECS)), + )) + # ── Reload config ──────────────────────────────────────────────────── @app.post("/api/reload") async def reload_config(): - return await _op(lambda: ops.reload_config(state)) + # start_reload, not reload_config: this must return before a + # brand-new group's synchronous initial scan finishes (minutes, not + # seconds, on a real library) — see ops.start_reload for why. + return await _op(lambda: ops.start_reload(state)) # ── Chat endpoints ─────────────────────────────────────────────────────── |