1use crate::pipeline::{PipelineComponent, PipelineOverrides};
2use crate::{
3 catch_errors, validate_json_value_with_options, validate_value, BootError, BootErrorKind,
4 BoxFuture, ExecutionContext, ExecutionInterceptor, ExecutionTransportKind, Guard, Result,
5 TransportExceptionFilter, Validate, ValidationOptions, ValidationSchema,
6};
7use serde::de::DeserializeOwned;
8use serde::{Deserialize, Serialize};
9use serde_json::Value;
10use std::collections::BTreeMap;
11use std::future::Future;
12use std::ops::Deref;
13use std::sync::Arc;
14
15#[cfg(feature = "grpc-transport")]
16mod grpc;
17#[cfg(feature = "kafka-transport")]
18mod kafka;
19#[cfg(feature = "mqtt-transport")]
20mod mqtt;
21#[cfg(feature = "nats-transport")]
22mod nats;
23#[cfg(feature = "rabbitmq-transport")]
24mod rabbitmq;
25#[cfg(feature = "redis-transport")]
26mod redis;
27#[cfg(feature = "tcp-transport")]
28mod tcp;
29
30#[cfg(feature = "grpc-transport")]
31pub use self::grpc::{GrpcTransport, GrpcTransportClient, GrpcTransportOptions};
32#[cfg(feature = "kafka-transport")]
33pub use self::kafka::{KafkaTransport, KafkaTransportClient, KafkaTransportOptions};
34#[cfg(feature = "mqtt-transport")]
35pub use self::mqtt::{MqttTransport, MqttTransportClient, MqttTransportOptions, MqttTransportQoS};
36#[cfg(feature = "nats-transport")]
37pub use self::nats::{NatsTransport, NatsTransportClient, NatsTransportOptions};
38#[cfg(feature = "rabbitmq-transport")]
39pub use self::rabbitmq::{RabbitMqTransport, RabbitMqTransportClient, RabbitMqTransportOptions};
40#[cfg(feature = "redis-transport")]
41pub use self::redis::{RedisTransport, RedisTransportClient, RedisTransportOptions};
42#[cfg(any(
43 feature = "grpc-transport",
44 feature = "kafka-transport",
45 feature = "mqtt-transport",
46 feature = "nats-transport",
47 feature = "rabbitmq-transport",
48 feature = "redis-transport",
49 feature = "tcp-transport"
50))]
51pub(super) fn transport_error_from_status(status: u16, message: String) -> BootError {
52 BootError::from_http_status(status, message)
53}
54
55#[cfg(feature = "tcp-transport")]
56pub use tcp::{TcpTransport, TcpTransportClient, TcpTransportOptions};
57
58#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
60pub struct TransportMessage {
61 pub pattern: String,
62 #[serde(default)]
63 pub data: Value,
64}
65
66impl TransportMessage {
67 pub fn new(pattern: impl Into<String>, data: impl Into<Value>) -> Self {
68 Self {
69 pattern: pattern.into(),
70 data: data.into(),
71 }
72 }
73
74 pub fn pattern(&self) -> &str {
75 &self.pattern
76 }
77
78 pub fn data(&self) -> &Value {
79 &self.data
80 }
81
82 pub fn text(pattern: impl Into<String>, data: impl Into<String>) -> Self {
83 Self::new(pattern, Value::String(data.into()))
84 }
85
86 pub fn json<T>(pattern: impl Into<String>, data: &T) -> Result<Self>
87 where
88 T: Serialize,
89 {
90 Ok(Self::new(
91 pattern,
92 serde_json::to_value(data).map_err(|err| BootError::Internal(err.to_string()))?,
93 ))
94 }
95
96 pub fn data_as<T>(&self) -> Result<T>
97 where
98 T: DeserializeOwned,
99 {
100 serde_json::from_value(self.data.clone())
101 .map_err(|err| BootError::BadRequest(err.to_string()))
102 }
103
104 pub fn data_field(&self, name: &str) -> Result<Option<Value>> {
105 let Value::Object(fields) = &self.data else {
106 return Err(BootError::BadRequest(
107 "expected JSON object transport data".to_string(),
108 ));
109 };
110
111 Ok(fields.get(name).filter(|value| !value.is_null()).cloned())
112 }
113
114 pub fn data_field_as<T>(&self, name: &str) -> Result<T>
115 where
116 T: DeserializeOwned,
117 {
118 let Some(value) = self.data_field(name)? else {
119 return Err(BootError::BadRequest(format!(
120 "missing transport data field: {name}"
121 )));
122 };
123 deserialize_data_field("transport data field", name, value)
124 }
125
126 pub fn optional_data_field_as<T>(&self, name: &str) -> Result<Option<T>>
127 where
128 T: DeserializeOwned,
129 {
130 self.data_field(name)?
131 .map(|value| deserialize_data_field("transport data field", name, value))
132 .transpose()
133 }
134
135 pub fn data_field_string(&self, name: &str) -> Result<String> {
136 let Some(value) = self.data_field(name)? else {
137 return Err(BootError::BadRequest(format!(
138 "missing transport data field: {name}"
139 )));
140 };
141 data_field_value_to_string(value)
142 }
143
144 pub fn optional_data_field_string(&self, name: &str) -> Result<Option<String>> {
145 self.data_field(name)?
146 .map(data_field_value_to_string)
147 .transpose()
148 }
149
150 pub fn validated_data<T>(&self) -> Result<T>
151 where
152 T: DeserializeOwned + Validate,
153 {
154 validate_value(self.data_as::<T>()?)
155 }
156}
157
158fn deserialize_data_field<T>(label: &str, name: &str, value: Value) -> Result<T>
159where
160 T: DeserializeOwned,
161{
162 serde_json::from_value(value)
163 .map_err(|error| BootError::BadRequest(format!("invalid {label} {name}: {error}")))
164}
165
166fn data_field_value_to_string(value: Value) -> Result<String> {
167 match value {
168 Value::String(value) => Ok(value),
169 Value::Bool(value) => Ok(value.to_string()),
170 Value::Number(value) => Ok(value.to_string()),
171 Value::Array(_) | Value::Object(_) => {
172 serde_json::to_string(&value).map_err(|error| BootError::BadRequest(error.to_string()))
173 }
174 Value::Null => Ok("null".to_string()),
175 }
176}
177
178#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
180pub struct TransportReply {
181 #[serde(default)]
182 pub data: Value,
183}
184
185impl TransportReply {
186 pub fn new(data: impl Into<Value>) -> Self {
187 Self { data: data.into() }
188 }
189
190 pub fn data(&self) -> &Value {
191 &self.data
192 }
193
194 pub fn text(data: impl Into<String>) -> Self {
195 Self::new(Value::String(data.into()))
196 }
197
198 pub fn json<T>(data: &T) -> Result<Self>
199 where
200 T: Serialize,
201 {
202 Ok(Self::new(
203 serde_json::to_value(data).map_err(|err| BootError::Internal(err.to_string()))?,
204 ))
205 }
206
207 pub fn data_as<T>(&self) -> Result<T>
208 where
209 T: DeserializeOwned,
210 {
211 serde_json::from_value(self.data.clone())
212 .map_err(|err| BootError::BadRequest(err.to_string()))
213 }
214}
215
216pub trait IntoTransportReply {
218 fn into_transport_reply(self) -> Option<TransportReply>;
219}
220
221impl IntoTransportReply for TransportReply {
222 fn into_transport_reply(self) -> Option<TransportReply> {
223 Some(self)
224 }
225}
226
227impl IntoTransportReply for Option<TransportReply> {
228 fn into_transport_reply(self) -> Option<TransportReply> {
229 self
230 }
231}
232
233impl IntoTransportReply for Value {
234 fn into_transport_reply(self) -> Option<TransportReply> {
235 Some(TransportReply::new(self))
236 }
237}
238
239impl IntoTransportReply for Option<Value> {
240 fn into_transport_reply(self) -> Option<TransportReply> {
241 self.map(TransportReply::new)
242 }
243}
244
245impl IntoTransportReply for () {
246 fn into_transport_reply(self) -> Option<TransportReply> {
247 None
248 }
249}
250
251#[derive(Debug, Clone, Copy, PartialEq, Eq)]
252pub enum MessagePatternKind {
253 RequestResponse,
254 Event,
255}
256
257impl MessagePatternKind {
258 pub fn as_str(self) -> &'static str {
259 match self {
260 Self::RequestResponse => "request-response",
261 Self::Event => "event",
262 }
263 }
264}
265
266#[derive(Debug, Clone)]
268pub struct TransportContext {
269 pub pattern: String,
270 pub kind: MessagePatternKind,
271 pub module_name: Option<String>,
272 execution_context: ExecutionContext,
273}
274
275impl TransportContext {
276 fn new(definition: &MessagePatternDefinition, pattern: &str) -> Self {
277 let pattern = pattern.to_string();
278 let kind = definition.kind;
279 let module_name = definition.module_name.clone();
280 let metadata = definition.metadata.clone();
281 let execution_context = ExecutionContext::transport(
282 pattern.clone(),
283 ExecutionTransportKind::from(kind),
284 module_name.clone(),
285 metadata,
286 );
287 Self {
288 pattern,
289 kind,
290 module_name,
291 execution_context,
292 }
293 }
294
295 pub fn execution_context(&self) -> &ExecutionContext {
296 &self.execution_context
297 }
298
299 pub fn into_execution_context(self) -> ExecutionContext {
300 self.execution_context
301 }
302}
303
304impl Deref for TransportContext {
305 type Target = ExecutionContext;
306
307 fn deref(&self) -> &Self::Target {
308 self.execution_context()
309 }
310}
311
312impl From<MessagePatternKind> for ExecutionTransportKind {
313 fn from(kind: MessagePatternKind) -> Self {
314 match kind {
315 MessagePatternKind::RequestResponse => Self::RequestResponse,
316 MessagePatternKind::Event => Self::Event,
317 }
318 }
319}
320
321pub trait TransportPipe: Send + Sync + 'static {
323 fn transform(&self, message: TransportMessage) -> BoxFuture<'static, Result<TransportMessage>>;
324}
325
326impl<F, Fut> TransportPipe for F
327where
328 F: Fn(TransportMessage) -> Fut + Send + Sync + 'static,
329 Fut: Future<Output = Result<TransportMessage>> + Send + 'static,
330{
331 fn transform(&self, message: TransportMessage) -> BoxFuture<'static, Result<TransportMessage>> {
332 Box::pin(self(message))
333 }
334}
335
336pub trait TransportGuard: Send + Sync + 'static {
338 fn can_activate(&self, context: TransportContext) -> BoxFuture<'static, Result<bool>>;
339}
340
341impl<F, Fut> TransportGuard for F
342where
343 F: Fn(TransportContext) -> Fut + Send + Sync + 'static,
344 Fut: Future<Output = Result<bool>> + Send + 'static,
345{
346 fn can_activate(&self, context: TransportContext) -> BoxFuture<'static, Result<bool>> {
347 Box::pin(self(context))
348 }
349}
350
351struct ExecutionTransportGuard<G> {
352 inner: G,
353}
354
355impl<G> TransportGuard for ExecutionTransportGuard<G>
356where
357 G: Guard,
358{
359 fn can_activate(&self, context: TransportContext) -> BoxFuture<'static, Result<bool>> {
360 self.inner.can_activate(context.into_execution_context())
361 }
362}
363
364pub trait TransportInterceptor: Send + Sync + 'static {
366 fn before(&self, _context: TransportContext) -> BoxFuture<'static, Result<()>> {
367 Box::pin(async { Ok(()) })
368 }
369
370 fn after(
371 &self,
372 _context: TransportContext,
373 reply: Option<TransportReply>,
374 ) -> BoxFuture<'static, Result<Option<TransportReply>>> {
375 Box::pin(async move { Ok(reply) })
376 }
377}
378
379struct ExecutionTransportInterceptor<I> {
380 inner: I,
381}
382
383impl<I> TransportInterceptor for ExecutionTransportInterceptor<I>
384where
385 I: ExecutionInterceptor,
386{
387 fn before(&self, context: TransportContext) -> BoxFuture<'static, Result<()>> {
388 self.inner.before(context.into_execution_context())
389 }
390
391 fn after(
392 &self,
393 context: TransportContext,
394 reply: Option<TransportReply>,
395 ) -> BoxFuture<'static, Result<Option<TransportReply>>> {
396 let future = self.inner.after(context.into_execution_context());
397 Box::pin(async move {
398 future.await?;
399 Ok(reply)
400 })
401 }
402}
403
404type TransportHandlerFuture = BoxFuture<'static, Result<Option<TransportReply>>>;
405type MessageValidator =
406 Arc<dyn Fn(TransportMessage, ValidationOptions) -> Result<TransportMessage> + Send + Sync>;
407
408trait TransportMessageHandler: Send + Sync + 'static {
409 fn call(&self, message: TransportMessage) -> TransportHandlerFuture;
410}
411
412struct TransportHandlerAdapter<H> {
413 handler: H,
414}
415
416impl<H, Fut, R> TransportMessageHandler for TransportHandlerAdapter<H>
417where
418 H: Fn(TransportMessage) -> Fut + Send + Sync + 'static,
419 Fut: Future<Output = Result<R>> + Send + 'static,
420 R: IntoTransportReply + Send + 'static,
421{
422 fn call(&self, message: TransportMessage) -> TransportHandlerFuture {
423 let future = (self.handler)(message);
424 Box::pin(async move { Ok(future.await?.into_transport_reply()) })
425 }
426}
427
428#[derive(Clone)]
430pub struct MessagePatternDefinition {
431 pattern: String,
432 kind: MessagePatternKind,
433 handler: Arc<dyn TransportMessageHandler>,
434 pipes: Vec<PipelineComponent<dyn TransportPipe>>,
435 guards: Vec<PipelineComponent<dyn TransportGuard>>,
436 interceptors: Vec<PipelineComponent<dyn TransportInterceptor>>,
437 filters: Vec<PipelineComponent<dyn TransportExceptionFilter>>,
438 validators: Vec<MessageValidator>,
439 validation_enabled: bool,
440 validation_disabled: bool,
441 validation_options: ValidationOptions,
442 metadata: BTreeMap<String, Value>,
443 module_name: Option<String>,
444}
445
446impl MessagePatternDefinition {
447 pub fn request<H, Fut, R>(pattern: impl Into<String>, handler: H) -> Result<Self>
448 where
449 H: Fn(TransportMessage) -> Fut + Send + Sync + 'static,
450 Fut: Future<Output = Result<R>> + Send + 'static,
451 R: IntoTransportReply + Send + 'static,
452 {
453 Self::new(pattern, MessagePatternKind::RequestResponse, handler)
454 }
455
456 pub fn event<H, Fut>(pattern: impl Into<String>, handler: H) -> Result<Self>
457 where
458 H: Fn(TransportMessage) -> Fut + Send + Sync + 'static,
459 Fut: Future<Output = Result<()>> + Send + 'static,
460 {
461 Self::new(pattern, MessagePatternKind::Event, handler)
462 }
463
464 pub fn request_json<T, H, Fut, R>(pattern: impl Into<String>, handler: H) -> Result<Self>
465 where
466 T: DeserializeOwned + Send + 'static,
467 H: Fn(T) -> Fut + Send + Sync + 'static,
468 Fut: Future<Output = Result<R>> + Send + 'static,
469 R: Serialize + Send + 'static,
470 {
471 Self::request(pattern, move |message: TransportMessage| {
472 let payload = message.data_as::<T>();
473 let future = payload.map(&handler);
474 async move {
475 let response = future?.await?;
476 TransportReply::json(&response)
477 }
478 })
479 }
480
481 pub fn request_validated_json<T, H, Fut, R>(
482 pattern: impl Into<String>,
483 handler: H,
484 ) -> Result<Self>
485 where
486 T: DeserializeOwned + Validate + Send + 'static,
487 H: Fn(T) -> Fut + Send + Sync + 'static,
488 Fut: Future<Output = Result<R>> + Send + 'static,
489 R: Serialize + Send + 'static,
490 {
491 Self::request(pattern, move |message: TransportMessage| {
492 let payload = message.validated_data::<T>();
493 let future = payload.map(&handler);
494 async move {
495 let response = future?.await?;
496 TransportReply::json(&response)
497 }
498 })
499 }
500
501 pub fn event_json<T, H, Fut>(pattern: impl Into<String>, handler: H) -> Result<Self>
502 where
503 T: DeserializeOwned + Send + 'static,
504 H: Fn(T) -> Fut + Send + Sync + 'static,
505 Fut: Future<Output = Result<()>> + Send + 'static,
506 {
507 Self::event(pattern, move |message: TransportMessage| {
508 let payload = message.data_as::<T>();
509 let future = payload.map(&handler);
510 async move { future?.await }
511 })
512 }
513
514 pub fn event_validated_json<T, H, Fut>(pattern: impl Into<String>, handler: H) -> Result<Self>
515 where
516 T: DeserializeOwned + Validate + Send + 'static,
517 H: Fn(T) -> Fut + Send + Sync + 'static,
518 Fut: Future<Output = Result<()>> + Send + 'static,
519 {
520 Self::event(pattern, move |message: TransportMessage| {
521 let payload = message.validated_data::<T>();
522 let future = payload.map(&handler);
523 async move { future?.await }
524 })
525 }
526
527 fn new<H, Fut, R>(
528 pattern: impl Into<String>,
529 kind: MessagePatternKind,
530 handler: H,
531 ) -> Result<Self>
532 where
533 H: Fn(TransportMessage) -> Fut + Send + Sync + 'static,
534 Fut: Future<Output = Result<R>> + Send + 'static,
535 R: IntoTransportReply + Send + 'static,
536 {
537 let pattern = pattern.into();
538 validate_pattern(&pattern)?;
539 Ok(Self {
540 pattern,
541 kind,
542 handler: Arc::new(TransportHandlerAdapter { handler }),
543 pipes: Vec::new(),
544 guards: Vec::new(),
545 interceptors: Vec::new(),
546 filters: Vec::new(),
547 validators: Vec::new(),
548 validation_enabled: false,
549 validation_disabled: false,
550 validation_options: ValidationOptions::default(),
551 metadata: BTreeMap::new(),
552 module_name: None,
553 })
554 }
555
556 pub fn pattern(&self) -> &str {
557 &self.pattern
558 }
559
560 pub fn kind(&self) -> MessagePatternKind {
561 self.kind
562 }
563
564 pub fn module_name(&self) -> Option<&str> {
565 self.module_name.as_deref()
566 }
567
568 pub fn metadata(&self) -> &BTreeMap<String, Value> {
569 &self.metadata
570 }
571
572 pub fn metadata_value(&self, key: &str) -> Option<&Value> {
573 self.metadata.get(key)
574 }
575
576 pub fn with_metadata<V>(self, key: impl Into<String>, value: V) -> Result<Self>
577 where
578 V: Serialize,
579 {
580 let key = key.into();
581 let value = serde_json::to_value(value).map_err(|error| {
582 BootError::Internal(format!(
583 "failed to serialize message pattern metadata `{key}`: {error}"
584 ))
585 })?;
586 Ok(self.with_metadata_value(key, value))
587 }
588
589 pub fn with_metadata_value(mut self, key: impl Into<String>, value: Value) -> Self {
590 self.metadata.insert(key.into(), value);
591 self
592 }
593
594 pub fn with_pipe<P>(mut self, pipe: P) -> Self
595 where
596 P: TransportPipe,
597 {
598 self.pipes
599 .push(PipelineComponent::<dyn TransportPipe>::new(pipe));
600 self
601 }
602
603 pub fn with_guard<G>(mut self, guard: G) -> Self
604 where
605 G: TransportGuard,
606 {
607 self.guards
608 .push(PipelineComponent::<dyn TransportGuard>::new(guard));
609 self
610 }
611
612 pub fn with_execution_guard<G>(mut self, guard: G) -> Self
613 where
614 G: Guard,
615 {
616 self.guards
617 .push(PipelineComponent::<dyn TransportGuard>::new(
618 ExecutionTransportGuard { inner: guard },
619 ));
620 self
621 }
622
623 pub(crate) fn with_execution_pipeline_prefix(
624 mut self,
625 guards: &[Arc<dyn Guard>],
626 interceptors: &[Arc<dyn ExecutionInterceptor>],
627 ) -> Self {
628 self.guards = prepend_execution_guards(guards, self.guards);
629 self.interceptors = prepend_execution_interceptors(interceptors, self.interceptors);
630 self
631 }
632
633 pub(crate) fn with_guard_prefix(mut self, guards: &[Arc<dyn TransportGuard>]) -> Self {
634 let mut merged = guards
635 .iter()
636 .cloned()
637 .map(PipelineComponent::<dyn TransportGuard>::from_arc)
638 .collect::<Vec<_>>();
639 merged.extend(self.guards);
640 self.guards = merged;
641 self
642 }
643
644 pub(crate) fn with_interceptor_prefix(
645 mut self,
646 interceptors: &[Arc<dyn TransportInterceptor>],
647 ) -> Self {
648 let mut merged = interceptors
649 .iter()
650 .cloned()
651 .map(PipelineComponent::<dyn TransportInterceptor>::from_arc)
652 .collect::<Vec<_>>();
653 merged.extend(self.interceptors);
654 self.interceptors = merged;
655 self
656 }
657
658 pub(crate) fn with_pipe_prefix(mut self, pipes: &[Arc<dyn TransportPipe>]) -> Self {
659 let mut merged = pipes
660 .iter()
661 .cloned()
662 .map(PipelineComponent::<dyn TransportPipe>::from_arc)
663 .collect::<Vec<_>>();
664 merged.extend(self.pipes);
665 self.pipes = merged;
666 self
667 }
668
669 pub(crate) fn with_filter_prefix(
670 mut self,
671 filters: &[Arc<dyn TransportExceptionFilter>],
672 ) -> Self {
673 let mut merged = filters
674 .iter()
675 .cloned()
676 .map(PipelineComponent::<dyn TransportExceptionFilter>::from_arc)
677 .collect::<Vec<_>>();
678 merged.extend(self.filters);
679 self.filters = merged;
680 self
681 }
682
683 pub fn with_interceptor<I>(mut self, interceptor: I) -> Self
684 where
685 I: TransportInterceptor,
686 {
687 self.interceptors
688 .push(PipelineComponent::<dyn TransportInterceptor>::new(
689 interceptor,
690 ));
691 self
692 }
693
694 pub fn with_execution_interceptor<I>(mut self, interceptor: I) -> Self
695 where
696 I: ExecutionInterceptor,
697 {
698 self.interceptors
699 .push(PipelineComponent::<dyn TransportInterceptor>::new(
700 ExecutionTransportInterceptor { inner: interceptor },
701 ));
702 self
703 }
704
705 pub fn with_filter<F>(mut self, filter: F) -> Self
706 where
707 F: TransportExceptionFilter,
708 {
709 self.filters
710 .push(PipelineComponent::<dyn TransportExceptionFilter>::new(
711 filter,
712 ));
713 self
714 }
715
716 pub fn with_catch_filter<I, F>(self, kinds: I, filter: F) -> Self
717 where
718 I: IntoIterator<Item = BootErrorKind>,
719 F: TransportExceptionFilter,
720 {
721 self.with_filter(catch_errors(kinds, filter))
722 }
723
724 pub(crate) fn with_pipeline_overrides(mut self, overrides: &PipelineOverrides) -> Self {
725 overrides.apply_to_transport_pipes(&mut self.pipes);
726 overrides.apply_to_transport_guards(&mut self.guards);
727 overrides.apply_to_transport_interceptors(&mut self.interceptors);
728 overrides.apply_to_transport_filters(&mut self.filters);
729 self
730 }
731
732 pub fn with_validation(mut self) -> Self {
733 self.validation_enabled = true;
734 self.validation_disabled = false;
735 self
736 }
737
738 pub fn with_validation_options(mut self, options: ValidationOptions) -> Self {
739 self.validation_enabled = true;
740 self.validation_disabled = false;
741 self.validation_options = self.validation_options.merge(options);
742 self
743 }
744
745 pub fn without_validation(mut self) -> Self {
746 self.validation_enabled = false;
747 self.validation_disabled = true;
748 self
749 }
750
751 pub(crate) fn with_validation_prefix(
752 mut self,
753 validation_enabled: bool,
754 validation_options: ValidationOptions,
755 ) -> Self {
756 if !self.validation_disabled {
757 self.validation_enabled = validation_enabled || self.validation_enabled;
758 self.validation_options = validation_options.merge(self.validation_options);
759 }
760 self
761 }
762
763 pub fn with_payload_validation<T>(mut self) -> Self
764 where
765 T: DeserializeOwned + Validate + 'static,
766 {
767 self.validators.push(Arc::new(|message, _| {
768 message.validated_data::<T>().map(|_| message)
769 }));
770 self.with_validation()
771 }
772
773 pub fn with_payload_validation_options<T>(mut self, options: ValidationOptions) -> Self
774 where
775 T: DeserializeOwned + Serialize + Validate + ValidationSchema + 'static,
776 {
777 self.validators
778 .push(Arc::new(move |mut message, inherited_options| {
779 let options = inherited_options.merge(options);
780 let data = validate_json_value_with_options::<T>(
781 message.data.clone(),
782 options,
783 "message property",
784 )?;
785 if options.transform || options.whitelist {
786 message.data = data;
787 }
788 Ok(message)
789 }));
790 self.with_validation()
791 }
792
793 pub async fn dispatch(&self, message: TransportMessage) -> Result<Option<TransportReply>> {
794 let context = TransportContext::new(self, &message.pattern);
795 match self.dispatch_pipeline(message, context.clone()).await {
796 Ok(reply) => Ok(reply),
797 Err(error) => self.handle_error(context, error).await,
798 }
799 }
800
801 async fn dispatch_pipeline(
802 &self,
803 mut message: TransportMessage,
804 context: TransportContext,
805 ) -> Result<Option<TransportReply>> {
806 if message.pattern != self.pattern {
807 return Err(BootError::NotFound(format!(
808 "message pattern {}",
809 message.pattern
810 )));
811 }
812
813 for guard in &self.guards {
814 let can_activate = guard.inner().can_activate(context.clone()).await?;
815 if !can_activate {
816 return Err(BootError::Forbidden(format!(
817 "message pattern {}",
818 message.pattern
819 )));
820 }
821 }
822
823 for interceptor in &self.interceptors {
824 interceptor.inner().before(context.clone()).await?;
825 }
826
827 for pipe in &self.pipes {
828 message = pipe.inner().transform(message).await?;
829 }
830
831 if self.validation_enabled {
832 for validator in &self.validators {
833 message = validator(message, self.validation_options)?;
834 }
835 }
836
837 let mut reply = self.handler.call(message).await?;
838 if self.kind == MessagePatternKind::Event {
839 reply = None;
840 }
841
842 for interceptor in self.interceptors.iter().rev() {
843 reply = interceptor.inner().after(context.clone(), reply).await?;
844 }
845 Ok(reply)
846 }
847
848 async fn handle_error(
849 &self,
850 context: TransportContext,
851 error: BootError,
852 ) -> Result<Option<TransportReply>> {
853 for filter in self.filters.iter().rev() {
854 if let Some(response) = filter
855 .inner()
856 .catch(context.clone(), error.clone_for_filter())
857 .await?
858 {
859 return Ok(if self.kind == MessagePatternKind::Event {
860 None
861 } else {
862 response.into_reply()
863 });
864 }
865 }
866 Err(error)
867 }
868
869 pub(crate) fn with_module_name(mut self, module_name: &str) -> Self {
870 self.module_name = Some(module_name.to_string());
871 self
872 }
873}
874
875fn prepend_execution_guards(
876 prefix: &[Arc<dyn Guard>],
877 values: Vec<PipelineComponent<dyn TransportGuard>>,
878) -> Vec<PipelineComponent<dyn TransportGuard>> {
879 let mut merged = prefix
880 .iter()
881 .cloned()
882 .map(|guard| {
883 PipelineComponent::<dyn TransportGuard>::new(ExecutionTransportGuard { inner: guard })
884 })
885 .collect::<Vec<_>>();
886 merged.extend(values);
887 merged
888}
889
890fn prepend_execution_interceptors(
891 prefix: &[Arc<dyn ExecutionInterceptor>],
892 values: Vec<PipelineComponent<dyn TransportInterceptor>>,
893) -> Vec<PipelineComponent<dyn TransportInterceptor>> {
894 let mut merged = prefix
895 .iter()
896 .cloned()
897 .map(|interceptor| {
898 PipelineComponent::<dyn TransportInterceptor>::new(ExecutionTransportInterceptor {
899 inner: interceptor,
900 })
901 })
902 .collect::<Vec<_>>();
903 merged.extend(values);
904 merged
905}
906
907pub trait MessageTransport {
909 type Output;
910
911 fn build(&self, app: crate::BootApplication) -> Result<Self::Output>;
912
913 fn serve(&self, app: crate::BootApplication) -> BoxFuture<'static, Result<()>>;
914}
915
916#[derive(Debug, Clone, Copy, Default)]
918pub struct InProcessTransport;
919
920impl InProcessTransport {
921 pub fn new() -> Self {
922 Self
923 }
924}
925
926impl MessageTransport for InProcessTransport {
927 type Output = InProcessTransportClient;
928
929 fn build(&self, app: crate::BootApplication) -> Result<Self::Output> {
930 Ok(InProcessTransportClient { app })
931 }
932
933 fn serve(&self, _app: crate::BootApplication) -> BoxFuture<'static, Result<()>> {
934 Box::pin(async { Ok(()) })
935 }
936}
937
938#[derive(Clone)]
940pub struct InProcessTransportClient {
941 app: crate::BootApplication,
942}
943
944impl InProcessTransportClient {
945 pub async fn send(&self, message: TransportMessage) -> Result<Option<TransportReply>> {
946 self.app.dispatch_message(message).await
947 }
948
949 pub async fn emit(&self, message: TransportMessage) -> Result<()> {
950 self.app.emit_message(message).await
951 }
952}
953
954fn validate_pattern(pattern: &str) -> Result<()> {
955 if pattern.trim().is_empty() {
956 return Err(BootError::BadRequest(
957 "message pattern cannot be empty".to_string(),
958 ));
959 }
960 Ok(())
961}