Skip to main content

SelectiveRouter

Struct SelectiveRouter 

Source
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

Source

pub fn new() -> Self

Create a new selective router (deduplication disabled by default)

Source

pub fn new_verbose() -> Self

Create a new selective router with verbose logging

Source

pub fn new_with_deduplication(config: DeduplicationConfig) -> Self

Create a new selective router with deduplication enabled

Source

pub fn dedup_cache_size(&self) -> usize

Get the number of entries in the deduplication cache

Source

pub fn clear_dedup_cache(&self)

Clear the deduplication cache

Source

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 route
  • state - Current topology state
  • this_node_id - This node’s identifier
§Returns

RoutingDecision indicating what to do with the packet

Source

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 packet
  • state - Current topology state
  • this_node_id - This node’s identifier
§Returns

true if this node should process the packet

Source

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 packet
  • state - Current topology state
§Returns

true if packet should be forwarded to another peer

Source

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 packet
  • state - Current topology state
§Returns

Node ID of the next hop, or None if no valid next hop

Source

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 packet
  • state - Current topology state
§Returns

Vector of node IDs to forward to (empty if no valid hops)

Source

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:

  1. Collect telemetry packets from squad members (batching)
  2. Use Aggregator::aggregate_telemetry() to create aggregated packet
  3. 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 check
  • decision - The routing decision for this packet
  • state - Current topology state
§Returns

true if this packet should be aggregated before forwarding

Trait Implementations§

Source§

impl Default for SelectiveRouter

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

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> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more