2026-06-11 10:08:07 +02:00
|
|
|
use crate::{AddressedEnvelope, DeliveryService, Transport};
|
|
|
|
|
use crossbeam_channel::{Receiver, Sender, unbounded};
|
2026-04-08 23:15:48 +02:00
|
|
|
use std::collections::HashMap;
|
|
|
|
|
use std::convert::Infallible;
|
2026-06-11 10:08:07 +02:00
|
|
|
use std::sync::{Arc, Mutex};
|
2026-04-08 23:15:48 +02:00
|
|
|
|
|
|
|
|
type Message = Vec<u8>;
|
|
|
|
|
|
2026-06-11 10:08:07 +02:00
|
|
|
/// Shared in-process message bus. Cheap to clone — all clones share one routing
|
|
|
|
|
/// table. On `publish`, a message is fanned out to every endpoint subscribed to
|
|
|
|
|
/// its delivery address.
|
2026-05-19 11:54:54 -07:00
|
|
|
#[derive(Clone, Default, Debug)]
|
2026-04-08 23:15:48 +02:00
|
|
|
pub struct MessageBus {
|
2026-06-11 10:08:07 +02:00
|
|
|
routes: Arc<Mutex<HashMap<String, Vec<Sender<Message>>>>>,
|
2026-04-08 23:15:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl MessageBus {
|
2026-06-11 10:08:07 +02:00
|
|
|
fn register(&self, address: &str, sender: Sender<Message>) {
|
|
|
|
|
let mut routes = self.routes.lock().unwrap();
|
|
|
|
|
let senders = routes.entry(address.to_string()).or_default();
|
|
|
|
|
// Idempotent per endpoint: the core re-subscribes an address whenever it
|
|
|
|
|
// rebuilds a conversation, so skip senders already registered for it —
|
|
|
|
|
// otherwise each payload reaches that endpoint more than once.
|
|
|
|
|
if senders.iter().any(|s| s.same_channel(&sender)) {
|
|
|
|
|
return;
|
2026-04-08 23:15:48 +02:00
|
|
|
}
|
2026-06-11 10:08:07 +02:00
|
|
|
senders.push(sender);
|
2026-04-08 23:15:48 +02:00
|
|
|
}
|
|
|
|
|
|
2026-06-11 10:08:07 +02:00
|
|
|
fn publish(&self, address: &str, data: Message) {
|
|
|
|
|
if let Some(senders) = self.routes.lock().unwrap().get_mut(address) {
|
|
|
|
|
// Prune endpoints whose receiver was dropped: a disconnected endpoint
|
|
|
|
|
// is harmless, but keeping its sender would leak it in `routes`.
|
|
|
|
|
senders.retain(|tx| tx.send(data.clone()).is_ok());
|
2026-04-08 23:15:48 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-11 10:08:07 +02:00
|
|
|
/// One client's endpoint onto a shared [`MessageBus`].
|
2026-04-08 23:15:48 +02:00
|
|
|
///
|
2026-06-11 10:08:07 +02:00
|
|
|
/// `publish` fans the message out through the bus; `subscribe` registers this
|
|
|
|
|
/// endpoint's inbound sender for an address, so subsequent publishes to it are
|
|
|
|
|
/// delivered. The client obtains the inbound stream via [`Transport::inbound`].
|
|
|
|
|
#[derive(Debug)]
|
|
|
|
|
pub struct InProcessDelivery {
|
2026-04-08 23:15:48 +02:00
|
|
|
bus: MessageBus,
|
2026-06-11 10:08:07 +02:00
|
|
|
inbound_tx: Sender<Message>,
|
|
|
|
|
inbound_rx: Option<Receiver<Message>>,
|
2026-04-08 23:15:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl InProcessDelivery {
|
2026-06-11 10:08:07 +02:00
|
|
|
/// Create an endpoint on `bus`.
|
2026-04-08 23:15:48 +02:00
|
|
|
pub fn new(bus: MessageBus) -> Self {
|
2026-06-11 10:08:07 +02:00
|
|
|
let (tx, rx) = unbounded();
|
|
|
|
|
Self {
|
|
|
|
|
bus,
|
|
|
|
|
inbound_tx: tx,
|
|
|
|
|
inbound_rx: Some(rx),
|
|
|
|
|
}
|
2026-04-08 23:15:48 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl DeliveryService for InProcessDelivery {
|
|
|
|
|
type Error = Infallible;
|
|
|
|
|
|
|
|
|
|
fn publish(&mut self, envelope: AddressedEnvelope) -> Result<(), Infallible> {
|
2026-06-11 10:08:07 +02:00
|
|
|
self.bus.publish(&envelope.delivery_address, envelope.data);
|
2026-04-08 23:15:48 +02:00
|
|
|
Ok(())
|
|
|
|
|
}
|
2026-05-19 11:54:54 -07:00
|
|
|
|
2026-06-11 10:08:07 +02:00
|
|
|
fn subscribe(&mut self, delivery_address: &str) -> Result<(), Self::Error> {
|
|
|
|
|
self.bus.register(delivery_address, self.inbound_tx.clone());
|
2026-05-19 11:54:54 -07:00
|
|
|
Ok(())
|
|
|
|
|
}
|
2026-04-08 23:15:48 +02:00
|
|
|
}
|
2026-06-11 10:08:07 +02:00
|
|
|
|
|
|
|
|
impl Transport for InProcessDelivery {
|
|
|
|
|
fn inbound(&mut self) -> Receiver<Vec<u8>> {
|
|
|
|
|
self.inbound_rx
|
|
|
|
|
.take()
|
|
|
|
|
.expect("InProcessDelivery::inbound called more than once")
|
|
|
|
|
}
|
|
|
|
|
}
|