Spaces:
Running on Zero
Running on Zero
File size: 2,898 Bytes
8f53c4c | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 | """Mesh join service — redeem an invite/code into an all-to-all relay membership.
Exposes a single bus capability:
``mesh.join@1.0`` — given either a raw invite (``invite_text``) or an explicit
``relay_url`` (+ optional ``token``), join the relay hub so this node meshes
all-to-all with every other member over NAT. On success the roster peers are
already registered locally (by :class:`~hearthnet.transport.relay_client.RelayClient`),
so ``llm.chat`` / ``rag.query`` / ``chat.deliver`` route to them immediately.
This is the programmatic counterpart to the QR/redeem-code onboarding flow: the
invite already carries the relay endpoint (see
:func:`hearthnet.ui.onboarding.make_invite`), so a single ``mesh.join`` decodes
it and connects.
"""
from __future__ import annotations
from typing import Any
from hearthnet.bus.capability import CapabilityDescriptor, RouteRequest
class MeshService:
name = "mesh"
version = "1.0"
def __init__(self, node: Any) -> None:
self._node = node
def capabilities(self) -> list[tuple[Any, ...]]:
return [
(
CapabilityDescriptor(
name="mesh.join",
version=(1, 0),
trust_required="trusted",
idempotent=False,
),
self.join,
),
]
async def join(self, req: RouteRequest) -> dict[str, Any]:
body = req.body.get("input", {}) or req.body.get("params", {})
relay_url = body.get("relay_url")
token = body.get("token") or body.get("relay_token")
invite_text = body.get("invite_text") or body.get("invite")
if invite_text and not relay_url:
try:
from hearthnet.ui.onboarding import decode_invite
blob = decode_invite(str(invite_text))
except Exception as exc:
return {"error": "invite_invalid", "message": str(exc)}
relay_url = blob.relay_url
token = token or blob.relay_token
if not relay_url:
return {
"error": "no_relay",
"message": "invite does not carry a relay_url for mesh join",
}
if not relay_url:
return {"error": "bad_request", "message": "relay_url or invite_text required"}
try:
result = await self._node.join_relay(str(relay_url), token=token or None)
except Exception as exc:
code = getattr(exc, "code", "relay_join_failed")
return {"error": code, "message": str(exc)}
roster = result.get("roster", [])
return {
"output": {
"relay_url": relay_url,
"joined": True,
"members": [m.get("node_id") for m in roster],
"member_count": len(roster),
}
}
|