Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion docs/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ Enumeration of HiveMind message types.
| `QUERY` | `"query"` | Request-response upstream; first answering node wins |
| `CASCADE` | `"cascade"` | Request-response flood; collects responses from all nodes |
| `PING` | `"ping"` | Network topology discovery (flood-based) |
| `RENDEZVOUS` | `"rendezvous"` | Reserved for rendezvous nodes |
| `RENDEZVOUS` | `"rendezvous"` | Async dead-drop via `hivemind-rendezvous` HTTP plugin; payload is INTERCOM; retrieved via pubkey proof |
| `BINARY` | `"bin"` | Raw binary data container |
| `THIRDPRTY` | `"3rdparty"` | User-defined message type |

Expand All @@ -69,6 +69,21 @@ Describes the content of a `BINARY` message.

WebSocket client that extends `ovos_bus_client.MessageBusClient`.

### Constructor Parameters

| Parameter | Type | Default | Description |
|---|---|---|---|
| `key` | `str` | `None` | Access key credential |
| `password` | `str` | `None` | Password credential |
| `host` | `str` | `None` | Hub WebSocket URL (e.g. `"ws://192.168.1.10"`) |
| `port` | `int` | `None` | Hub port (default 5678) |
| `identity` | `NodeIdentity` | `None` | Pre-built identity; loaded from disk if omitted |
| `rendezvous_urls` | `List[str]` | `None` | Rendezvous server base URLs to poll periodically (`client.py:106`) |
| `rendezvous_poll_interval` | `float` | `60.0` | Polling interval in seconds (`client.py:107`) |
| `share_bus` | `bool` | `False` | Share internal OVOS bus with hub (SHARED_BUS) |
| `compress` | `bool` | `True` | Enable message compression |
| `binarize` | `bool` | `True` | Use binary wire format when hub supports it |

### Core Methods

- `connect(bus=FakeBus(), protocol=None, site_id=None)` (`client.py:193`): Connects to the HiveMind hub, starts the background thread, and waits for the handshake to complete.
Expand All @@ -79,6 +94,14 @@ WebSocket client that extends `ovos_bus_client.MessageBusClient`.
- `wait_for_handshake(timeout=5, max_retries=15)` (`client.py:236`): Blocks until the cryptographic handshake with the hub is finished.
- `emit_intercom(message, pubkey)` (`client.py:538`): Sends a hybrid-encrypted (AES-GCM + RSA) message targeted at a specific node's public key.

### Rendezvous Polling

When `rendezvous_urls` is provided, a daemon thread (`"rendezvous-poller"`) starts automatically and polls each URL at `rendezvous_poll_interval` seconds.

- `_start_rendezvous_polling()` (`client.py:250`): Start the poller thread (called automatically in `__init__`).
- `_stop_rendezvous_polling()` (`client.py:263`): Stop the poller thread (called automatically in `on_close()`).
- `_poll_rendezvous(base_url)` (`client.py:276`): Single poll cycle for one URL — signs proof-of-ownership, POSTs to `/retrieve`, feeds each returned `HiveMessage` into `_handle_hive_protocol()`.

### Waiting for Messages

