aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-node/src/meshbay_node/ui
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-node/src/meshbay_node/ui')
-rw-r--r--packages/meshbay-node/src/meshbay_node/ui/app.py51
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 ───────────────────────────────────────────────────────