use std::any::Any;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use agent_mesh_protocol::{AgentKey, Fingerprint, SignedEnvelope};
use async_trait::async_trait;
use tokio::io::{AsyncRead, AsyncWrite};
use tokio::sync::mpsc;
use tokio::sync::Mutex as AsyncMutex;
use crate::bus::PeerEndpoint;
use crate::{BusError, Result};
pub type ReplyRoute = Arc<dyn Any + Send + Sync>;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AuthenticatedPeer {
pub user_fp: Fingerprint,
pub agent_fp: Fingerprint,
}
impl AuthenticatedPeer {
#[must_use]
pub fn new(user_fp: Fingerprint, agent_fp: Fingerprint) -> Self {
Self { user_fp, agent_fp }
}
fn for_agent(agent: &AgentKey) -> Self {
Self::new(agent.cert().user_fingerprint(), agent.fingerprint())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum DeliveryProvenance {
Direct {
carrier: AuthenticatedPeer,
},
Unbound,
}
pub struct SessionStream {
pub send: Box<dyn AsyncWrite + Send + Sync + Unpin>,
pub recv: Box<dyn AsyncRead + Send + Sync + Unpin>,
pub live: agent_mesh_transport::LiveCheck,
}
pub struct Inbound {
pub envelope: SignedEnvelope,
pub provenance: DeliveryProvenance,
pub reply_route: ReplyRoute,
pub stream: Option<SessionStream>,
}
#[async_trait]
pub trait Transport: Send + Sync {
async fn send_to(&self, fp: Fingerprint, env: SignedEnvelope) -> Result<()>;
async fn send_to_endpoint(&self, peer: &PeerEndpoint, env: SignedEnvelope) -> Result<()>;
async fn send_request_to(
&self,
fp: Fingerprint,
env: SignedEnvelope,
window: std::time::Duration,
) -> Result<()> {
let _ = window;
self.send_to(fp, env).await
}
async fn send_request_to_endpoint(
&self,
peer: &PeerEndpoint,
env: SignedEnvelope,
window: std::time::Duration,
) -> Result<()> {
let _ = window;
self.send_to_endpoint(peer, env).await
}
async fn reply(&self, fp: Fingerprint, route: &ReplyRoute, env: SignedEnvelope) -> Result<()>;
async fn open_stream_to(&self, fp: Fingerprint) -> Result<(AuthenticatedPeer, SessionStream)> {
let _ = fp;
Err(no_sessions())
}
async fn open_stream_to_endpoint(
&self,
peer: &PeerEndpoint,
) -> Result<(AuthenticatedPeer, SessionStream)> {
let _ = peer;
Err(no_sessions())
}
async fn recv(&self) -> Option<Inbound>;
fn local_port(&self) -> u16;
async fn close(&self);
}
fn no_sessions() -> BusError {
BusError::TransportBackend("this transport carries no session streams".into())
}
#[derive(Default)]
pub struct MeshNet {
peers: Mutex<HashMap<Fingerprint, mpsc::UnboundedSender<Inbound>>>,
}
impl MeshNet {
#[must_use]
pub fn new() -> Arc<Self> {
Arc::new(Self::default())
}
pub fn transport_for(self: &Arc<Self>, agent: &AgentKey) -> InMemoryTransport {
let me = AuthenticatedPeer::for_agent(agent);
let (tx, rx) = mpsc::unbounded_channel();
self.peers.lock().unwrap().insert(me.agent_fp, tx);
InMemoryTransport {
me,
net: Arc::clone(self),
inbound: AsyncMutex::new(rx),
}
}
fn deliver(&self, to: Fingerprint, inbound: Inbound) -> Result<()> {
let peers = self.peers.lock().unwrap();
match peers.get(&to) {
Some(tx) => tx.send(inbound).map_err(|_| {
BusError::Unreachable(format!("in-memory peer {} has closed", to.short()))
}),
None => Err(BusError::Unreachable(format!(
"in-memory peer {} is not on the mesh",
to.short()
))),
}
}
fn remove(&self, me: &Fingerprint) {
self.peers.lock().unwrap().remove(me);
}
}
pub struct InMemoryTransport {
me: AuthenticatedPeer,
net: Arc<MeshNet>,
inbound: AsyncMutex<mpsc::UnboundedReceiver<Inbound>>,
}
impl InMemoryTransport {
fn push(&self, to: Fingerprint, env: SignedEnvelope) -> Result<()> {
self.net.deliver(
to,
Inbound {
envelope: env,
provenance: DeliveryProvenance::Direct { carrier: self.me },
reply_route: Arc::new(self.me.agent_fp),
stream: None,
},
)
}
}
#[async_trait]
impl Transport for InMemoryTransport {
async fn send_to(&self, fp: Fingerprint, env: SignedEnvelope) -> Result<()> {
self.push(fp, env)
}
async fn send_to_endpoint(&self, peer: &PeerEndpoint, env: SignedEnvelope) -> Result<()> {
self.push(peer.fingerprint(), env)
}
async fn reply(&self, fp: Fingerprint, _route: &ReplyRoute, env: SignedEnvelope) -> Result<()> {
self.push(fp, env)
}
async fn recv(&self) -> Option<Inbound> {
self.inbound.lock().await.recv().await
}
fn local_port(&self) -> u16 {
0
}
async fn close(&self) {
self.net.remove(&self.me.agent_fp);
}
}
#[cfg(test)]
mod tests {
use super::*;
use agent_mesh_protocol::{AgentKey, AgentMetadata, Caveats, Recipient, UserKey};
fn agent(user: &UserKey, role: &str) -> AgentKey {
AgentKey::issue(
user,
AgentMetadata {
role: role.into(),
host: "test".into(),
capabilities: vec!["test".into()],
issued_at: "2026-05-28T00:00:00Z".into(),
expires_at: None,
caveats: Caveats::top(),
},
)
}
fn envelope(from: &AgentKey, to: Fingerprint, body: &[u8]) -> SignedEnvelope {
SignedEnvelope::new(from, Recipient::Direct { agent_fp: to }, 1, body.to_vec())
}
#[tokio::test]
async fn send_delivers_and_reply_route_round_trips() {
let user = UserKey::generate();
let a = agent(&user, "a");
let b = agent(&user, "b");
let (a_fp, b_fp) = (a.fingerprint(), b.fingerprint());
let net = MeshNet::new();
let ta = net.transport_for(&a);
let tb = net.transport_for(&b);
ta.send_to(b_fp, envelope(&a, b_fp, b"hi")).await.unwrap();
let inbound = tb.recv().await.expect("b receives");
assert_eq!(inbound.envelope.sender_agent_fp(), a_fp);
assert_eq!(
inbound.provenance,
DeliveryProvenance::Direct {
carrier: AuthenticatedPeer::new(user.fingerprint(), a_fp),
},
"the in-memory carrier evidence must describe the sending leg"
);
tb.reply(a_fp, &inbound.reply_route, envelope(&b, a_fp, b"yo"))
.await
.unwrap();
let back = ta.recv().await.expect("a receives reply");
assert_eq!(back.envelope.sender_agent_fp(), b_fp);
}
#[tokio::test]
async fn send_to_endpoint_routes_by_fingerprint() {
let user = UserKey::generate();
let a = agent(&user, "a");
let b = agent(&user, "b");
let b_fp = b.fingerprint();
let net = MeshNet::new();
let ta = net.transport_for(&a);
let tb = net.transport_for(&b);
let peer = PeerEndpoint::new(b.public_bytes(), "127.0.0.1:1".parse().unwrap());
ta.send_to_endpoint(&peer, envelope(&a, b_fp, b"hi"))
.await
.unwrap();
assert!(tb.recv().await.is_some(), "endpoint send reaches b");
}
#[tokio::test]
async fn send_to_unregistered_peer_is_unreachable() {
let user = UserKey::generate();
let a = agent(&user, "a");
let net = MeshNet::new();
let ta = net.transport_for(&a);
let phantom = Fingerprint([0x11u8; 32]);
match ta.send_to(phantom, envelope(&a, phantom, b"x")).await {
Err(BusError::Unreachable(_)) => {}
other => panic!("expected Unreachable, got {other:?}"),
}
assert_eq!(ta.local_port(), 0);
}
#[tokio::test]
async fn a_closed_peer_no_longer_receives() {
let user = UserKey::generate();
let a = agent(&user, "a");
let b = agent(&user, "b");
let b_fp = b.fingerprint();
let net = MeshNet::new();
let ta = net.transport_for(&a);
let tb = net.transport_for(&b);
tb.close().await;
match ta.send_to(b_fp, envelope(&a, b_fp, b"x")).await {
Err(BusError::Unreachable(_)) => {}
other => panic!("expected Unreachable after close, got {other:?}"),
}
}
}