- `wait_for_message(message_type, timeout=3.0)` (`client.py:454`): Blocks until a specific `HiveMessageType` is received.
Expand Down
25 changes: 25 additions & 0 deletions docs/client_api.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,31 @@ msg = HiveMessage(HiveMessageType.BUS,
client.emit(msg) # Encrypts and sends via the WebSocket
```

### Rendezvous Polling

Pass `rendezvous_urls` to receive INTERCOM messages deposited at a `hivemind-rendezvous` server by nodes in other hives — even when those nodes are not simultaneously connected.

A daemon thread polls each URL every `rendezvous_poll_interval` seconds (default: 60). Retrieved messages are fed into the same `_handle_hive_protocol` path as live WebSocket messages, so existing `INTERCOM` handlers work without modification.

```python
client = HiveMessageBusClient(
key="my_access_key",
password="my_password",
host="ws://127.0.0.1",
rendezvous_urls=[
"http://rendezvous.example.com",
"http://backup-rendezvous.example.com",
],
rendezvous_poll_interval=30.0, # poll every 30 seconds
)
client.connect()

# INTERCOM messages retrieved from rendezvous are dispatched here
client.on(HiveMessageType.INTERCOM, lambda msg: print("Got rendezvous message:", msg))
```

The poller stops automatically when the WebSocket connection closes (`on_close`).

## 2. `HiveMindHTTPClient`
Use this for scenarios where a persistent WebSocket is not desired or possible.
- **Source**: `hivemind_bus_client.http_client.HiveMindHTTPClient`
Expand Down
61 changes: 61 additions & 0 deletions docs/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -226,3 +226,64 @@ announcement = HiveMessage(
)
client.emit(announcement)
```

---

## Receiving INTERCOM messages via a rendezvous server

Nodes in other hives can deposit INTERCOM messages at a shared rendezvous server. Enable polling to receive them asynchronously — no simultaneous connection required.

```python
from hivemind_bus_client.client import HiveMessageBusClient
from hivemind_bus_client.message import HiveMessage, HiveMessageType

client = HiveMessageBusClient(
key="my_access_key",
password="my_password",
host="ws://127.0.0.1",
rendezvous_urls=["http://rendezvous.example.com"],
rendezvous_poll_interval=30.0,
)
client.connect()

# handler fires for both live WebSocket INTERCOM and rendezvous-retrieved ones
client.on(HiveMessageType.INTERCOM, lambda msg: print("INTERCOM:", msg.payload))
```

## Depositing a message at a rendezvous server (sender side)

The sender uses `hivemind-rendezvous` client helpers directly (no WebSocket needed):

```python
import json, time, urllib.request
import base64
from poorman_handshake.asymmetric.utils import sign_RSA, load_RSA_key
from hivemind_bus_client.message import HiveMessage, HiveMessageType
from hivemind_bus_client.identity import NodeIdentity

identity = NodeIdentity()
recipient_pubkey = "-----BEGIN PUBLIC KEY-----\n..." # obtained e.g. via PING

# Build and encrypt an INTERCOM payload
from hivemind_bus_client.encryption import hybrid_encrypt
from ovos_bus_client.message import Message as MycroftMessage

private_key = load_RSA_key(identity.private_key)
inner = MycroftMessage("speak", {"utterance": "hello from the other side"})
envelope = hybrid_encrypt(recipient_pubkey, HiveMessage(HiveMessageType.BUS, inner).serialize(),
sign_key=private_key)
msg = HiveMessage(HiveMessageType.INTERCOM, payload=envelope)
Comment on lines +273 to +275
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add recipient_pubkey to enable recipient binding in the example.

The example encrypts for recipient_pubkey but doesn't pass it as the recipient_pubkey parameter, so the envelope won't include recipient_fingerprint for binding. This should match the new API.

📝 Proposed fix
 envelope = hybrid_encrypt(recipient_pubkey, HiveMessage(HiveMessageType.BUS, inner).serialize(),
-                          sign_key=private_key)
+                          sign_key=private_key,
+                          recipient_pubkey=recipient_pubkey)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
envelope = hybrid_encrypt(recipient_pubkey, HiveMessage(HiveMessageType.BUS, inner).serialize(),
sign_key=private_key)
msg = HiveMessage(HiveMessageType.INTERCOM, payload=envelope)
envelope = hybrid_encrypt(recipient_pubkey, HiveMessage(HiveMessageType.BUS, inner).serialize(),
sign_key=private_key,
recipient_pubkey=recipient_pubkey)
msg = HiveMessage(HiveMessageType.INTERCOM, payload=envelope)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/examples.md` around lines 273 - 275, The example calls
hybrid_encrypt(recipient_pubkey, HiveMessage(...).serialize(),
sign_key=private_key) but does not pass the recipient_pubkey as the named
parameter required to include recipient_fingerprint; update the call to supply
recipient_pubkey (e.g., recipient_pubkey=recipient_pubkey) so hybrid_encrypt
produces an envelope bound to the recipient; keep the rest (HiveMessage,
HiveMessageType.BUS, HiveMessageType.INTERCOM, payload=envelope,
sign_key=private_key) unchanged.


body = json.dumps({
"payload": msg.serialize(),
"target_pubkey": recipient_pubkey,
}).encode()
req = urllib.request.Request(
"http://rendezvous.example.com/deposit",
data=body,
headers={"Content-Type": "application/json"},
method="POST",
)
with urllib.request.urlopen(req) as resp:
print(json.loads(resp.read())) # {"status": "ok", "deposit_id": "..."}
```
2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
- **Trusted Peers**: `NodeIdentity.trusted_keys` gates BUS injection for PROPAGATE and INTERCOM from untrusted sources.
- **CASCADE Aggregation**: Collects responses from all nodes with timeout and early resolution via `HiveMapper`.
- **PING Discovery**: Flood-based topology mapping with public key and locale announcement.
- **Binary Support**: Optimized handling for binary payloads such as TTS audio and file transfers.
- **Binary Support**: Optimized handling for binary payloads such as TTS audio and file transfers.\n- **Rendezvous Polling**: Optional background thread that periodically retrieves INTERCOM messages from one or more `hivemind-rendezvous` servers, enabling async communication with nodes from non-simultaneously-connected hives.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix inline \n — should be an actual line break.

The literal \n- string appears in the markdown source. This should be a proper newline to render the "Rendezvous Polling" feature as a separate bullet point.

📝 Proposed fix
-- **Binary Support**: Optimized handling for binary payloads such as TTS audio and file transfers.\n- **Rendezvous Polling**: Optional background thread that periodically retrieves INTERCOM messages from one or more `hivemind-rendezvous` servers, enabling async communication with nodes from non-simultaneously-connected hives.
+- **Binary Support**: Optimized handling for binary payloads such as TTS audio and file transfers.
+- **Rendezvous Polling**: Optional background thread that periodically retrieves INTERCOM messages from one or more `hivemind-rendezvous` servers, enabling async communication with nodes from non-simultaneously-connected hives.
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- **Binary Support**: Optimized handling for binary payloads such as TTS audio and file transfers.\n- **Rendezvous Polling**: Optional background thread that periodically retrieves INTERCOM messages from one or more `hivemind-rendezvous` servers, enabling async communication with nodes from non-simultaneously-connected hives.
- **Binary Support**: Optimized handling for binary payloads such as TTS audio and file transfers.
- **Rendezvous Polling**: Optional background thread that periodically retrieves INTERCOM messages from one or more `hivemind-rendezvous` servers, enabling async communication with nodes from non-simultaneously-connected hives.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/index.md` at line 13, The markdown contains a literal "\n- " sequence in
the bullet list (around the "Binary Support" and "Rendezvous Polling" items) so
"Rendezvous Polling" is not on its own line; edit the docs index content where
the list is defined and replace the escaped newline sequence with an actual
newline so each bullet (e.g., the "Binary Support" and "Rendezvous Polling"
items) is on its own line, ensuring standard Markdown list formatting.

- **Drop-in Replacement**: Designed to be mostly compatible with `ovos-bus-client`, allowing easy migration of existing OVOS skills or services to HiveMind.

## Primary Components
Expand Down
33 changes: 33 additions & 0 deletions docs/message_types.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ The `msg_type` (defined in `hivemind_bus_client.message.HiveMessageType`) dictat
| **`QUERY`** | Request-response upstream | Like ESCALATE, but first answering node sends a response back. Stops propagation on answer. |
| **`CASCADE`** | Request-response flood | Like PROPAGATE, but expects responses from ALL nodes. Supports disambiguation. |
| **`PING`** | Network discovery flood | Each node responds with its own PING (same `flood_id`). Carried inside PROPAGATE. Route metadata = hive path. |
| **`RENDEZVOUS`** | Async dead-drop (HTTP plugin) | Sender deposits INTERCOM payload at a rendezvous server; recipient retrieves via pubkey proof. Implemented by `hivemind-rendezvous`; not dispatched over WebSocket. |
| **`HELLO`** | Node announcement | Session sync at connection time. |
| **`HANDSHAKE`** | Crypto negotiation | Key exchange at connection time. |
| **`THIRDPRTY`** | User-land custom | Application-defined payload; HiveMind relays without interpretation. |
Expand Down Expand Up @@ -155,6 +156,38 @@ For automated topology collection use `HiveMapper` from `hivemind_core.hive_map`

---

## RENDEZVOUS — Async Dead Drop

`RENDEZVOUS` is implemented as a standalone HTTP plugin (`hivemind-rendezvous`), separate from the WebSocket protocol. It is **not dispatched over the WebSocket** — it is retrieved by the client via periodic HTTP polling.

### Use Case

Nodes from different, non-simultaneously-connected hives can exchange INTERCOM messages via a shared rendezvous server without ever establishing a direct connection or knowing each other's IP address.

### Polling

Configure `rendezvous_urls` in `HiveMessageBusClient` to enable background polling:

```python
client = HiveMessageBusClient(
key="...", password="...", host="ws://myhub",
rendezvous_urls=["http://rendezvous.example.com"],
rendezvous_poll_interval=60.0,
)
```

Each poll cycle:
1. Signs `pubkey + str(timestamp)` with the node's RSA private key (proof-of-ownership).
2. POSTs to `{url}/retrieve` with `pubkey`, `timestamp`, and `signature`.
3. Server verifies signature and freshness (timestamp within ±60 s), returns pending messages.
4. Each returned serialised `HiveMessage` is fed into `_handle_hive_protocol()` — same path as live WebSocket messages.

### Privacy

The rendezvous server sees the recipient's pubkey SHA-256 fingerprint and deposit metadata. It cannot read INTERCOM payload content (E2E RSA-encrypted). Neither communicating node learns the other's IP address.

---

## Route Metadata

Every `HiveMessage` has a `route` field: `List[Dict[str, Any]]` — an ordered list of hops tracking the network path.
Expand Down
138 changes: 134 additions & 4 deletions hivemind_bus_client/client.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import json
import ssl
from threading import Event
from typing import Union, Optional, Callable
import time
import urllib.error
import urllib.request
from threading import Event, Thread
from typing import Union, Optional, Callable, List

import pybase64
from Cryptodome.PublicKey import RSA
Expand Down Expand Up @@ -103,7 +106,9 @@ def __init__(self, key: Optional[str] = None,
binarize: bool = True,
identity: NodeIdentity = None,
internal_bus: Optional[OVOSBusClient] = None,
bin_callbacks: BinaryDataCallbacks = BinaryDataCallbacks()):
bin_callbacks: BinaryDataCallbacks = BinaryDataCallbacks(),
rendezvous_urls: Optional[List[str]] = None,
rendezvous_poll_interval: float = 60.0):
self.bin_callbacks = bin_callbacks
self.json_encoding = SupportedEncodings.JSON_HEX # server defaults before it was made configurable
self.cipher = SupportedCiphers.AES_GCM # server defaults before it was made configurable
Expand All @@ -120,6 +125,11 @@ def __init__(self, key: Optional[str] = None,
self.allow_self_signed = self_signed
self.share_bus = share_bus
self.handshake_event = Event()
self._rendezvous_urls: List[str] = list(rendezvous_urls) if rendezvous_urls else []
self._rendezvous_poll_interval: float = rendezvous_poll_interval
self._rendezvous_stop_event: Event = Event()
self._rendezvous_thread: Optional[Thread] = None
self._rendezvous_server_pubkeys: dict = {} # base_url -> cached server pubkey

# if you want to reduce CPU usage in exchange for more bandwidth set below to False
self.compress = compress # None -> auto
Expand All @@ -142,6 +152,9 @@ def __init__(self, key: Optional[str] = None,
super().__init__(host=host, port=self._port, ssl=use_ssl,
emitter=EventEmitter(), session=sess)

if self._rendezvous_urls:
self._start_rendezvous_polling()

def init_identity(self, site_id=None):
self.identity = self.identity or NodeIdentity()
self.identity.password = self._password or self.identity.password
Expand Down Expand Up @@ -231,8 +244,123 @@ def on_error(self, *args):
def on_close(self, *args):
self.handshake_event.clear()
self.crypto_key = None
self._stop_rendezvous_polling()
super().on_close(*args)

# ------------------------------------------------------------------
# Rendezvous polling
# ------------------------------------------------------------------

def _start_rendezvous_polling(self) -> None:
"""Start the background thread that periodically polls rendezvous URLs.

Does nothing if no URLs are configured or a thread is already running.
"""
if not self._rendezvous_urls or self._rendezvous_thread is not None:
return
self._rendezvous_stop_event.clear()
self._rendezvous_thread = Thread(
target=self._rendezvous_poll_loop,
daemon=True,
name="rendezvous-poller",
)
self._rendezvous_thread.start()
LOG.info("Rendezvous polling started (%d URLs, interval=%.0fs)",
len(self._rendezvous_urls), self._rendezvous_poll_interval)

def _stop_rendezvous_polling(self) -> None:
"""Signal the rendezvous polling thread to stop and wait for it to exit."""
stop_event = getattr(self, "_rendezvous_stop_event", None)
if stop_event is None:
return
stop_event.set()
thread = getattr(self, "_rendezvous_thread", None)
if thread is not None:
thread.join(timeout=5)
self._rendezvous_thread = None

def _rendezvous_poll_loop(self) -> None:
"""Background loop: poll every configured rendezvous URL at the configured interval."""
while not self._rendezvous_stop_event.wait(timeout=self._rendezvous_poll_interval):
for url in self._rendezvous_urls:
try:
self._poll_rendezvous(url.rstrip("/"))
except Exception:
LOG.exception("Rendezvous poll error for %s", url)

def _fetch_rendezvous_server_pubkey(self, base_url: str) -> str:
"""Fetch and cache the rendezvous server's RSA public key from ``GET /pubkey``.

Args:
base_url: Rendezvous server base URL (trailing slash already stripped).

Returns:
PEM-encoded RSA public key string, or empty string on failure.
"""
if base_url in self._rendezvous_server_pubkeys:
return self._rendezvous_server_pubkeys[base_url]
try:
req = urllib.request.Request(f"{base_url}/pubkey", method="GET")
with urllib.request.urlopen(req, timeout=10) as resp:
data = json.loads(resp.read())
server_pubkey: str = data.get("pubkey", "")
self._rendezvous_server_pubkeys[base_url] = server_pubkey
return server_pubkey
except Exception as exc:
LOG.warning("Rendezvous: could not fetch server pubkey from %s: %s", base_url, exc)
return ""

def _poll_rendezvous(self, base_url: str) -> None:
"""Retrieve pending messages from one rendezvous server and inject them.

Fetches the server's public key (cached after first call), builds a
server-bound domain-separated proof-of-ownership, POSTs to
``{base_url}/retrieve``, and feeds each returned serialised
:class:`HiveMessage` into :meth:`_handle_hive_protocol`.

Args:
base_url: Rendezvous server base URL (trailing slash already stripped).
"""
from hivemind_rendezvous.auth import sign_ownership
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if hivemind_rendezvous is declared as a dependency
echo "=== Checking setup.py ==="
cat setup.py 2>/dev/null | grep -i rendezvous || echo "Not found in setup.py"

echo "=== Checking pyproject.toml ==="
cat pyproject.toml 2>/dev/null | grep -i rendezvous || echo "Not found in pyproject.toml"

echo "=== Checking requirements*.txt ==="
cat requirements*.txt 2>/dev/null | grep -i rendezvous || echo "Not found in requirements"

Repository: JarbasHiveMind/hivemind-websocket-client

Length of output: 252


🏁 Script executed:

# Check what dependencies are actually declared
echo "=== Checking setup.py dependencies ==="
head -100 setup.py 2>/dev/null || echo "setup.py not found or too small"

echo -e "\n=== Checking pyproject.toml ==="
cat pyproject.toml 2>/dev/null || echo "pyproject.toml not found"

echo -e "\n=== Checking for any requirements files ==="
ls -la requirements*.txt 2>/dev/null || echo "No requirements files found"

Repository: JarbasHiveMind/hivemind-websocket-client

Length of output: 4183


🏁 Script executed:

# View the code context around line 324 in hivemind_bus_client/client.py
echo "=== Code context around line 324 ==="
sed -n '310,340p' hivemind_bus_client/client.py 2>/dev/null || echo "File or lines not found"

Repository: JarbasHiveMind/hivemind-websocket-client

Length of output: 1447


🏁 Script executed:

# Check requirements.txt content
cat requirements.txt

# Get more context around line 324 to check for error handling
echo -e "\n=== Broader context (lines 300-360) ==="
sed -n '300,360p' hivemind_bus_client/client.py

Repository: JarbasHiveMind/hivemind-websocket-client

Length of output: 2977


Add hivemind_rendezvous to dependencies or implement graceful error handling.

The import from hivemind_rendezvous.auth import sign_ownership at line 324 is missing error handling. The package is not listed in pyproject.toml or requirements.txt. Either add hivemind_rendezvous to project dependencies, or wrap the import in a try-except block to gracefully degrade if the package is unavailable (since the method uses a lazy import pattern suggesting optional functionality).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@hivemind_bus_client/client.py` at line 324, The import of sign_ownership from
hivemind_rendezvous.auth is unguarded and the package isn't listed as a
dependency; either add hivemind_rendezvous to the project dependencies
(pyproject.toml/requirements) or make the import optional by wrapping "from
hivemind_rendezvous.auth import sign_ownership" in a try/except ImportError that
sets sign_ownership = None (or a no-op) and update any callers in this module to
check for None and raise a clear, actionable error or skip signing when
unavailable; locate the import and its usages (symbol: sign_ownership) and
implement the conditional handling to gracefully degrade or fail with an
instructive message.


server_pubkey: str = self._fetch_rendezvous_server_pubkey(base_url)
pubkey: str = self.identity.public_key
private_key = load_RSA_key(self.identity.private_key)
timestamp: int = int(time.time())
signature: str = sign_ownership(private_key, pubkey, timestamp,
server_pubkey=server_pubkey)

body = json.dumps({
"pubkey": pubkey,
"timestamp": timestamp,
"signature": signature,
}).encode("utf-8")
req = urllib.request.Request(
f"{base_url}/retrieve",
data=body,
headers={"Content-Type": "application/json"},
method="POST",
)
try:
with urllib.request.urlopen(req, timeout=10) as resp:
result = json.loads(resp.read())
except urllib.error.HTTPError as exc:
LOG.warning("Rendezvous retrieve failed (%s): HTTP %d", base_url, exc.code)
return
except OSError as exc:
LOG.warning("Rendezvous retrieve connection error (%s): %s", base_url, exc)
return

messages = result.get("messages", [])
if messages:
LOG.info("Rendezvous: received %d message(s) from %s", len(messages), base_url)
for serialised in messages:
try:
msg = HiveMessage.deserialize(serialised)
self._handle_hive_protocol(msg)
except Exception:
LOG.exception("Rendezvous: failed to process retrieved message")

def wait_for_handshake(self, timeout=5, max_retries=15):
"""
Waits for the HiveMind handshake to complete; if the handshake is not set and the websocket connection is open, starts the handshake, otherwise waits for the websocket to open and retries.
Expand Down Expand Up @@ -548,5 +676,7 @@ def emit_intercom(self, message: Union[MycroftMessage, HiveMessage],
pubkey: RSA public key of the target peer.
"""
private_key = load_RSA_key(self.identity.private_key)
envelope = hybrid_encrypt(pubkey, message.serialize(), sign_key=private_key)
envelope = hybrid_encrypt(pubkey, message.serialize(),
sign_key=private_key,
recipient_pubkey=pubkey)
self.emit(HiveMessage(HiveMessageType.INTERCOM, payload=envelope))
Loading
Loading