use anyhow::Result;
use async_trait::async_trait;
use super::peer_table::PeerTable;
use super::traits::{Router, RoutingStrategy};
use crate::network::MessageEnvelope;
use crate::transport::TransportAddress;
#[derive(Debug, Default)]
pub struct BroadcastRouter;
impl BroadcastRouter {
pub fn new() -> Self {
Self
}
}
#[async_trait]
impl Router for BroadcastRouter {
async fn route(
&self,
envelope: &MessageEnvelope,
peers: &PeerTable,
) -> Result<Vec<TransportAddress>> {
let mut addrs = Vec::new();
for peer_id in peers.all_peer_ids() {
if *peer_id == envelope.sender {
continue;
}
if let Some(peer_addrs) = peers.addresses(peer_id) {
addrs.extend_from_slice(peer_addrs);
}
}
Ok(addrs)
}
fn strategy(&self) -> RoutingStrategy {
RoutingStrategy::Broadcast
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::identity::AgentIdentity;
use crate::network::Payload;
use uuid::Uuid;
#[tokio::test]
async fn broadcast_reaches_all_except_sender() {
let router = BroadcastRouter::new();
let mut peers = PeerTable::new();
let sender = AgentIdentity::new("sender");
let sender_id = sender.id;
let peer_a = AgentIdentity::new("a");
let peer_b = AgentIdentity::new("b");
peers.upsert(
sender,
vec![TransportAddress::Tcp("127.0.0.1:1000".parse().unwrap())],
);
peers.upsert(
peer_a,
vec![TransportAddress::Tcp("127.0.0.1:2000".parse().unwrap())],
);
peers.upsert(
peer_b,
vec![TransportAddress::Tcp("127.0.0.1:3000".parse().unwrap())],
);
let env = MessageEnvelope::broadcast(sender_id, Payload::Text("ping".into()));
let addrs = router.route(&env, &peers).await.unwrap();
assert_eq!(addrs.len(), 2);
assert!(!addrs.contains(&TransportAddress::Tcp("127.0.0.1:1000".parse().unwrap())));
}
#[tokio::test]
async fn broadcast_empty_peers() {
let router = BroadcastRouter::new();
let peers = PeerTable::new();
let env = MessageEnvelope::broadcast(Uuid::new_v4(), Payload::Text("ping".into()));
let addrs = router.route(&env, &peers).await.unwrap();
assert!(addrs.is_empty());
}
}