1use anyhow::anyhow;
17use async_nats::{
18 Client, ConnectOptions, HeaderMap, HeaderValue, Message, PublishError, RequestError,
19 RequestErrorKind, Subject, SubscribeError, Subscriber, ToServerAddrs,
20};
21use backon::{BackoffBuilder, ExponentialBuilder};
22use futures::channel::mpsc;
23use futures::stream::FuturesUnordered;
24use futures::{FutureExt, Stream, StreamExt, select};
25use parity_scale_codec::{Decode, Encode};
26use std::any::type_name;
27use std::collections::VecDeque;
28use std::future::Future;
29use std::marker::PhantomData;
30use std::ops::Deref;
31use std::pin::Pin;
32use std::sync::Arc;
33use std::task::{Context, Poll};
34use std::time::Duration;
35use std::{fmt, mem};
36use subspace_process::AsyncJoinOnDrop;
37use thiserror::Error;
38use tracing::{Instrument, debug, error, trace, warn};
39use ulid::Ulid;
40
41const EXPECTED_MESSAGE_SIZE: usize = 2 * 1024 * 1024;
42const ACKNOWLEDGEMENT_TIMEOUT: Duration = Duration::from_mins(1);
43const REQUEST_TIMEOUT: Duration = Duration::from_mins(5);
46
47pub trait GenericRequest: Encode + Decode + fmt::Debug + Send + Sync + 'static {
53 const SUBJECT: &'static str;
55 type Response: Encode + Decode + fmt::Debug + Send + Sync + 'static;
57}
58
59pub trait GenericStreamRequest: Encode + Decode + fmt::Debug + Send + Sync + 'static {
66 const SUBJECT: &'static str;
68 type Response: Encode + Decode + fmt::Debug + Send + Sync + 'static;
74}
75
76#[derive(Debug, Encode, Decode)]
80enum GenericStreamResponses<Response> {
81 Continue {
83 index: u32,
85 responses: VecDeque<Response>,
87 ack_subject: String,
90 },
91 Last {
93 index: u32,
95 responses: VecDeque<Response>,
97 },
98}
99
100impl<Response> From<GenericStreamResponses<Response>> for VecDeque<Response> {
101 #[inline]
102 fn from(value: GenericStreamResponses<Response>) -> Self {
103 match value {
104 GenericStreamResponses::Continue { responses, .. } => responses,
105 GenericStreamResponses::Last { responses, .. } => responses,
106 }
107 }
108}
109
110impl<Response> GenericStreamResponses<Response> {
111 fn next(&mut self) -> Option<Response> {
112 match self {
113 GenericStreamResponses::Continue { responses, .. } => responses.pop_front(),
114 GenericStreamResponses::Last { responses, .. } => responses.pop_front(),
115 }
116 }
117
118 fn index(&self) -> u32 {
119 match self {
120 GenericStreamResponses::Continue { index, .. } => *index,
121 GenericStreamResponses::Last { index, .. } => *index,
122 }
123 }
124
125 fn ack_subject(&self) -> Option<&str> {
126 if let GenericStreamResponses::Continue { ack_subject, .. } = self {
127 Some(ack_subject)
128 } else {
129 None
130 }
131 }
132
133 fn is_last(&self) -> bool {
134 matches!(self, Self::Last { .. })
135 }
136}
137
138#[derive(Debug, Error)]
140pub enum StreamRequestError {
141 #[error("Subscribe error: {0}")]
143 Subscribe(#[from] SubscribeError),
144 #[error("Publish error: {0}")]
146 Publish(#[from] PublishError),
147}
148
149#[derive(Debug)]
152#[pin_project::pin_project]
153pub struct StreamResponseSubscriber<Response> {
154 #[pin]
155 subscriber: Subscriber,
156 response_subject: String,
157 buffered_responses: Option<GenericStreamResponses<Response>>,
158 next_index: u32,
159 acknowledgement_sender: mpsc::UnboundedSender<(String, u32)>,
160 _background_task: AsyncJoinOnDrop<()>,
161 _phantom: PhantomData<Response>,
162}
163
164impl<Response> Stream for StreamResponseSubscriber<Response>
165where
166 Response: Decode,
167{
168 type Item = Response;
169
170 fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
171 if let Some(buffered_responses) = self.buffered_responses.as_mut() {
172 if let Some(response) = buffered_responses.next() {
173 return Poll::Ready(Some(response));
174 } else if buffered_responses.is_last() {
175 return Poll::Ready(None);
176 }
177
178 self.buffered_responses.take();
179 self.next_index += 1;
180 }
181
182 let mut projected = self.project();
183 match projected.subscriber.poll_next_unpin(cx) {
184 Poll::Ready(Some(message)) => {
185 match GenericStreamResponses::<Response>::decode(&mut message.payload.as_ref()) {
186 Ok(mut responses) => {
187 if responses.index() != *projected.next_index {
188 warn!(
189 actual_index = %responses.index(),
190 expected_index = %*projected.next_index,
191 message_type = %type_name::<Response>(),
192 response_subject = %projected.response_subject,
193 "Received unexpected response stream index, aborting stream"
194 );
195
196 return Poll::Ready(None);
197 }
198
199 if let Some(ack_subject) = responses.ack_subject() {
200 let index = responses.index();
201 let ack_subject = ack_subject.to_string();
202
203 if let Err(error) = projected
204 .acknowledgement_sender
205 .unbounded_send((ack_subject.clone(), index))
206 {
207 warn!(
208 %error,
209 %index,
210 message_type = %type_name::<Response>(),
211 response_subject = %projected.response_subject,
212 %ack_subject,
213 "Failed to send acknowledgement for stream response"
214 );
215 }
216 }
217
218 if let Some(response) = responses.next() {
219 *projected.buffered_responses = Some(responses);
220 Poll::Ready(Some(response))
221 } else {
222 Poll::Ready(None)
223 }
224 }
225 Err(error) => {
226 warn!(
227 %error,
228 response_type = %type_name::<Response>(),
229 response_subject = %projected.response_subject,
230 message = %hex::encode(message.payload),
231 "Failed to decode stream response"
232 );
233
234 Poll::Ready(None)
235 }
236 }
237 }
238 Poll::Ready(None) => Poll::Ready(None),
239 Poll::Pending => Poll::Pending,
240 }
241 }
242}
243
244impl<Response> StreamResponseSubscriber<Response> {
245 fn new(subscriber: Subscriber, response_subject: String, nats_client: NatsClient) -> Self {
246 let (acknowledgement_sender, mut acknowledgement_receiver) =
247 mpsc::unbounded::<(String, u32)>();
248
249 let ack_publisher_fut = {
250 let response_subject = response_subject.clone();
251
252 async move {
253 while let Some((subject, index)) = acknowledgement_receiver.next().await {
254 trace!(
255 %subject,
256 %index,
257 %response_subject,
258 %index,
259 "Sending stream response acknowledgement"
260 );
261 if let Err(error) = nats_client
262 .publish(subject.clone(), index.to_le_bytes().to_vec().into())
263 .await
264 {
265 warn!(
266 %error,
267 %subject,
268 %index,
269 %response_subject,
270 %index,
271 "Failed to send stream response acknowledgement"
272 );
273 return;
274 }
275 }
276 }
277 };
278 let background_task =
279 AsyncJoinOnDrop::new(tokio::spawn(ack_publisher_fut.in_current_span()), true);
280
281 Self {
282 response_subject,
283 subscriber,
284 buffered_responses: None,
285 next_index: 0,
286 acknowledgement_sender,
287 _background_task: background_task,
288 _phantom: PhantomData,
289 }
290 }
291}
292
293pub trait GenericNotification: Encode + Decode + fmt::Debug + Send + Sync + 'static {
295 const SUBJECT: &'static str;
298}
299
300pub trait GenericBroadcast: Encode + Decode + fmt::Debug + Send + Sync + 'static {
306 const SUBJECT: &'static str;
308
309 fn deterministic_message_id(&self) -> Option<HeaderValue> {
312 None
313 }
314}
315
316#[derive(Debug)]
318#[pin_project::pin_project]
319pub struct SubscriberWrapper<Message> {
320 #[pin]
321 subscriber: Subscriber,
322 _phantom: PhantomData<Message>,
323}
324
325impl<Message> Stream for SubscriberWrapper<Message>
326where
327 Message: Decode,
328{
329 type Item = Message;
330
331 fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
332 match self.project().subscriber.poll_next_unpin(cx) {
333 Poll::Ready(Some(message)) => match Message::decode(&mut message.payload.as_ref()) {
334 Ok(message) => Poll::Ready(Some(message)),
335 Err(error) => {
336 warn!(
337 %error,
338 message_type = %type_name::<Message>(),
339 message = %hex::encode(message.payload),
340 "Failed to decode stream message"
341 );
342
343 Poll::Pending
344 }
345 },
346 Poll::Ready(None) => Poll::Ready(None),
347 Poll::Pending => Poll::Pending,
348 }
349 }
350}
351
352#[derive(Debug)]
353struct Inner {
354 client: Client,
355 request_retry_backoff_policy: ExponentialBuilder,
356 approximate_max_message_size: usize,
357 max_message_size: usize,
358}
359
360#[derive(Debug, Clone)]
362pub struct NatsClient {
363 inner: Arc<Inner>,
364}
365
366impl Deref for NatsClient {
367 type Target = Client;
368
369 #[inline]
370 fn deref(&self) -> &Self::Target {
371 &self.inner.client
372 }
373}
374
375impl NatsClient {
376 pub async fn new<A: ToServerAddrs>(
378 addrs: A,
379 request_retry_backoff_policy: ExponentialBuilder,
380 ) -> Result<Self, async_nats::Error> {
381 let servers = addrs.to_server_addrs()?.collect::<Vec<_>>();
382 Self::from_client(
383 async_nats::connect_with_options(
384 &servers,
385 ConnectOptions::default().request_timeout(Some(REQUEST_TIMEOUT)),
386 )
387 .await?,
388 request_retry_backoff_policy,
389 )
390 }
391
392 pub fn from_client(
394 client: Client,
395 request_retry_backoff_policy: ExponentialBuilder,
396 ) -> Result<Self, async_nats::Error> {
397 let max_payload = client.server_info().max_payload;
398 if max_payload < EXPECTED_MESSAGE_SIZE {
399 return Err(format!(
400 "Max payload {max_payload} is smaller than expected {EXPECTED_MESSAGE_SIZE}, \
401 increase it by specifying max_payload = 2MB or higher number in NATS configuration"
402 )
403 .into());
404 }
405
406 let inner = Inner {
407 client,
408 request_retry_backoff_policy,
409 approximate_max_message_size: max_payload * 9 / 10,
411 max_message_size: max_payload,
413 };
414
415 Ok(Self {
416 inner: Arc::new(inner),
417 })
418 }
419
420 pub fn approximate_max_message_size(&self) -> usize {
423 self.inner.approximate_max_message_size
424 }
425
426 pub async fn request<Request>(
428 &self,
429 request: &Request,
430 instance: Option<&str>,
431 ) -> Result<Request::Response, RequestError>
432 where
433 Request: GenericRequest,
434 {
435 let subject = subject_with_instance(Request::SUBJECT, instance);
436 let mut maybe_retry_backoff = None;
437 let message = loop {
438 match self
439 .inner
440 .client
441 .request(subject.clone(), request.encode().into())
442 .await
443 {
444 Ok(message) => {
445 break message;
446 }
447 Err(error) => {
448 match error.kind() {
449 RequestErrorKind::TimedOut | RequestErrorKind::NoResponders => {
450 }
452 RequestErrorKind::Other
453 | RequestErrorKind::InvalidSubject
454 | RequestErrorKind::MaxPayloadExceeded => {
455 return Err(error);
456 }
457 }
458
459 let retry_backoff = maybe_retry_backoff
460 .get_or_insert_with(|| self.inner.request_retry_backoff_policy.build());
461
462 if let Some(delay) = retry_backoff.next() {
463 debug!(
464 %subject,
465 %error,
466 request_type = %type_name::<Request>(),
467 ?delay,
468 "Failed to make request, retrying after some delay"
469 );
470
471 tokio::time::sleep(delay).await;
472 continue;
473 } else {
474 return Err(error);
475 }
476 }
477 }
478 };
479
480 let response =
481 Request::Response::decode(&mut message.payload.as_ref()).map_err(|error| {
482 warn!(
483 %subject,
484 %error,
485 response_type = %type_name::<Request::Response>(),
486 response = %hex::encode(message.payload),
487 "Response decoding failed"
488 );
489
490 RequestErrorKind::Other
491 })?;
492
493 Ok(response)
494 }
495
496 pub async fn request_responder<Request, F, OP>(
511 &self,
512 instance: Option<&str>,
513 queue_group: Option<String>,
514 process: OP,
515 ) -> anyhow::Result<()>
516 where
517 Request: GenericRequest,
518 F: Future<Output = Option<Request::Response>> + Send,
519 OP: Fn(Request) -> F + Send + Sync,
520 {
521 let mut processing = FuturesUnordered::new();
523
524 let subscription = self
525 .common_subscribe(Request::SUBJECT, instance, queue_group)
526 .await
527 .map_err(|error| {
528 anyhow!(
529 "Failed to subscribe to {} requests for {instance:?}: {error}",
530 type_name::<Request>(),
531 )
532 })?;
533
534 debug!(
535 request_type = %type_name::<Request>(),
536 ?subscription,
537 "Requests subscription"
538 );
539 let mut subscription = subscription.fuse();
540
541 loop {
542 select! {
543 message = subscription.select_next_some() => {
544 processing.push(
546 self
547 .process_request(
548 message,
549 &process,
550 )
551 .in_current_span(),
552 );
553 },
554 _ = processing.next() => {
555 },
557 complete => {
558 break;
559 }
560 }
561 }
562
563 Ok(())
564 }
565
566 async fn process_request<Request, F, OP>(&self, message: Message, process: OP)
567 where
568 Request: GenericRequest,
569 F: Future<Output = Option<Request::Response>> + Send,
570 OP: Fn(Request) -> F + Send + Sync,
571 {
572 let Some(reply_subject) = message.reply else {
573 return;
574 };
575
576 let message_payload_size = message.payload.len();
577 let request = match Request::decode(&mut message.payload.as_ref()) {
578 Ok(request) => {
579 drop(message.payload);
581 request
582 }
583 Err(error) => {
584 warn!(
585 request_type = %type_name::<Request>(),
586 %error,
587 message = %hex::encode(message.payload),
588 "Failed to decode request"
589 );
590 return;
591 }
592 };
593
594 if message_payload_size > 1024 {
596 trace!(
597 request_type = %type_name::<Request>(),
598 %reply_subject,
599 "Processing request"
600 );
601 } else {
602 trace!(
603 request_type = %type_name::<Request>(),
604 ?request,
605 %reply_subject,
606 "Processing request"
607 );
608 }
609
610 if let Some(response) = process(request).await
611 && let Err(error) = self.publish(reply_subject, response.encode().into()).await
612 {
613 warn!(
614 request_type = %type_name::<Request>(),
615 %error,
616 "Failed to send response"
617 );
618 }
619 }
620
621 pub async fn stream_request<Request>(
623 &self,
624 request: &Request,
625 instance: Option<&str>,
626 ) -> Result<StreamResponseSubscriber<Request::Response>, StreamRequestError>
627 where
628 Request: GenericStreamRequest,
629 {
630 let stream_request_subject = subject_with_instance(Request::SUBJECT, instance);
631 let stream_response_subject = format!("stream-response.{}", Ulid::generate());
632
633 let subscriber = self
634 .inner
635 .client
636 .subscribe(stream_response_subject.clone())
637 .await?;
638
639 debug!(
640 request_type = %type_name::<Request>(),
641 %stream_request_subject,
642 %stream_response_subject,
643 ?subscriber,
644 "Stream request subscription"
645 );
646
647 self.inner
648 .client
649 .publish_with_reply(
650 stream_request_subject,
651 stream_response_subject.clone(),
652 request.encode().into(),
653 )
654 .await?;
655
656 Ok(StreamResponseSubscriber::new(
657 subscriber,
658 stream_response_subject,
659 self.clone(),
660 ))
661 }
662
663 pub async fn stream_request_responder<Request, F, S, OP>(
678 &self,
679 instance: Option<&str>,
680 queue_group: Option<String>,
681 process: OP,
682 ) -> anyhow::Result<()>
683 where
684 Request: GenericStreamRequest,
685 F: Future<Output = Option<S>> + Send,
686 S: Stream<Item = Request::Response> + Unpin,
687 OP: Fn(Request) -> F + Send + Sync,
688 {
689 let mut processing = FuturesUnordered::new();
691
692 let subscription = self
693 .common_subscribe(Request::SUBJECT, instance, queue_group)
694 .await
695 .map_err(|error| {
696 anyhow!(
697 "Failed to subscribe to {} stream requests for {instance:?}: {error}",
698 type_name::<Request>(),
699 )
700 })?;
701
702 debug!(
703 request_type = %type_name::<Request>(),
704 ?subscription,
705 "Stream requests subscription"
706 );
707 let mut subscription = subscription.fuse();
708
709 loop {
710 select! {
711 message = subscription.select_next_some() => {
712 processing.push(
714 self
715 .process_stream_request(
716 message,
717 &process,
718 )
719 .in_current_span(),
720 );
721 },
722 _ = processing.next() => {
723 },
725 complete => {
726 break;
727 }
728 }
729 }
730
731 Ok(())
732 }
733
734 async fn process_stream_request<Request, F, S, OP>(&self, message: Message, process: OP)
735 where
736 Request: GenericStreamRequest,
737 F: Future<Output = Option<S>> + Send,
738 S: Stream<Item = Request::Response> + Unpin,
739 OP: Fn(Request) -> F + Send + Sync,
740 {
741 let Some(reply_subject) = message.reply else {
742 return;
743 };
744
745 let message_payload_size = message.payload.len();
746 let request = match Request::decode(&mut message.payload.as_ref()) {
747 Ok(request) => {
748 drop(message.payload);
750 request
751 }
752 Err(error) => {
753 warn!(
754 request_type = %type_name::<Request>(),
755 %error,
756 message = %hex::encode(message.payload),
757 "Failed to decode request"
758 );
759 return;
760 }
761 };
762
763 if message_payload_size > 1024 {
765 trace!(
766 request_type = %type_name::<Request>(),
767 %reply_subject,
768 "Processing request"
769 );
770 } else {
771 trace!(
772 request_type = %type_name::<Request>(),
773 ?request,
774 %reply_subject,
775 "Processing request"
776 );
777 }
778
779 if let Some(stream) = process(request).await {
780 self.stream_response::<Request, _>(reply_subject, stream)
781 .await;
782 }
783 }
784
785 async fn stream_response<Request, S>(&self, response_subject: Subject, response_stream: S)
787 where
788 Request: GenericStreamRequest,
789 S: Stream<Item = Request::Response> + Unpin,
790 {
791 type Response<Request> =
792 GenericStreamResponses<<Request as GenericStreamRequest>::Response>;
793
794 let mut response_stream = response_stream.fuse();
795
796 let first_element = match response_stream.next().await {
798 Some(first_element) => first_element,
799 None => {
800 if let Err(error) = self
801 .publish(
802 response_subject.clone(),
803 Response::<Request>::Last {
804 index: 0,
805 responses: VecDeque::new(),
806 }
807 .encode()
808 .into(),
809 )
810 .await
811 {
812 warn!(
813 %response_subject,
814 %error,
815 request_type = %type_name::<Request>(),
816 response_type = %type_name::<Request::Response>(),
817 "Failed to send stream response"
818 );
819 }
820
821 return;
822 }
823 };
824 let max_message_size = self.inner.max_message_size;
825 let approximate_max_message_size = self.approximate_max_message_size();
826 let max_responses_per_message = approximate_max_message_size / first_element.encoded_size();
827
828 let ack_subject = format!("stream-response-ack.{}", Ulid::generate());
829 let mut ack_subscription = match self.subscribe(ack_subject.clone()).await {
830 Ok(ack_subscription) => ack_subscription,
831 Err(error) => {
832 warn!(
833 %response_subject,
834 %error,
835 request_type = %type_name::<Request>(),
836 response_type = %type_name::<Request::Response>(),
837 "Failed to subscribe to ack subject"
838 );
839 return;
840 }
841 };
842 debug!(
843 %response_subject,
844 request_type = %type_name::<Request>(),
845 response_type = %type_name::<Request::Response>(),
846 ?ack_subscription,
847 "Ack subscription subscription"
848 );
849 let mut index = 0;
850 let mut buffer = VecDeque::with_capacity(max_responses_per_message);
852 buffer.push_back(first_element);
853 let mut overflow_buffer = VecDeque::new();
854
855 loop {
856 if buffer.is_empty()
858 && let Some(element) = response_stream.next().await
859 {
860 buffer.push_back(element);
861 }
862 while buffer.encoded_size() < approximate_max_message_size
863 && let Some(element) = response_stream.next().now_or_never().flatten()
864 {
865 buffer.push_back(element);
866 }
867
868 loop {
869 let is_done = response_stream.is_done() && overflow_buffer.is_empty();
870 let num_messages = buffer.len();
871 let response = if is_done {
872 Response::<Request>::Last {
873 index,
874 responses: buffer,
875 }
876 } else {
877 Response::<Request>::Continue {
878 index,
879 responses: buffer,
880 ack_subject: ack_subject.clone(),
881 }
882 };
883 let encoded_response = response.encode();
884 let encoded_response_len = encoded_response.len();
885 if encoded_response_len > max_message_size {
888 buffer = response.into();
889 if let Some(element) = buffer.pop_back() {
890 if buffer.is_empty() {
891 error!(
892 ?element,
893 encoded_response_len,
894 max_message_size,
895 "Element was too large to fit into NATS message, this is an \
896 implementation bug"
897 );
898 }
899 overflow_buffer.push_front(element);
900 continue;
901 } else {
902 error!(
903 %response_subject,
904 request_type = %type_name::<Request>(),
905 response_type = %type_name::<Request::Response>(),
906 "Empty response overflown message size, this should never happen"
907 );
908 return;
909 }
910 }
911
912 debug!(
913 %response_subject,
914 num_messages,
915 %index,
916 %is_done,
917 "Publishing stream response messages",
918 );
919
920 if let Err(error) = self
921 .publish(response_subject.clone(), encoded_response.into())
922 .await
923 {
924 warn!(
925 %response_subject,
926 %error,
927 request_type = %type_name::<Request>(),
928 response_type = %type_name::<Request::Response>(),
929 "Failed to send stream response"
930 );
931 return;
932 }
933
934 if is_done {
935 return;
936 } else {
937 buffer = response.into();
938 buffer.clear();
939 buffer.extend(overflow_buffer.drain(..));
941 }
942
943 if index >= 1 {
944 let expected_index = index - 1;
946
947 trace!(
948 %response_subject,
949 %expected_index,
950 "Waiting for acknowledgement"
951 );
952 match tokio::time::timeout(ACKNOWLEDGEMENT_TIMEOUT, ack_subscription.next())
953 .await
954 {
955 Ok(Some(message)) => {
956 if let Some(received_index) = message
957 .payload
958 .split_at_checked(mem::size_of::<u32>())
959 .map(|(bytes, _)| {
960 u32::from_le_bytes(
961 bytes.try_into().expect("Correctly chunked slice; qed"),
962 )
963 })
964 {
965 debug!(
966 %response_subject,
967 %received_index,
968 "Received acknowledgement"
969 );
970 if received_index != expected_index {
971 warn!(
972 %response_subject,
973 %received_index,
974 %expected_index,
975 request_type = %type_name::<Request>(),
976 response_type = %type_name::<Request::Response>(),
977 message = %hex::encode(message.payload),
978 "Unexpected acknowledgement index"
979 );
980 return;
981 }
982 } else {
983 warn!(
984 %response_subject,
985 request_type = %type_name::<Request>(),
986 response_type = %type_name::<Request::Response>(),
987 message = %hex::encode(message.payload),
988 "Unexpected acknowledgement message"
989 );
990 return;
991 }
992 }
993 Ok(None) => {
994 warn!(
995 %response_subject,
996 request_type = %type_name::<Request>(),
997 response_type = %type_name::<Request::Response>(),
998 "Acknowledgement stream ended unexpectedly"
999 );
1000 return;
1001 }
1002 Err(_error) => {
1003 warn!(
1004 %response_subject,
1005 %expected_index,
1006 request_type = %type_name::<Request>(),
1007 response_type = %type_name::<Request::Response>(),
1008 "Acknowledgement wait timed out"
1009 );
1010 return;
1011 }
1012 }
1013 }
1014
1015 index += 1;
1016
1017 if buffer.is_empty() {
1019 break;
1020 }
1021 }
1022 }
1023 }
1024
1025 pub async fn notification<Notification>(
1027 &self,
1028 notification: &Notification,
1029 instance: Option<&str>,
1030 ) -> Result<(), PublishError>
1031 where
1032 Notification: GenericNotification,
1033 {
1034 self.inner
1035 .client
1036 .publish(
1037 subject_with_instance(Notification::SUBJECT, instance),
1038 notification.encode().into(),
1039 )
1040 .await
1041 }
1042
1043 pub async fn broadcast<Broadcast>(
1045 &self,
1046 message: &Broadcast,
1047 instance: &str,
1048 ) -> Result<(), PublishError>
1049 where
1050 Broadcast: GenericBroadcast,
1051 {
1052 self.inner
1053 .client
1054 .publish_with_headers(
1055 Broadcast::SUBJECT.replace('*', instance),
1056 {
1057 let mut headers = HeaderMap::new();
1058 if let Some(message_id) = message.deterministic_message_id() {
1059 headers.insert("Nats-Msg-Id", message_id);
1060 }
1061 headers
1062 },
1063 message.encode().into(),
1064 )
1065 .await
1066 }
1067
1068 pub async fn subscribe_to_notifications<Notification>(
1071 &self,
1072 instance: Option<&str>,
1073 queue_group: Option<String>,
1074 ) -> Result<SubscriberWrapper<Notification>, SubscribeError>
1075 where
1076 Notification: GenericNotification,
1077 {
1078 self.simple_subscribe(Notification::SUBJECT, instance, queue_group)
1079 .await
1080 }
1081
1082 pub async fn subscribe_to_broadcasts<Broadcast>(
1085 &self,
1086 instance: Option<&str>,
1087 queue_group: Option<String>,
1088 ) -> Result<SubscriberWrapper<Broadcast>, SubscribeError>
1089 where
1090 Broadcast: GenericBroadcast,
1091 {
1092 self.simple_subscribe(Broadcast::SUBJECT, instance, queue_group)
1093 .await
1094 }
1095
1096 async fn simple_subscribe<Message>(
1099 &self,
1100 subject: &'static str,
1101 instance: Option<&str>,
1102 queue_group: Option<String>,
1103 ) -> Result<SubscriberWrapper<Message>, SubscribeError>
1104 where
1105 Message: Decode,
1106 {
1107 let subscriber = self
1108 .common_subscribe(subject, instance, queue_group)
1109 .await?;
1110 debug!(
1111 %subject,
1112 message_type = %type_name::<Message>(),
1113 ?subscriber,
1114 "Simple subscription"
1115 );
1116
1117 Ok(SubscriberWrapper {
1118 subscriber,
1119 _phantom: PhantomData,
1120 })
1121 }
1122
1123 async fn common_subscribe(
1126 &self,
1127 subject: &'static str,
1128 instance: Option<&str>,
1129 queue_group: Option<String>,
1130 ) -> Result<Subscriber, SubscribeError> {
1131 let subscriber = if let Some(queue_group) = queue_group {
1132 self.inner
1133 .client
1134 .queue_subscribe(subject_with_instance(subject, instance), queue_group)
1135 .await?
1136 } else {
1137 self.inner
1138 .client
1139 .subscribe(subject_with_instance(subject, instance))
1140 .await?
1141 };
1142
1143 Ok(subscriber)
1144 }
1145}
1146
1147fn subject_with_instance(subject: &'static str, instance: Option<&str>) -> Subject {
1148 if let Some(instance) = instance {
1149 Subject::from(subject.replace('*', instance))
1150 } else {
1151 Subject::from_static(subject)
1152 }
1153}