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