1use std::{
23 any::TypeId,
24 sync::mpsc::{channel, Receiver, Sender},
25 time::Instant,
26};
27
28use futures::future::LocalBoxFuture;
29use tokio::sync::oneshot;
30
31use crate::{AsyncHandler, DeliveryStats, Handler, Message, Service};
32
33pub struct Envelope<S> {
35 message: Box<dyn EnvelopeT<S>>,
36}
37
38impl<S: Service> Envelope<S> {
39 pub fn wrap<M>(message: M) -> Self
40 where
41 M: Message,
42 S: Handler<M>,
43 {
44 Self::wrap_with_reply(message).0
45 }
46
47 pub fn wrap_with_reply<M>(message: M) -> (Self, Receiver<M::Reply>)
48 where
49 M: Message,
50 S: Handler<M>,
51 {
52 let (ack_sender, ack_receiver) = channel();
53 (
54 Envelope {
55 message: Box::new(EnvelopeTImpl {
56 timestamp: Instant::now(),
57 message: Some(message),
58 ack_sender,
59 }),
60 },
61 ack_receiver,
62 )
63 }
64
65 pub fn deliver_to(&mut self, service: &mut S) -> Result<DeliveryStats, &'static str> {
66 self.message.handle(service)
67 }
68
69 pub fn message_type_id(&self) -> Option<TypeId> {
70 self.message.type_id()
71 }
72}
73
74trait EnvelopeT<S: Service>: Send {
75 fn type_id(&self) -> Option<TypeId>;
76 fn handle(&mut self, service: &mut S) -> Result<DeliveryStats, &'static str>;
77}
78struct EnvelopeTImpl<M>
79where
80 M: Message,
81{
82 message: Option<M>,
83 ack_sender: Sender<M::Reply>,
84 timestamp: Instant,
85}
86impl<S: Service + Handler<M>, M: Message> EnvelopeT<S> for EnvelopeTImpl<M> {
87 fn type_id(&self) -> Option<TypeId> {
88 self.message.as_ref().map(|m| m.type_id())
89 }
90
91 fn handle(&mut self, service: &mut S) -> Result<DeliveryStats, &'static str> {
92 if let Some(message) = self.message.take() {
93 let processing_at = Instant::now();
94 let r = service.deliver(message);
95
96 let queued = processing_at - self.timestamp;
97 let processing = Instant::now() - processing_at;
98
99 let _error = self.ack_sender.send(r);
100 Ok(DeliveryStats { queued, processing })
101 } else {
102 Err("Attempt to deliver multiple times")
103 }
104 }
105}
106
107pub struct AsyncEnvelope<S> {
109 message: Box<dyn AsyncEnvelopeT<S>>,
110}
111
112impl<S: Service> AsyncEnvelope<S> {
113 pub fn wrap<M>(message: M) -> Self
114 where
115 M: Message,
116 S: AsyncHandler<M>,
117 {
118 Self::wrap_with_reply(message).0
119 }
120
121 pub fn wrap_with_reply<M>(message: M) -> (Self, oneshot::Receiver<M::Reply>)
122 where
123 M: Message,
124 S: AsyncHandler<M>,
125 {
126 let (ack_sender, ack_receiver) = oneshot::channel();
127 (
128 AsyncEnvelope {
129 message: Box::new(AsyncEnvelopeTImpl {
130 timestamp: Instant::now(),
131 message: Some(message),
132 ack_sender: Some(ack_sender),
133 }),
134 },
135 ack_receiver,
136 )
137 }
138
139 pub fn deliver_to<'a>(
140 &'a mut self,
141 service: &'a mut S,
142 ) -> LocalBoxFuture<'a, Result<DeliveryStats, &'static str>> {
143 self.message.handle(service)
144 }
145
146 pub fn message_type_id(&self) -> Option<TypeId> {
147 self.message.type_id()
148 }
149}
150
151trait AsyncEnvelopeT<S: Service>: Send {
152 fn type_id(&self) -> Option<TypeId>;
153 fn handle<'a>(
154 &'a mut self,
155 service: &'a mut S,
156 ) -> LocalBoxFuture<'a, Result<DeliveryStats, &'static str>>;
157}
158struct AsyncEnvelopeTImpl<M>
159where
160 M: Message,
161{
162 message: Option<M>,
163 ack_sender: Option<oneshot::Sender<M::Reply>>,
164 timestamp: Instant,
165}
166impl<S: Service + AsyncHandler<M>, M: Message> AsyncEnvelopeT<S> for AsyncEnvelopeTImpl<M> {
167 fn type_id(&self) -> Option<TypeId> {
168 self.message.as_ref().map(|m| m.type_id())
169 }
170
171 fn handle<'a>(
172 &'a mut self,
173 service: &'a mut S,
174 ) -> LocalBoxFuture<'a, Result<DeliveryStats, &'static str>> {
175 Box::pin(async move {
176 if let Some(message) = self.message.take() {
177 let processing_at = Instant::now();
178 let r = service.deliver_async(message).await;
179
180 let queued = processing_at - self.timestamp;
181 let processing = Instant::now() - processing_at;
182
183 if let Some(ack_sender) = self.ack_sender.take() {
184 let _error = ack_sender.send(r);
185 }
186 Ok(DeliveryStats { queued, processing })
187 } else {
188 Err("Attempt to deliver multiple times")
189 }
190 })
191 }
192}
193
194pub enum TaskEnvelope<S> {
197 Sync(Envelope<S>),
198 Async(AsyncEnvelope<S>),
199}
200
201impl<S: Service> TaskEnvelope<S> {
202 pub fn message_type_id(&self) -> Option<TypeId> {
203 match self {
204 TaskEnvelope::Sync(envelope) => envelope.message_type_id(),
205 TaskEnvelope::Async(envelope) => envelope.message_type_id(),
206 }
207 }
208}
209
210impl<S: Service> From<Envelope<S>> for TaskEnvelope<S> {
211 fn from(envelope: Envelope<S>) -> Self {
212 TaskEnvelope::Sync(envelope)
213 }
214}
215
216impl<S: Service> From<AsyncEnvelope<S>> for TaskEnvelope<S> {
217 fn from(envelope: AsyncEnvelope<S>) -> Self {
218 TaskEnvelope::Async(envelope)
219 }
220}