aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-node/src/meshbay_node/daemon.py
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-node/src/meshbay_node/daemon.py')
-rw-r--r--packages/meshbay-node/src/meshbay_node/daemon.py64
1 files changed, 35 insertions, 29 deletions
diff --git a/packages/meshbay-node/src/meshbay_node/daemon.py b/packages/meshbay-node/src/meshbay_node/daemon.py
index e11a654..5fc70fe 100644
--- a/packages/meshbay-node/src/meshbay_node/daemon.py
+++ b/packages/meshbay-node/src/meshbay_node/daemon.py
@@ -241,14 +241,13 @@ class NodeDaemon:
gek=gek,
on_change=self._on_index_change,
)
- await indexer.start()
+ await indexer.start(defer_scan=True)
self._indexers.append(indexer)
self._state["indexes"][group_cfg.id] = indexer.index
self._state["indexers"][group_cfg.id] = indexer
- log.info("Indexing group %s: %s (%d files)",
+ log.info("Group %s configured: %s (scan deferred)",
group_cfg.name,
- ", ".join(f"{r.name}={r.path}" for r in roots),
- indexer.index.count)
+ ", ".join(f"{r.name}={r.path}" for r in roots))
groups_ctx[group_cfg.id] = {
"gek": gek,
@@ -268,8 +267,8 @@ class NodeDaemon:
}
if not groups_ctx:
- log.error("No valid groups configured — exiting")
- return
+ log.warning("No groups configured yet — admin UI and hub "
+ "connection stay up; attach a group to go live")
# 5. Chat stores (one SQLite DB per group)
for gid in groups_ctx:
@@ -290,14 +289,14 @@ class NodeDaemon:
denylist = self._denylist
# 6. WebRTC transport (browser clients)
- first = next(iter(groups_ctx.values()))
+ first = next(iter(groups_ctx.values()), None)
if WEBRTC_AVAILABLE:
self._webrtc = WebRTCTransport(
sk_node=keys.sk_ed25519,
hub_pk_pem=session.hub_pk_pem,
- gek=first["gek"],
- roots=first["roots"],
- index=first["index"],
+ gek=first["gek"] if first else None,
+ roots=first["roots"] if first else None,
+ index=first["index"] if first else None,
groups=groups_ctx,
denylist=denylist,
max_concurrent_streams=self._config.node.max_concurrent_streams,
@@ -307,6 +306,7 @@ class NodeDaemon:
# _group_ctx(). Assigning the first group's store transport-wide
# sent every group's chat to one database and served it back to
# members of every other group (finding H1).
+ self._webrtc._ctx["groups"] = groups_ctx
self._webrtc._ctx["hub_ws"] = _WsSender(hub)
self._webrtc._ctx["node_user_id"] = session.user_id
self._webrtc._ctx["audit_store"] = self._audit_store
@@ -342,14 +342,15 @@ class NodeDaemon:
self._quic_server = QuicChunkServer(
sk_node=keys.sk_ed25519,
hub_pk_pem=session.hub_pk_pem,
- gek=first["gek"],
- roots=first["roots"],
- index=first["index"],
+ gek=first["gek"] if first else None,
+ roots=first["roots"] if first else None,
+ index=first["index"] if first else None,
host="::",
port=self._config.node.quic_port,
groups=groups_ctx,
denylist=denylist,
)
+ self._quic_server._ctx["groups"] = groups_ctx
await self._quic_server.start()
log.info("QUIC server on port %d (%d groups)",
self._config.node.quic_port, len(groups_ctx))
@@ -434,18 +435,23 @@ class NodeDaemon:
"yes" if self._webrtc else "no",
"yes" if self._quic_server else "no")
- # 11. Initial swarm registration — PUBLIC groups only.
- # Finding H7: registering every group's hashes hands the hub a content
- # fingerprint of every private file on the node, which is exactly the
- # metadata the "hub stores no content metadata" claim rules out. It also
- # lets anyone confirm whether a known file exists in the network.
- endpoint = f"webrtc:{self._config.node.quic_port}"
- for gctx in groups_ctx.values():
- if gctx.get("visibility") != "public":
- continue
- hashes = [e.id for e in gctx["index"].entries]
- if hashes:
- asyncio.ensure_future(self._register_swarm(hashes, endpoint))
+ # 11. Background initial scan — files appear progressively.
+ async def _bg_scan(indexer, name, gctx):
+ await indexer.initial_scan()
+ log.info("Background scan complete for %s: %d files",
+ name, indexer.index.count)
+ # Swarm registration for public groups (after files are known).
+ if gctx.get("visibility") == "public":
+ endpoint = f"webrtc:{self._config.node.quic_port}"
+ hashes = [e.id for e in gctx["index"].entries]
+ if hashes:
+ await self._register_swarm(hashes, endpoint)
+
+ for idx, group_cfg in zip(self._indexers, self._config.groups):
+ gctx = groups_ctx.get(group_cfg.id)
+ if gctx:
+ self._tasks.append(asyncio.create_task(
+ _bg_scan(idx, group_cfg.name, gctx)))
# 12. Wait for shutdown
stop_event = asyncio.Event()
@@ -486,7 +492,7 @@ class NodeDaemon:
log.error("Reload failed, keeping the running config: %s", e)
return
- groups_ctx = self._state.get("groups_ctx") or {}
+ groups_ctx = self._state.get("groups_ctx", {})
hosted = set(groups_ctx)
incoming = {g.id for g in fresh.groups if g.id}
@@ -647,7 +653,7 @@ class NodeDaemon:
log.warning(
"Node key not linked. Open the admin UI, copy this "
"node's key, and paste it in Settings > Link Node on "
- "%s. Retrying in 30s...",
+ "%s. Retrying in 5s...",
self._config.hub.url,
)
else:
@@ -655,10 +661,10 @@ class NodeDaemon:
log.warning(
"Hub rejected the node credentials for user %r. "
"Register that account on %s first, then link this "
- "node's key. Retrying in 30s...",
+ "node's key. Retrying in 5s...",
self._config.hub.username, self._config.hub.url,
)
- await asyncio.sleep(30)
+ await asyncio.sleep(5)
else:
raise
except Exception as e: