pub struct SelectiveRouter { /* private fields */ }Expand description
Selective router for hierarchical mesh networks
Makes intelligent routing decisions based on:
- Node’s position in hierarchy (level and role)
- Data direction (upward/downward/lateral)
- Topology state (selected peer, linked peers, lateral peers)
§Message Deduplication
The router can optionally track seen packet IDs to prevent routing loops.
Use new_with_deduplication() to enable this feature.
§Example
use peat_mesh::routing::{SelectiveRouter, DataPacket, DeduplicationConfig};
use peat_mesh::topology::TopologyState;
// Create router with deduplication enabled
let router = SelectiveRouter::new_with_deduplication(DeduplicationConfig::default());
let state = get_topology_state();
let packet = DataPacket::telemetry("node-123", vec![1, 2, 3]);
// Route will automatically deduplicate
let decision = router.route(&packet, &state, "this-node");
// Second call with same packet returns Drop (duplicate)
let decision2 = router.route(&packet, &state, "this-node");
assert_eq!(decision2, RoutingDecision::Drop);Implementations§
Source§impl SelectiveRouter
impl SelectiveRouter
Sourcepub fn new_verbose() -> Self
pub fn new_verbose() -> Self
Create a new selective router with verbose logging
Sourcepub fn new_with_deduplication(config: DeduplicationConfig) -> Self
pub fn new_with_deduplication(config: DeduplicationConfig) -> Self
Create a new selective router with deduplication enabled
Sourcepub fn dedup_cache_size(&self) -> usize
pub fn dedup_cache_size(&self) -> usize
Get the number of entries in the deduplication cache
Sourcepub fn clear_dedup_cache(&self)
pub fn clear_dedup_cache(&self)
Clear the deduplication cache
Sourcepub fn route(
&self,
packet: &DataPacket,
state: &TopologyState,
this_node_id: &str,
) -> RoutingDecision
pub fn route( &self, packet: &DataPacket, state: &TopologyState, this_node_id: &str, ) -> RoutingDecision
Make a complete routing decision for a packet
This is the primary entry point that combines should_consume, should_forward, and next_hop into a single decision.
If deduplication is enabled, duplicate packets are automatically dropped.
§Arguments
packet- The data packet to routestate- Current topology statethis_node_id- This node’s identifier
§Returns
RoutingDecision indicating what to do with the packet
Sourcepub fn should_consume(
&self,
packet: &DataPacket,
state: &TopologyState,
this_node_id: &str,
) -> bool
pub fn should_consume( &self, packet: &DataPacket, state: &TopologyState, this_node_id: &str, ) -> bool
Determine if this node should consume (process) the packet
§Consumption Rules
Upward (Telemetry)
- Always consume telemetry for local processing/aggregation
Downward (Commands)
- Consume if packet is addressed to us
- Leaders consume commands for their squad
Lateral (Coordination)
- Leaders consume coordination messages
- Members typically don’t consume lateral messages
§Arguments
packet- The data packetstate- Current topology statethis_node_id- This node’s identifier
§Returns
true if this node should process the packet
Sourcepub fn should_forward(&self, packet: &DataPacket, state: &TopologyState) -> bool
pub fn should_forward(&self, packet: &DataPacket, state: &TopologyState) -> bool
Determine if this node should forward the packet
§Forwarding Rules
Upward (Telemetry)
- Forward if we have a selected peer (parent in hierarchy)
- Don’t forward if we’re at HQ level (no parent)
Downward (Commands)
- Forward if we have linked peers (children) that need this data
- Don’t forward if we’re a leaf node (no children)
Lateral (Coordination)
- Forward if addressed to a lateral peer we track
- Leaders may forward to other Leaders at same level
§Arguments
packet- The data packetstate- Current topology state
§Returns
true if packet should be forwarded to another peer
Sourcepub fn next_hop(
&self,
packet: &DataPacket,
state: &TopologyState,
) -> Option<String>
pub fn next_hop( &self, packet: &DataPacket, state: &TopologyState, ) -> Option<String>
Determine the next hop for forwarding the packet
§Next Hop Selection
Upward: selected_peer (parent in hierarchy) Downward: linked_peers (children) - for now, return first child Lateral: lateral_peers - specific peer if addressed, or first if broadcast
§Arguments
packet- The data packetstate- Current topology state
§Returns
Node ID of the next hop, or None if no valid next hop
Sourcepub fn next_hops(
&self,
packet: &DataPacket,
state: &TopologyState,
) -> Vec<String>
pub fn next_hops( &self, packet: &DataPacket, state: &TopologyState, ) -> Vec<String>
Determine all next hops for multicast/broadcast forwarding
Returns all appropriate peers for scenarios requiring multicast:
- Downward command dissemination to all children
- Lateral coordination broadcast to all peers at same level
§Next Hops Selection
Upward: Returns selected_peer (parent) as single-element vector Downward: Returns all linked_peers (children) for broadcast Lateral: Returns all lateral_peers for broadcast
§Arguments
packet- The data packetstate- Current topology state
§Returns
Vector of node IDs to forward to (empty if no valid hops)
Sourcepub fn should_aggregate(
&self,
packet: &DataPacket,
decision: &RoutingDecision,
state: &TopologyState,
) -> bool
pub fn should_aggregate( &self, packet: &DataPacket, decision: &RoutingDecision, state: &TopologyState, ) -> bool
Check if a packet should be aggregated before forwarding
Aggregation is appropriate when:
- Packet data type requires aggregation (Telemetry, Status)
- Routing decision is ConsumeAndForward (intermediate node)
- Node is a Leader (squad leader aggregating member data)
§Integration with Aggregator
When this returns true, the application should:
- Collect telemetry packets from squad members (batching)
- Use
Aggregator::aggregate_telemetry()to create aggregated packet - Route the aggregated packet upward using this router
§Example
use peat_mesh::routing::{SelectiveRouter, Aggregator, DataPacket};
let router = SelectiveRouter::new();
// let aggregator = MyAggregator::new();
// Collect telemetry from squad members
let mut squad_telemetry = Vec::new();
for packet in incoming_packets {
let decision = router.route(&packet, &state, "platoon-leader");
if router.should_aggregate(&packet, &decision, &state) {
squad_telemetry.push(packet);
}
}
// Aggregate when we have enough data
if squad_telemetry.len() >= 3 {
let aggregated = aggregator.aggregate_telemetry(
"squad-1",
"platoon-leader",
squad_telemetry,
)?;
// Route aggregated packet upward
let decision = router.route(&aggregated, &state, "platoon-leader");
// ... forward to parent
}§Arguments
packet- The data packet to checkdecision- The routing decision for this packetstate- Current topology state
§Returns
true if this packet should be aggregated before forwarding