HiveMesh

Struct HiveMesh 

Source
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

Source

pub fn new(config: HiveMeshConfig) -> Self

Create a new HiveMesh instance

Source

pub fn is_encryption_enabled(&self) -> bool

Check if mesh-wide encryption is enabled

Source

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.

Source

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.

Source

pub fn disable_encryption(&mut self)

Disable mesh-wide encryption

Source

pub fn is_relay_enabled(&self) -> bool

Check if multi-hop relay is enabled

Source

pub fn enable_relay(&mut self)

Enable multi-hop relay

Source

pub fn disable_relay(&mut self)

Disable multi-hop relay

Source

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).

Source

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).

Source

pub fn seen_cache_size(&self) -> usize

Get the number of entries in the seen message cache

Source

pub fn clear_seen_cache(&self)

Clear the seen message cache

Source

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.

Source

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.

Source

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/relayed
  • Ok(None) if message was a duplicate or TTL expired
  • Err if parsing failed
Source

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.

Source

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).

Source

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.

Source

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.

Source

pub fn record_delta_sent(&self, peer_id: &NodeId, bytes: usize)

Record bytes sent to a peer (for delta statistics)

Source

pub fn record_delta_received( &self, peer_id: &NodeId, bytes: usize, timestamp: u64, )

Record bytes received from a peer (for delta statistics)

Source

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.

Source

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.

Source

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.

Source

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.

Source

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).

Source

pub fn disable_peer_e2ee(&self)

Disable per-peer E2EE capability

Clears all peer sessions and disables E2EE.

Source

pub fn is_peer_e2ee_enabled(&self) -> bool

Check if per-peer E2EE is enabled

Source

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.

Source

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.

Source

pub fn has_peer_e2ee_session(&self, peer_node_id: NodeId) -> bool

Check if we have an established E2EE session with a peer

Source

pub fn peer_e2ee_session_state( &self, peer_node_id: NodeId, ) -> Option<SessionState>

Get E2EE session state with a peer

Source

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).

Source

pub fn close_peer_e2ee(&self, peer_node_id: NodeId)

Close E2EE session with a peer

Source

pub fn peer_e2ee_session_count(&self) -> usize

Get count of active E2EE sessions

Source

pub fn peer_e2ee_established_count(&self) -> usize

Get count of established E2EE sessions

Source

pub fn node_id(&self) -> NodeId

Get our node ID

Source

pub fn callsign(&self) -> &str

Get our callsign

Source

pub fn mesh_id(&self) -> &str

Get the mesh ID

Source

pub fn device_name(&self) -> String

Get the device name for BLE advertising

Source

pub fn add_observer(&self, observer: Arc<dyn HiveObserver>)

Add an observer for mesh events

Source

pub fn remove_observer(&self, observer: &Arc<dyn HiveObserver>)

Remove an observer

Source

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.

Source

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.

Source

pub fn clear_event(&self)

Clear the current event (emergency or ack)

Source

pub fn is_emergency_active(&self) -> bool

Check if emergency is active

Source

pub fn is_ack_active(&self) -> bool

Check if ACK is active

Source

pub fn current_event(&self) -> Option<EventType>

Get current event type

Source

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.

Source

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.

Source

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.

Source

pub fn clear_emergency(&self)

Clear the current emergency event

Source

pub fn has_active_emergency(&self) -> bool

Check if there’s an active emergency

Source

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.

Source

pub fn has_peer_acked(&self, peer_id: u32) -> bool

Check if a specific peer has ACKed the current emergency

Source

pub fn all_peers_acked(&self) -> bool

Check if all peers have ACKed the current emergency

Source

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.

Source

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.

Source

pub fn chat_count(&self) -> usize

Get the number of chat messages in the local CRDT

Source

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.

Source

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.

Source

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.

Source

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.

Source

pub fn on_ble_disconnected( &self, identifier: &str, reason: DisconnectReason, ) -> Option<NodeId>

Called when a BLE connection is lost

Source

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).

Source

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.

Source

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.

Source

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.

Source

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.

Source

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.

Source

pub fn get_peers(&self) -> Vec<HivePeer>

Get all known peers

Source

pub fn get_connected_peers(&self) -> Vec<HivePeer>

Get connected peers only

Source

pub fn get_peer(&self, node_id: NodeId) -> Option<HivePeer>

Get a specific peer by NodeId

Source

pub fn peer_count(&self) -> usize

Get peer count

Source

pub fn connected_count(&self) -> usize

Get connected peer count

Source

pub fn matches_mesh(&self, device_mesh_id: Option<&str>) -> bool

Check if a device mesh ID matches our mesh

Source

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),
        _ => {}
    }
}
Source

pub fn get_peer_connection_state( &self, node_id: NodeId, ) -> Option<PeerConnectionState>

Get a specific peer’s connection state

Source

pub fn get_connected_states(&self) -> Vec<PeerConnectionState>

Get all currently connected peers from the connection graph

Source

pub fn get_degraded_peers(&self) -> Vec<PeerConnectionState>

Get peers in degraded state (connected but poor signal quality)

Source

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.

Source

pub fn get_lost_peers(&self) -> Vec<PeerConnectionState>

Get peers in Lost state (disconnected and no longer advertising)

Source

pub fn get_connection_state_counts(&self) -> StateCountSummary

Get summary counts of peers in each connection state

Source

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.

Source

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 peers
  • Some(PeerDegree::OneHop/TwoHop/ThreeHop) for indirect peers
  • None if peer is not known
Source

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).

Source

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.

Source

pub fn is_peer_known(&self, node_id: NodeId) -> bool

Check if a node is known (either direct or indirect)

Source

pub fn indirect_peer_count(&self) -> usize

Get number of indirect peers

Source

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.

Source

pub fn total_count(&self) -> u64

Get total counter value

Source

pub fn document_version(&self) -> u32

Get document version

Source

pub fn version(&self) -> u32

Get document version (alias)

Source

pub fn update_health(&self, battery_percent: u8)

Update health status (battery percentage)

Source

pub fn update_activity(&self, activity: u8)

Update activity level (0=still, 1=walking, 2=running, 3=fall)

Source

pub fn update_health_full(&self, battery_percent: u8, activity: u8)

Update full health status (battery and activity)

Source

pub fn build_document(&self) -> Vec<u8>

Build current document for transmission

If encryption is enabled, the document is encrypted.

Source

pub fn peers_needing_sync(&self, now_ms: u64) -> Vec<HivePeer>

Get peers that should be synced with

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.