pub struct HiveMesh { /* private fields */ }Expand description
Main facade for HIVE BLE mesh operations
Composes peer management, document sync, and observer notifications. Platform implementations call into this from their BLE callbacks.
Implementations§
Source§impl HiveMesh
impl HiveMesh
Sourcepub fn new(config: HiveMeshConfig) -> Self
pub fn new(config: HiveMeshConfig) -> Self
Create a new HiveMesh instance
Sourcepub fn is_encryption_enabled(&self) -> bool
pub fn is_encryption_enabled(&self) -> bool
Check if mesh-wide encryption is enabled
Sourcepub fn is_strict_encryption_enabled(&self) -> bool
pub fn is_strict_encryption_enabled(&self) -> bool
Check if strict encryption mode is enabled
Returns true only if both encryption and strict_encryption are enabled.
Sourcepub fn enable_encryption(&mut self, secret: &[u8; 32])
pub fn enable_encryption(&mut self, secret: &[u8; 32])
Enable mesh-wide encryption with a shared secret
Derives a ChaCha20-Poly1305 key from the secret using HKDF-SHA256. All mesh participants must use the same secret to communicate.
Sourcepub fn disable_encryption(&mut self)
pub fn disable_encryption(&mut self)
Disable mesh-wide encryption
Sourcepub fn is_relay_enabled(&self) -> bool
pub fn is_relay_enabled(&self) -> bool
Check if multi-hop relay is enabled
Sourcepub fn enable_relay(&mut self)
pub fn enable_relay(&mut self)
Enable multi-hop relay
Sourcepub fn disable_relay(&mut self)
pub fn disable_relay(&mut self)
Disable multi-hop relay
Sourcepub fn has_seen_message(&self, message_id: &MessageId) -> bool
pub fn has_seen_message(&self, message_id: &MessageId) -> bool
Check if a message has been seen before (for deduplication)
Returns true if the message was already seen (duplicate).
Sourcepub fn mark_message_seen(
&self,
message_id: MessageId,
origin: NodeId,
now_ms: u64,
) -> bool
pub fn mark_message_seen( &self, message_id: MessageId, origin: NodeId, now_ms: u64, ) -> bool
Mark a message as seen
Returns true if this is a new message (first time seen).
Sourcepub fn seen_cache_size(&self) -> usize
pub fn seen_cache_size(&self) -> usize
Get the number of entries in the seen message cache
Sourcepub fn clear_seen_cache(&self)
pub fn clear_seen_cache(&self)
Clear the seen message cache
Sourcepub fn wrap_for_relay(&self, payload: Vec<u8>) -> Vec<u8> ⓘ
pub fn wrap_for_relay(&self, payload: Vec<u8>) -> Vec<u8> ⓘ
Wrap a document in a relay envelope for multi-hop transmission
The returned bytes can be sent to peers and will be automatically relayed through the mesh if relay is enabled on receiving nodes.
Sourcepub fn get_relay_targets(&self, exclude_peer: Option<NodeId>) -> Vec<HivePeer>
pub fn get_relay_targets(&self, exclude_peer: Option<NodeId>) -> Vec<HivePeer>
Get peers to relay a message to
Uses the configured gossip strategy to select relay targets. Excludes the source peer (if provided) to avoid sending back to sender.
Sourcepub fn process_relay_envelope(
&self,
data: &[u8],
source_peer: NodeId,
now_ms: u64,
) -> Option<RelayDecision>
pub fn process_relay_envelope( &self, data: &[u8], source_peer: NodeId, now_ms: u64, ) -> Option<RelayDecision>
Process an incoming relay envelope
Handles deduplication, TTL checking, and determines if the message should be processed and/or relayed.
Returns:
Ok(Some(RelayDecision))if message should be processed/relayedOk(None)if message was a duplicate or TTL expiredErrif parsing failed
Sourcepub fn build_relay_document(&self) -> Vec<u8> ⓘ
pub fn build_relay_document(&self) -> Vec<u8> ⓘ
Build a document wrapped in a relay envelope
Convenience method that builds the document, encrypts it (if enabled), and wraps it in a relay envelope for multi-hop transmission.
Sourcepub fn register_peer_for_delta(&self, peer_id: &NodeId)
pub fn register_peer_for_delta(&self, peer_id: &NodeId)
Register a peer for delta sync tracking
Call this when a peer connects to start tracking what data has been sent to them. This enables future delta sync (sending only changes).
Sourcepub fn unregister_peer_for_delta(&self, peer_id: &NodeId)
pub fn unregister_peer_for_delta(&self, peer_id: &NodeId)
Unregister a peer from delta sync tracking
Call this when a peer disconnects to clean up tracking state.
Sourcepub fn reset_peer_delta_state(&self, peer_id: &NodeId)
pub fn reset_peer_delta_state(&self, peer_id: &NodeId)
Reset delta sync state for a peer
Call this when a peer reconnects to force a full sync on next communication. This clears the record of what was previously sent.
Sourcepub fn record_delta_sent(&self, peer_id: &NodeId, bytes: usize)
pub fn record_delta_sent(&self, peer_id: &NodeId, bytes: usize)
Record bytes sent to a peer (for delta statistics)
Sourcepub fn record_delta_received(
&self,
peer_id: &NodeId,
bytes: usize,
timestamp: u64,
)
pub fn record_delta_received( &self, peer_id: &NodeId, bytes: usize, timestamp: u64, )
Record bytes received from a peer (for delta statistics)
Sourcepub fn delta_stats(&self) -> DeltaStats
pub fn delta_stats(&self) -> DeltaStats
Get delta sync statistics
Returns aggregate statistics about delta sync across all peers, including bytes sent/received and sync counts.
Sourcepub fn peer_delta_stats(&self, peer_id: &NodeId) -> Option<(u64, u64, u32)>
pub fn peer_delta_stats(&self, peer_id: &NodeId) -> Option<(u64, u64, u32)>
Get delta sync statistics for a specific peer
Returns the bytes sent/received and sync count for a single peer.
Sourcepub fn build_delta_document_for_peer(
&self,
peer_id: &NodeId,
now_ms: u64,
) -> Option<Vec<u8>>
pub fn build_delta_document_for_peer( &self, peer_id: &NodeId, now_ms: u64, ) -> Option<Vec<u8>>
Build a delta document for a specific peer
This only includes operations that have changed since the last sync with this peer. Uses the delta encoder to track per-peer state.
Returns the encoded delta document bytes, or None if there’s nothing new to send to this peer.
Sourcepub fn build_full_delta_document(&self, now_ms: u64) -> Vec<u8> ⓘ
pub fn build_full_delta_document(&self, now_ms: u64) -> Vec<u8> ⓘ
Build a full delta document (for broadcast or new peers)
Unlike build_delta_document_for_peer, this includes all state
regardless of what has been sent before. Use this for broadcasts.
Sourcepub fn enable_peer_e2ee(&self)
pub fn enable_peer_e2ee(&self)
Enable per-peer E2EE capability
Creates a new identity key for this node. This allows establishing encrypted sessions with specific peers where only the sender and recipient can read messages (other mesh members cannot).
Sourcepub fn disable_peer_e2ee(&self)
pub fn disable_peer_e2ee(&self)
Disable per-peer E2EE capability
Clears all peer sessions and disables E2EE.
Sourcepub fn is_peer_e2ee_enabled(&self) -> bool
pub fn is_peer_e2ee_enabled(&self) -> bool
Check if per-peer E2EE is enabled
Sourcepub fn peer_e2ee_public_key(&self) -> Option<[u8; 32]>
pub fn peer_e2ee_public_key(&self) -> Option<[u8; 32]>
Get our E2EE public key (for sharing with peers)
Returns None if per-peer E2EE is not enabled.
Sourcepub fn initiate_peer_e2ee(
&self,
peer_node_id: NodeId,
now_ms: u64,
) -> Option<Vec<u8>>
pub fn initiate_peer_e2ee( &self, peer_node_id: NodeId, now_ms: u64, ) -> Option<Vec<u8>>
Initiate E2EE session with a specific peer
Returns the key exchange message bytes to send to the peer. The message should be broadcast/sent to the peer. Returns None if per-peer E2EE is not enabled.
Sourcepub fn has_peer_e2ee_session(&self, peer_node_id: NodeId) -> bool
pub fn has_peer_e2ee_session(&self, peer_node_id: NodeId) -> bool
Check if we have an established E2EE session with a peer
Sourcepub fn peer_e2ee_session_state(
&self,
peer_node_id: NodeId,
) -> Option<SessionState>
pub fn peer_e2ee_session_state( &self, peer_node_id: NodeId, ) -> Option<SessionState>
Get E2EE session state with a peer
Sourcepub fn send_peer_e2ee(
&self,
peer_node_id: NodeId,
plaintext: &[u8],
now_ms: u64,
) -> Option<Vec<u8>>
pub fn send_peer_e2ee( &self, peer_node_id: NodeId, plaintext: &[u8], now_ms: u64, ) -> Option<Vec<u8>>
Send an E2EE encrypted message to a specific peer
Returns the encrypted message bytes to send, or None if no session exists. The message should be sent directly to the peer (not broadcast).
Sourcepub fn close_peer_e2ee(&self, peer_node_id: NodeId)
pub fn close_peer_e2ee(&self, peer_node_id: NodeId)
Close E2EE session with a peer
Sourcepub fn peer_e2ee_session_count(&self) -> usize
pub fn peer_e2ee_session_count(&self) -> usize
Get count of active E2EE sessions
Sourcepub fn peer_e2ee_established_count(&self) -> usize
pub fn peer_e2ee_established_count(&self) -> usize
Get count of established E2EE sessions
Sourcepub fn device_name(&self) -> String
pub fn device_name(&self) -> String
Get the device name for BLE advertising
Sourcepub fn add_observer(&self, observer: Arc<dyn HiveObserver>)
pub fn add_observer(&self, observer: Arc<dyn HiveObserver>)
Add an observer for mesh events
Sourcepub fn remove_observer(&self, observer: &Arc<dyn HiveObserver>)
pub fn remove_observer(&self, observer: &Arc<dyn HiveObserver>)
Remove an observer
Sourcepub fn send_emergency(&self, timestamp: u64) -> Vec<u8> ⓘ
pub fn send_emergency(&self, timestamp: u64) -> Vec<u8> ⓘ
Send an emergency alert
Returns the document bytes to broadcast to all peers. If encryption is enabled, the document is encrypted.
Sourcepub fn send_ack(&self, timestamp: u64) -> Vec<u8> ⓘ
pub fn send_ack(&self, timestamp: u64) -> Vec<u8> ⓘ
Send an ACK response
Returns the document bytes to broadcast to all peers. If encryption is enabled, the document is encrypted.
Sourcepub fn clear_event(&self)
pub fn clear_event(&self)
Clear the current event (emergency or ack)
Sourcepub fn is_emergency_active(&self) -> bool
pub fn is_emergency_active(&self) -> bool
Check if emergency is active
Sourcepub fn is_ack_active(&self) -> bool
pub fn is_ack_active(&self) -> bool
Check if ACK is active
Sourcepub fn current_event(&self) -> Option<EventType>
pub fn current_event(&self) -> Option<EventType>
Get current event type
Sourcepub fn start_emergency(&self, timestamp: u64, known_peers: &[u32]) -> Vec<u8> ⓘ
pub fn start_emergency(&self, timestamp: u64, known_peers: &[u32]) -> Vec<u8> ⓘ
Start a new emergency event with ACK tracking
Creates an emergency event that tracks ACKs from all known peers. Pass the list of known peer node IDs to track. Returns the document bytes to broadcast. If encryption is enabled, the document is encrypted.
Sourcepub fn start_emergency_with_known_peers(&self, timestamp: u64) -> Vec<u8> ⓘ
pub fn start_emergency_with_known_peers(&self, timestamp: u64) -> Vec<u8> ⓘ
Start a new emergency using all currently known peers
Convenience method that automatically includes all discovered peers.
Sourcepub fn ack_emergency(&self, timestamp: u64) -> Option<Vec<u8>>
pub fn ack_emergency(&self, timestamp: u64) -> Option<Vec<u8>>
Record our ACK for the current emergency
Returns the document bytes to broadcast, or None if no emergency is active. If encryption is enabled, the document is encrypted.
Sourcepub fn clear_emergency(&self)
pub fn clear_emergency(&self)
Clear the current emergency event
Sourcepub fn has_active_emergency(&self) -> bool
pub fn has_active_emergency(&self) -> bool
Check if there’s an active emergency
Sourcepub fn get_emergency_status(&self) -> Option<(u32, u64, usize, usize)>
pub fn get_emergency_status(&self) -> Option<(u32, u64, usize, usize)>
Get emergency status info
Returns (source_node, timestamp, acked_count, pending_count) if emergency is active.
Sourcepub fn has_peer_acked(&self, peer_id: u32) -> bool
pub fn has_peer_acked(&self, peer_id: u32) -> bool
Check if a specific peer has ACKed the current emergency
Sourcepub fn all_peers_acked(&self) -> bool
pub fn all_peers_acked(&self) -> bool
Check if all peers have ACKed the current emergency
Sourcepub fn send_chat(
&self,
sender: &str,
text: &str,
timestamp: u64,
) -> Option<Vec<u8>>
pub fn send_chat( &self, sender: &str, text: &str, timestamp: u64, ) -> Option<Vec<u8>>
Send a chat message
Adds the message to the local CRDT and returns the document bytes to broadcast to all peers. If encryption is enabled, the document is encrypted.
Returns the encrypted document bytes if the message was new, or None if it was a duplicate.
Sourcepub fn send_chat_reply(
&self,
sender: &str,
text: &str,
reply_to_node: u32,
reply_to_timestamp: u64,
timestamp: u64,
) -> Option<Vec<u8>>
pub fn send_chat_reply( &self, sender: &str, text: &str, reply_to_node: u32, reply_to_timestamp: u64, timestamp: u64, ) -> Option<Vec<u8>>
Send a chat reply
Adds the reply to the local CRDT with reply-to information and returns the document bytes to broadcast. If encryption is enabled, the document is encrypted.
Returns the encrypted document bytes if the message was new, or None if it was a duplicate.
Sourcepub fn chat_count(&self) -> usize
pub fn chat_count(&self) -> usize
Get the number of chat messages in the local CRDT
Sourcepub fn chat_messages_since(
&self,
since_timestamp: u64,
) -> Vec<(u32, u64, String, String, u32, u64)>
pub fn chat_messages_since( &self, since_timestamp: u64, ) -> Vec<(u32, u64, String, String, u32, u64)>
Get chat messages newer than a timestamp
Returns a vector of (origin_node, timestamp, sender, text, reply_to_node, reply_to_timestamp) tuples.
Sourcepub fn all_chat_messages(&self) -> Vec<(u32, u64, String, String, u32, u64)>
pub fn all_chat_messages(&self) -> Vec<(u32, u64, String, String, u32, u64)>
Get all chat messages
Returns a vector of (origin_node, timestamp, sender, text, reply_to_node, reply_to_timestamp) tuples.
Sourcepub fn on_ble_discovered(
&self,
identifier: &str,
name: Option<&str>,
rssi: i8,
mesh_id: Option<&str>,
now_ms: u64,
) -> Option<HivePeer>
pub fn on_ble_discovered( &self, identifier: &str, name: Option<&str>, rssi: i8, mesh_id: Option<&str>, now_ms: u64, ) -> Option<HivePeer>
Called when a BLE device is discovered
Returns Some(HivePeer) if this is a new HIVE peer on our mesh.
Sourcepub fn on_ble_connected(&self, identifier: &str, now_ms: u64) -> Option<NodeId>
pub fn on_ble_connected(&self, identifier: &str, now_ms: u64) -> Option<NodeId>
Called when a BLE connection is established (outgoing)
Returns the NodeId if this identifier is known.
Sourcepub fn on_ble_disconnected(
&self,
identifier: &str,
reason: DisconnectReason,
) -> Option<NodeId>
pub fn on_ble_disconnected( &self, identifier: &str, reason: DisconnectReason, ) -> Option<NodeId>
Called when a BLE connection is lost
Sourcepub fn on_peer_disconnected(&self, node_id: NodeId, reason: DisconnectReason)
pub fn on_peer_disconnected(&self, node_id: NodeId, reason: DisconnectReason)
Called when a BLE connection is lost, using NodeId directly
Alternative to on_ble_disconnected() when only NodeId is known (e.g., ESP32).
Sourcepub fn on_incoming_connection(
&self,
identifier: &str,
node_id: NodeId,
now_ms: u64,
) -> bool
pub fn on_incoming_connection( &self, identifier: &str, node_id: NodeId, now_ms: u64, ) -> bool
Called when a remote device connects to us (incoming connection)
Use this when we’re acting as a peripheral and a central connects to us.
Sourcepub fn on_ble_data_received(
&self,
identifier: &str,
data: &[u8],
now_ms: u64,
) -> Option<DataReceivedResult>
pub fn on_ble_data_received( &self, identifier: &str, data: &[u8], now_ms: u64, ) -> Option<DataReceivedResult>
Called when data is received from a peer
Parses the document, merges it, and generates appropriate events. If encryption is enabled, decrypts the document first. Handles per-peer E2EE messages (KEY_EXCHANGE and PEER_E2EE markers). Returns the source NodeId and whether the document contained an event.
Sourcepub fn on_ble_data_received_from_node(
&self,
node_id: NodeId,
data: &[u8],
now_ms: u64,
) -> Option<DataReceivedResult>
pub fn on_ble_data_received_from_node( &self, node_id: NodeId, data: &[u8], now_ms: u64, ) -> Option<DataReceivedResult>
Called when data is received but we don’t have the identifier mapped
Use this when receiving data from a peripheral we discovered. If encryption is enabled, decrypts the document first. Handles per-peer E2EE messages (KEY_EXCHANGE and PEER_E2EE markers). Handles relay envelopes for multi-hop mesh operation.
Sourcepub fn on_ble_data(
&self,
identifier: &str,
data: &[u8],
now_ms: u64,
) -> Option<DataReceivedResult>
pub fn on_ble_data( &self, identifier: &str, data: &[u8], now_ms: u64, ) -> Option<DataReceivedResult>
Called when data is received without a known identifier
This is the simplest data receive method - it extracts the source node_id from the document itself. Use this when you don’t track identifiers (e.g., ESP32 NimBLE). If encryption is enabled, decrypts the document first. Handles per-peer E2EE messages (KEY_EXCHANGE and PEER_E2EE markers). Handles relay envelopes for multi-hop mesh operation.
Sourcepub fn tick(&self, now_ms: u64) -> Option<Vec<u8>>
pub fn tick(&self, now_ms: u64) -> Option<Vec<u8>>
Periodic tick - call this regularly (e.g., every second)
Performs:
- Stale peer cleanup
- Periodic sync broadcast (if interval elapsed)
Returns Some(data) if a sync broadcast is needed.
Sourcepub fn get_connected_peers(&self) -> Vec<HivePeer>
pub fn get_connected_peers(&self) -> Vec<HivePeer>
Get connected peers only
Sourcepub fn peer_count(&self) -> usize
pub fn peer_count(&self) -> usize
Get peer count
Sourcepub fn connected_count(&self) -> usize
pub fn connected_count(&self) -> usize
Get connected peer count
Sourcepub fn matches_mesh(&self, device_mesh_id: Option<&str>) -> bool
pub fn matches_mesh(&self, device_mesh_id: Option<&str>) -> bool
Check if a device mesh ID matches our mesh
Sourcepub fn get_connection_graph(&self) -> Vec<PeerConnectionState>
pub fn get_connection_graph(&self) -> Vec<PeerConnectionState>
Get the connection state graph with all peer states
Returns a snapshot of all tracked peers and their connection lifecycle state. Apps can use this to display appropriate UI indicators:
- Green for Connected peers
- Yellow for Degraded or RecentlyDisconnected peers
- Gray for Lost peers
§Example
let states = mesh.get_connection_graph();
for peer in states {
match peer.state {
ConnectionState::Connected => show_green_indicator(&peer),
ConnectionState::Degraded => show_yellow_indicator(&peer),
ConnectionState::Disconnected => show_stale_indicator(&peer),
ConnectionState::Lost => show_gray_indicator(&peer),
_ => {}
}
}Sourcepub fn get_peer_connection_state(
&self,
node_id: NodeId,
) -> Option<PeerConnectionState>
pub fn get_peer_connection_state( &self, node_id: NodeId, ) -> Option<PeerConnectionState>
Get a specific peer’s connection state
Sourcepub fn get_connected_states(&self) -> Vec<PeerConnectionState>
pub fn get_connected_states(&self) -> Vec<PeerConnectionState>
Get all currently connected peers from the connection graph
Sourcepub fn get_degraded_peers(&self) -> Vec<PeerConnectionState>
pub fn get_degraded_peers(&self) -> Vec<PeerConnectionState>
Get peers in degraded state (connected but poor signal quality)
Sourcepub fn get_recently_disconnected(
&self,
within_ms: u64,
now_ms: u64,
) -> Vec<PeerConnectionState>
pub fn get_recently_disconnected( &self, within_ms: u64, now_ms: u64, ) -> Vec<PeerConnectionState>
Get peers that disconnected within the specified time window
Useful for showing “stale” peers that were recently connected.
Sourcepub fn get_lost_peers(&self) -> Vec<PeerConnectionState>
pub fn get_lost_peers(&self) -> Vec<PeerConnectionState>
Get peers in Lost state (disconnected and no longer advertising)
Sourcepub fn get_connection_state_counts(&self) -> StateCountSummary
pub fn get_connection_state_counts(&self) -> StateCountSummary
Get summary counts of peers in each connection state
Sourcepub fn get_indirect_peers(&self) -> Vec<IndirectPeer>
pub fn get_indirect_peers(&self) -> Vec<IndirectPeer>
Get all indirect (multi-hop) peers
Returns peers discovered via relay messages that are not directly connected via BLE. Each indirect peer includes the minimum hop count and the direct peers through which they can be reached.
Sourcepub fn get_peer_degree(&self, node_id: NodeId) -> Option<PeerDegree>
pub fn get_peer_degree(&self, node_id: NodeId) -> Option<PeerDegree>
Get the degree (hop count) for a specific peer
Returns:
Some(PeerDegree::Direct)for directly connected BLE peersSome(PeerDegree::OneHop/TwoHop/ThreeHop)for indirect peersNoneif peer is not known
Sourcepub fn get_full_state_counts(&self) -> FullStateCountSummary
pub fn get_full_state_counts(&self) -> FullStateCountSummary
Get full state counts including indirect peers
Returns counts of direct peers by connection state plus counts of indirect peers by hop count (1-hop, 2-hop, 3-hop).
Sourcepub fn get_paths_to_peer(&self, node_id: NodeId) -> Vec<(NodeId, u8)>
pub fn get_paths_to_peer(&self, node_id: NodeId) -> Vec<(NodeId, u8)>
Get all paths to reach an indirect peer
Returns a list of (via_peer_id, hop_count) pairs showing all known routes to the specified peer.
Sourcepub fn is_peer_known(&self, node_id: NodeId) -> bool
pub fn is_peer_known(&self, node_id: NodeId) -> bool
Check if a node is known (either direct or indirect)
Sourcepub fn indirect_peer_count(&self) -> usize
pub fn indirect_peer_count(&self) -> usize
Get number of indirect peers
Sourcepub fn cleanup_indirect_peers(&self, now_ms: u64) -> Vec<NodeId>
pub fn cleanup_indirect_peers(&self, now_ms: u64) -> Vec<NodeId>
Cleanup stale indirect peers
Removes indirect peers that haven’t been seen within the timeout. Returns the list of removed peer IDs.
Sourcepub fn total_count(&self) -> u64
pub fn total_count(&self) -> u64
Get total counter value
Sourcepub fn document_version(&self) -> u32
pub fn document_version(&self) -> u32
Get document version
Sourcepub fn update_health(&self, battery_percent: u8)
pub fn update_health(&self, battery_percent: u8)
Update health status (battery percentage)
Sourcepub fn update_activity(&self, activity: u8)
pub fn update_activity(&self, activity: u8)
Update activity level (0=still, 1=walking, 2=running, 3=fall)
Sourcepub fn update_health_full(&self, battery_percent: u8, activity: u8)
pub fn update_health_full(&self, battery_percent: u8, activity: u8)
Update full health status (battery and activity)
Sourcepub fn build_document(&self) -> Vec<u8> ⓘ
pub fn build_document(&self) -> Vec<u8> ⓘ
Build current document for transmission
If encryption is enabled, the document is encrypted.
Sourcepub fn peers_needing_sync(&self, now_ms: u64) -> Vec<HivePeer>
pub fn peers_needing_sync(&self, now_ms: u64) -> Vec<HivePeer>
Get peers that should be synced with