Skip to main content

brainwires_network/routing/
direct.rs

1use anyhow::{Result, bail};
2use async_trait::async_trait;
3
4use super::peer_table::PeerTable;
5use super::traits::{Router, RoutingStrategy};
6use crate::network::{MessageEnvelope, MessageTarget};
7use crate::transport::TransportAddress;
8
9/// Point-to-point router.
10///
11/// Looks up the recipient UUID in the peer table and returns its
12/// transport addresses. Fails if the recipient is unknown.
13#[derive(Debug, Default)]
14pub struct DirectRouter;
15
16impl DirectRouter {
17    /// Create a new direct router.
18    pub fn new() -> Self {
19        Self
20    }
21}
22
23#[async_trait]
24impl Router for DirectRouter {
25    async fn route(
26        &self,
27        envelope: &MessageEnvelope,
28        peers: &PeerTable,
29    ) -> Result<Vec<TransportAddress>> {
30        match &envelope.recipient {
31            MessageTarget::Direct(id) => peers
32                .addresses(id)
33                .map(|addrs| addrs.to_vec())
34                .ok_or_else(|| anyhow::anyhow!("no route to peer {id}")),
35            MessageTarget::Broadcast => {
36                bail!("DirectRouter does not handle broadcast messages");
37            }
38            MessageTarget::Topic(_) => {
39                bail!("DirectRouter does not handle topic messages");
40            }
41        }
42    }
43
44    fn strategy(&self) -> RoutingStrategy {
45        RoutingStrategy::Direct
46    }
47}
48
49#[cfg(test)]
50mod tests {
51    use super::*;
52    use crate::identity::AgentIdentity;
53    use crate::network::Payload;
54    use uuid::Uuid;
55
56    #[tokio::test]
57    async fn direct_routes_to_known_peer() {
58        let router = DirectRouter::new();
59        let mut peers = PeerTable::new();
60
61        let identity = AgentIdentity::new("target");
62        let target_id = identity.id;
63        let addr = TransportAddress::Tcp("127.0.0.1:9090".parse().unwrap());
64        peers.upsert(identity, vec![addr.clone()]);
65
66        let env = MessageEnvelope::direct(Uuid::new_v4(), target_id, Payload::Text("hello".into()));
67
68        let addrs = router.route(&env, &peers).await.unwrap();
69        assert_eq!(addrs, vec![addr]);
70    }
71
72    #[tokio::test]
73    async fn direct_fails_for_unknown_peer() {
74        let router = DirectRouter::new();
75        let peers = PeerTable::new();
76
77        let env = MessageEnvelope::direct(
78            Uuid::new_v4(),
79            Uuid::new_v4(),
80            Payload::Text("hello".into()),
81        );
82
83        let result = router.route(&env, &peers).await;
84        assert!(result.is_err());
85    }
86
87    #[tokio::test]
88    async fn direct_rejects_broadcast() {
89        let router = DirectRouter::new();
90        let peers = PeerTable::new();
91
92        let env = MessageEnvelope::broadcast(Uuid::new_v4(), Payload::Text("hello".into()));
93        let result = router.route(&env, &peers).await;
94        assert!(result.is_err());
95    }
96}