use std::mem;
use std::sync::Arc;
use std::task::{Context, Poll};
use std::time::Duration;
use bytes::Bytes;
use ruststream::testing::Coordinator;
use ruststream::{AckError, HeaderMap};
use tokio::time::sleep;
use crate::error::PulsarError;
use crate::in_process::bus::Bus;
use crate::in_process::route::Route;
use crate::in_process::router::{ConsumerId, Delivery};
use crate::in_process::seek::LogSeeker;
use crate::message::PulsarMessage;
use crate::subscriber::PulsarSeeker;
#[derive(Debug)]
pub(crate) struct Queued {
bus: Arc<Bus>,
id: ConsumerId,
route: Route,
coordinator: Option<Coordinator>,
ack_timeout: Option<Duration>,
}
impl Queued {
pub(crate) fn new(
bus: Arc<Bus>,
id: ConsumerId,
route: Route,
ack_timeout: Option<Duration>,
) -> Self {
let coordinator = bus.coordinator().cloned();
Self {
bus,
id,
route,
coordinator,
ack_timeout,
}
}
pub(crate) fn poll_next(
&self,
cx: &Context<'_>,
) -> Poll<Option<Result<PulsarMessage, PulsarError>>> {
self.bus.router().poll_delivery(self.id, cx).map(|next| {
next.map(|delivery| {
let named = self.route.named(&delivery.topic).to_owned();
let settlement = Settlement {
bus: Arc::clone(&self.bus),
id: self.id,
seq: delivery.seq,
topic: delivery.topic.clone(),
redeliveries: delivery.redeliveries,
coordinator: self.coordinator.clone(),
unsettled: Some(delivery.clone()),
};
Ok(PulsarMessage::in_process(
delivery,
named,
settlement,
self.ack_timeout,
))
})
})
}
pub(crate) fn seeker(&self) -> PulsarSeeker {
PulsarSeeker::in_process(LogSeeker::new(
Arc::clone(&self.bus),
self.id,
self.coordinator.clone(),
))
}
}
impl Drop for Queued {
fn drop(&mut self) {
self.bus
.router()
.unsubscribe(self.id, self.coordinator.as_ref());
}
}
#[derive(Debug)]
pub(crate) struct Settlement {
bus: Arc<Bus>,
id: ConsumerId,
seq: usize,
topic: String,
redeliveries: u32,
coordinator: Option<Coordinator>,
unsettled: Option<Delivery>,
}
impl Drop for Settlement {
fn drop(&mut self) {
if let Some(delivery) = self.unsettled.take() {
self.bus
.router()
.hold(self.id, delivery, self.coordinator.as_ref());
}
if let Some(coordinator) = &self.coordinator {
coordinator.consumed();
}
}
}
impl Settlement {
pub(crate) fn settle(mut self) {
self.unsettled = None;
}
pub(crate) const fn seq(&self) -> usize {
self.seq
}
pub(crate) fn seeker(&self) -> PulsarSeeker {
PulsarSeeker::in_process(LogSeeker::new(
Arc::clone(&self.bus),
self.id,
self.coordinator.clone(),
))
}
fn delivery(&mut self, payload: Bytes, headers: HeaderMap) -> Delivery {
Delivery {
payload,
headers,
seq: self.seq,
topic: mem::take(&mut self.topic),
redeliveries: self.redeliveries,
}
}
pub(crate) fn requeue(mut self, payload: Bytes, headers: HeaderMap) -> Result<(), AckError> {
self.unsettled = None;
let delivery = self.delivery(payload, headers);
let queued = self
.bus
.router()
.requeue(self.id, delivery, self.coordinator.as_ref())
.ok_or_else(consumer_gone)?;
if queued && let Some(coordinator) = &self.coordinator {
coordinator.enqueued();
}
Ok(())
}
pub(crate) fn nack_after(
mut self,
delay: Duration,
payload: Bytes,
headers: HeaderMap,
) -> Result<(), AckError> {
if !self.bus.router().settles(self.id) {
return Err(consumer_gone());
}
self.unsettled = None;
let delivery = self.delivery(payload, headers);
let bus = Arc::clone(&self.bus);
let id = self.id;
if let Some(coordinator) = self.coordinator.clone() {
let counter = coordinator.clone();
coordinator.schedule_redelivery(delay, move || {
if bus.router().requeue(id, delivery, Some(&counter)) == Some(true) {
counter.enqueued();
}
});
return Ok(());
}
self.bus.runtime().spawn(async move {
sleep(delay).await;
bus.router().requeue(id, delivery, None);
});
Ok(())
}
}
fn consumer_gone() -> AckError {
AckError::Broker(Box::from(
"the broker shut down, so the delivery cannot be handed back",
))
}