1use crate::exchanges::DeclareExchange;
3use anyhow::Result;
4use core::pin::Pin;
5use futures::{
6 future::Future,
7 stream::Stream,
8 task::{Context, Poll},
9};
10use lapin::{message::Delivery, Channel, Consumer};
11use std::sync::{Arc, Weak};
12use tokio::sync::mpsc::{Receiver, Sender};
13
14use super::comms::*;
15
16type ConsumerCreator = Box<dyn RabbitDispatcher<Object = Consumer>>;
18
19pub type CreatorResult<T> = Pin<Box<dyn Future<Output = Result<T>> + Send>>;
20pub type Creator<T> =
21 Pin<Box<dyn Fn(Arc<Channel>, Option<Arc<DeclareExchange>>) -> CreatorResult<T> + Send + Sync>>;
22
23pub type ChannelReceiver = Receiver<Weak<Channel>>;
24
25type NextFuture = Pin<Box<dyn Future<Output = (Delivery, Data)> + Send>>;
26
27struct Data {
28 consumer: Consumer,
30 channel: Weak<Channel>,
33 creator: ConsumerCreator,
35 channel_sender: ChannelSender,
37 channel_receiver: Receiver<Weak<Channel>>,
39 channel_requester: Arc<Sender<CommsMsg>>,
41}
42
43enum State {
44 Idle(Data),
46 Next {
48 next: NextFuture,
50 },
51}
52
53pub struct ConsumerWrapper {
58 state: Option<State>,
59}
60
61impl ConsumerWrapper {
62 pub(crate) async fn new(creator: ConsumerCreator) -> Self {
70 log::trace!("Getting channel requester");
71 let channel_requester = Comms::get_channel_comms();
72 let (channel_sender, mut channel_receiver) = Comms::create_channel_channel();
73 log::trace!("Creating the consumer using the creator");
74 let (consumer, channel) = creator
75 .start_dispatch(
76 None,
77 &channel_sender,
78 &mut channel_receiver,
79 &channel_requester,
80 )
81 .await;
82 log::trace!("Consumer wrapper created");
83 Self {
84 state: Some(State::Idle(Data {
85 consumer,
86 channel,
87 creator,
88 channel_sender,
89 channel_receiver,
90 channel_requester,
91 })),
92 }
93 }
94
95 async fn next_item(mut data: Data) -> (Delivery, Data) {
97 loop {
98 use futures::stream::StreamExt;
99 log::trace!("Polling consumer");
100 match data.consumer.next().await {
101 Some(Ok(delivery)) => {
102 log::trace!("Got delivery");
103 return (delivery, data);
104 }
105 Some(Err(err)) => {
106 log::error!("Failed to consume a message: {}", err);
107 }
108 None => {
109 log::error!("Consumer has finished for some reason!");
110 }
111 }
112 log::warn!("Consumer is broken, waiting for a new connection");
113 let (consumer, channel) = data
114 .creator
115 .start_dispatch(
116 Some(data.channel.clone()),
117 &data.channel_sender,
118 &mut data.channel_receiver,
119 &data.channel_requester,
120 )
121 .await;
122 data.consumer = consumer;
123 data.channel = channel;
124 }
125 }
126}
127
128impl Stream for ConsumerWrapper {
129 type Item = Delivery;
130 fn poll_next(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Option<Self::Item>> {
131 log::trace!("Poll next");
132 let this = Pin::into_inner(self);
133
134 loop {
135 match this.state.take() {
136 Some(State::Idle(data)) => {
137 this.state = Some(State::Next {
138 next: Box::pin(Self::next_item(data)),
139 });
140 }
141 Some(State::Next { mut next }) => {
142 let action = next.as_mut();
143 return match Future::poll(action, cx) {
144 Poll::Pending => {
145 this.state = Some(State::Next { next });
146 log::trace!("Pending");
147 Poll::Pending
148 }
149 Poll::Ready((delivery, data)) => {
150 this.state = Some(State::Idle(data));
151 log::trace!("Ready");
152 Poll::Ready(Some(delivery))
153 }
154 };
155 }
156 None => unreachable!(),
157 }
158 }
159 }
160}