use std::path::Path;
use std::sync::Arc;
use tokio::sync::broadcast;
use crate::daemon::audit::{AuditLogger, BUS_STREAM};
pub mod envelope;
pub mod error;
pub mod registry;
pub mod routes;
#[cfg(test)]
mod tests;
pub use envelope::{
BusEdge, BusEnvelope, BusPayload, CallerIdentity, CallerKind, ChannelOrigin, DeliveryState,
Recipient,
};
pub use error::BusError;
pub use registry::{InstanceMeta, InstanceRegistry, LiveInstance, PeerTarget};
#[derive(Debug)]
pub struct PeerBus {
registry: InstanceRegistry,
audit: AuditLogger,
}
impl PeerBus {
pub fn new(logs_dir: &Path) -> Self {
Self {
registry: InstanceRegistry::default(),
audit: AuditLogger::for_stream(logs_dir, BUS_STREAM),
}
}
pub fn registry(&self) -> &InstanceRegistry {
&self.registry
}
pub fn log_path(&self) -> &Path {
self.audit.path()
}
pub fn subscribe(
&self,
instance_id: &str,
) -> Result<broadcast::Receiver<BusEnvelope>, BusError> {
Ok(self.registry.resolve_instance(instance_id)?.tx.subscribe())
}
fn verified_sender(&self, mut from: CallerIdentity) -> Result<CallerIdentity, BusError> {
let claimed = from.instance_id.clone().ok_or_else(|| {
BusError::InvalidCaller("peer sender requires instance_id (DOC-60 §6c)".into())
})?;
let live =
self.registry
.resolve_instance(&claimed)
.map_err(|_| BusError::UnregisteredSender {
instance_id: claimed,
})?;
from.definition_id = Some(live.meta.definition_id);
Ok(from)
}
pub fn publish(
&self,
from: CallerIdentity,
target: &PeerTarget,
payload: BusPayload,
in_reply_to: Option<String>,
) -> Result<BusEnvelope, BusError> {
from.validate()?;
let edge = from.kind.peer_edge()?;
let from = self.verified_sender(from)?;
let live = match self.registry.resolve(target) {
Ok(live) => live,
Err(e) => {
let to = match target {
PeerTarget::Definition(d) => Recipient {
instance_id: None,
definition_id: Some(d.clone()),
},
PeerTarget::Instance(i) => Recipient {
instance_id: Some(i.clone()),
definition_id: None,
},
};
self.audit.log_record(&BusEnvelope::new(
edge,
from,
to,
payload,
in_reply_to,
DeliveryState::Dropped,
));
return Err(e);
}
};
let mut envelope = BusEnvelope::new(
edge,
from,
Recipient {
instance_id: Some(live.meta.instance_id.clone()),
definition_id: Some(live.meta.definition_id.clone()),
},
payload,
in_reply_to,
DeliveryState::Delivered,
);
if live.tx.send(envelope.clone()).is_err() {
envelope.delivery_state = DeliveryState::Dropped;
self.audit.log_record(&envelope);
return Err(BusError::NoSubscriber {
instance_id: live.meta.instance_id,
});
}
self.audit.log_record(&envelope);
Ok(envelope)
}
}
pub type SharedBus = Arc<PeerBus>;