use std::sync::Arc;
use std::task::{Context, Poll};
use std::time::Duration;
use super::project::{ConsumerId, HandedReceiver, Pending, Project};
use crate::error::PubSubError;
use crate::message::PubSubMessage;
use crate::subscription::DeliveryLimits;
pub(crate) struct Consumer {
project: Arc<Project>,
subscription: Arc<str>,
id: ConsumerId,
receiver: HandedReceiver,
limits: DeliveryLimits,
}
impl Consumer {
pub(super) fn new(
project: Arc<Project>,
subscription: Arc<str>,
id: ConsumerId,
receiver: HandedReceiver,
limits: DeliveryLimits,
) -> Self {
Self {
project,
subscription,
id,
receiver,
limits,
}
}
pub(crate) fn poll_next(
&mut self,
cx: &mut Context<'_>,
) -> Poll<Option<Result<PubSubMessage, PubSubError>>> {
self.receiver.poll_recv(cx).map(|handed| {
handed.map(|handed| {
let reported = self
.project
.reported_attempt(&self.subscription, handed.pending.attempt);
let message = handed.pending.message.clone();
Ok(PubSubMessage::in_process(
message,
Settlement {
project: Arc::clone(&self.project),
subscription: Arc::clone(&self.subscription),
pending: Some(handed.pending),
reported,
counted: handed.counted,
},
self.limits,
))
})
})
}
}
impl Drop for Consumer {
fn drop(&mut self) {
self.project
.cancel(&self.subscription, self.id, &mut self.receiver);
}
}
impl std::fmt::Debug for Consumer {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Consumer")
.field("subscription", &self.subscription)
.finish_non_exhaustive()
}
}
pub(crate) struct Settlement {
project: Arc<Project>,
subscription: Arc<str>,
pending: Option<Pending>,
reported: Option<i32>,
counted: bool,
}
impl Settlement {
pub(crate) fn delivery_attempt(&self) -> Option<i32> {
self.reported
}
pub(crate) fn ack(mut self) {
self.pending = None;
}
pub(crate) fn reject(mut self) {
if let Some(pending) = self.pending.take() {
self.project.reject(&self.subscription, pending);
}
}
pub(crate) fn reject_after(mut self, delay: Duration) {
let Some(pending) = self.pending.take() else {
return;
};
let project = Arc::clone(&self.project);
let subscription = Arc::clone(&self.subscription);
let reject = move || project.reject(&subscription, pending);
match self.project.coordinator() {
Some(coordinator) => coordinator.schedule_redelivery(delay, reject),
None => {
self.project.runtime().spawn(async move {
tokio::time::sleep(delay).await;
reject();
});
}
}
}
}
impl Drop for Settlement {
fn drop(&mut self) {
if let Some(pending) = self.pending.take() {
self.project.reject(&self.subscription, pending);
}
if self.counted
&& let Some(coordinator) = self.project.coordinator()
{
coordinator.consumed();
}
}
}
impl std::fmt::Debug for Settlement {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Settlement")
.field("subscription", &self.subscription)
.finish_non_exhaustive()
}
}