use std::sync::Arc;
use futures::Stream;
use ruststream::testing::Coordinator;
use ruststream::{AckError, Headers, IncomingMessage, Subscriber};
use super::broker::TestBrokerState;
use super::router::{DeliveryReceiver, DeliverySender, SubscriptionId, TestDelivery};
use crate::error::AmqpError;
pub struct LapinTestSubscriber {
state: Arc<TestBrokerState>,
id: SubscriptionId,
queue: String,
sender: DeliverySender,
receiver: DeliveryReceiver,
coordinator: Option<Coordinator>,
}
impl LapinTestSubscriber {
pub(crate) fn open(state: &Arc<TestBrokerState>, queue: String) -> Self {
let (id, sender, receiver) = state.router.subscribe(queue.clone());
let coordinator = state.coordinator();
Self {
state: Arc::clone(state),
id,
queue,
sender,
receiver,
coordinator,
}
}
#[must_use]
pub fn queue(&self) -> &str {
&self.queue
}
}
impl Drop for LapinTestSubscriber {
fn drop(&mut self) {
self.state.router.unsubscribe(self.id);
}
}
impl std::fmt::Debug for LapinTestSubscriber {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("LapinTestSubscriber")
.field("queue", &self.queue)
.finish_non_exhaustive()
}
}
impl Subscriber for LapinTestSubscriber {
type Message = LapinTestMessage;
type Error = AmqpError;
fn stream(&mut self) -> impl Stream<Item = Result<Self::Message, Self::Error>> + Send + '_ {
let Self {
receiver,
sender,
coordinator,
..
} = self;
futures::stream::poll_fn(move |cx| {
receiver.poll_recv(cx).map(|delivery| {
delivery.map(|delivery| {
Ok(LapinTestMessage {
delivery: Some(delivery),
sender: sender.clone(),
coordinator: coordinator.clone(),
})
})
})
})
}
}
pub struct LapinTestMessage {
delivery: Option<TestDelivery>,
sender: DeliverySender,
coordinator: Option<Coordinator>,
}
impl LapinTestMessage {
fn take(&mut self) -> TestDelivery {
self.delivery
.take()
.expect("LapinTestMessage settled twice")
}
}
impl Drop for LapinTestMessage {
fn drop(&mut self) {
if let Some(coordinator) = self.coordinator.take() {
coordinator.consumed();
}
}
}
impl std::fmt::Debug for LapinTestMessage {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("LapinTestMessage")
.field("delivery", &self.delivery)
.finish_non_exhaustive()
}
}
impl IncomingMessage for LapinTestMessage {
fn payload(&self) -> &[u8] {
&self
.delivery
.as_ref()
.expect("message accessed after settlement")
.payload
}
fn headers(&self) -> &Headers {
&self
.delivery
.as_ref()
.expect("message accessed after settlement")
.headers
}
async fn ack(mut self) -> Result<(), AckError> {
drop(self.take());
Ok(())
}
async fn nack(mut self, requeue: bool) -> Result<(), AckError> {
let delivery = self.take();
if requeue && self.sender.send(delivery).is_ok() {
if let Some(coordinator) = &self.coordinator {
coordinator.enqueued();
}
}
Ok(())
}
}