diff options
Diffstat (limited to 'packages/meshbay-node/src/meshbay_node/ui/app.py')
| -rw-r--r-- | packages/meshbay-node/src/meshbay_node/ui/app.py | 25 |
1 files changed, 24 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 9933750..f5cd5d0 100644 --- a/packages/meshbay-node/src/meshbay_node/ui/app.py +++ b/packages/meshbay-node/src/meshbay_node/ui/app.py @@ -23,6 +23,9 @@ from meshbay_node import __version__, ops log = logging.getLogger(__name__) +# Unread files sent to the operator's page at once; `unread_total` says the rest. +UNREAD_LISTED = 100 + def _op(coro): """ @@ -490,17 +493,28 @@ def create_ui_app(state: dict) -> FastAPI: 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. + + Also what the scan could not do, with paths, which is why it is here + and nowhere a member can ask: `unread`, the files it met and did not + index, each with the reason (`no_answer` when the disk said nothing); + and `stalled`, the folders the node paused by itself because their + disk stopped answering, each with where. """ 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": ""} + "current_dir": "", "unread": [], "unread_total": 0, "stalled": []} return { "scanning": progress.scanning, "scanned_bytes": progress.scanned_bytes, "total_bytes": progress.total_bytes, "current_dir": progress.current_dir, + "unread": [{"root": u.root, "path": u.path, "reason": u.reason} + for u in list(indexer.unread.values())[:UNREAD_LISTED]], + "unread_total": indexer.unread_count(), + "stalled": [{"root": name, "path": where} + for name, where in indexer.stalled.items()], } @app.get("/api/index-status") @@ -512,12 +526,17 @@ def create_ui_app(state: dict) -> FastAPI: is on screen whatever page the operator is on, so it cannot ask per group. Names roots, like `current_dir` above: loopback only, the operator's own screen. Reads state["indexers"] for the same reason. + + `slow_path` and `slow_secs` say what the disk has given no answer on, + and for how long, once that passes ten seconds: a scan that sits still + names the file it is sitting on. """ config = state.get("config") names = {g.id: g.name for g in config.groups} if config else {} groups = [] for gid, indexer in list(state.get("indexers", {}).items()): p = indexer.progress + slow = indexer.disk_wait() groups.append({ "group_id": gid, "group_name": names.get(gid, gid[:8]), @@ -530,6 +549,10 @@ def create_ui_app(state: dict) -> FastAPI: "files_done": p.files_done, "files_total": p.files_total, "queued": list(p.queued), + "slow_path": slow[0] if slow else "", + "slow_secs": int(slow[1]) if slow else 0, + "unread": indexer.unread_count(), + "stalled": list(indexer.stalled), }) return {"groups": groups} |