use std::sync::OnceLock;
use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
use ruststream::RawMessage;
use ruststream::testing::Coordinator;
use super::router::{AddressRouter, Delivery, DeliveryReceiver, SubscriptionId};
use crate::address::Routing;
use crate::error::AmqpError;
#[derive(Debug, Default)]
pub(crate) struct Bus {
router: AddressRouter,
coordinator: OnceLock<Coordinator>,
closed: AtomicBool,
reply_seq: AtomicU64,
}
impl Bus {
pub(crate) fn coordinator(&self) -> Option<&Coordinator> {
self.coordinator.get()
}
pub(crate) fn install(&self, coordinator: Coordinator) {
let _ = self.coordinator.set(coordinator);
}
pub(crate) fn ensure_live(&self) -> Result<(), AmqpError> {
if self.closed.load(Ordering::Acquire) {
return Err(AmqpError::NotConnected);
}
Ok(())
}
pub(crate) fn is_closed(&self) -> bool {
self.closed.load(Ordering::Acquire)
}
pub(crate) fn close(&self) {
self.closed.store(true, Ordering::Release);
self.router.close();
}
pub(crate) fn subscribe(
&self,
address: String,
routing: Routing,
) -> Result<(SubscriptionId, DeliveryReceiver), AmqpError> {
self.router
.subscribe(address, routing, self.coordinator())
.ok_or(AmqpError::NotConnected)
}
pub(crate) fn termini(&self, address: &str) -> (usize, usize) {
self.router.termini(address)
}
pub(crate) fn recipients(&self, address: &str) -> Vec<bool> {
self.router.recipients(address)
}
pub(crate) fn unsubscribe(&self, id: SubscriptionId, pending: Vec<Delivery>) {
self.router.unsubscribe(id, pending, self.coordinator());
}
pub(crate) fn release(&self, id: SubscriptionId, address: &str, delivery: Delivery) {
self.router
.release(id, address, delivery, self.coordinator());
}
pub(crate) fn route(&self, address: &str, delivery: &Delivery) -> Result<(), AmqpError> {
if self.router.publish(address, delivery, self.coordinator()) {
Ok(())
} else {
Err(AmqpError::NotConnected)
}
}
pub(crate) fn requeue(
&self,
id: SubscriptionId,
address: &str,
delivery: Delivery,
) -> Result<(), AmqpError> {
if self
.router
.requeue(id, address, delivery, self.coordinator())
{
Ok(())
} else {
Err(AmqpError::NotConnected)
}
}
pub(crate) fn route_all(&self, messages: &[(String, Delivery)]) -> Result<(), AmqpError> {
let messages = messages
.iter()
.map(|(address, delivery)| (address.as_str(), delivery));
if self.router.publish_all(messages, self.coordinator()) {
Ok(())
} else {
Err(AmqpError::NotConnected)
}
}
pub(crate) fn published(&self, address: &str) -> Vec<RawMessage> {
self.router.published(address)
}
pub(crate) fn next_reply_address(&self) -> String {
let seq = self.reply_seq.fetch_add(1, Ordering::Relaxed);
format!("in-process-reply-{seq}")
}
}