hedwig/
lib.rs

1//! Hedwig is a message bus library that works with arbitrary pubsub services such as AWS SNS/SQS
2//! or Google Cloud Pubsub. Messages are validated before they are published. The publisher and
3//! consumer are de-coupled and fan-out is supported out of the box.
4//!
5//! The Rust library currently only supports publishing.
6//!
7//! # Examples
8//!
9//! Publish a message. Payload encoded with JSON and validated using a JSON Schema.
10//!
11//! ```
12//! use hedwig::{validators, Publisher, Consumer};
13//! # use uuid::Uuid;
14//! # use std::{path::Path, time::SystemTime};
15//! # use futures_util::{sink::SinkExt, stream::StreamExt};
16//! # #[cfg(not(all(feature = "protobuf", feature = "mock")))]
17//! # fn main() {}
18//! # #[cfg(all(feature = "protobuf", feature = "mock"))] // example uses a protobuf validator.
19//! # #[tokio::main(flavor = "current_thread")]
20//! # async fn main() -> Result<(), Box<dyn std::error::Error>> {
21//!
22//! #[derive(Clone, PartialEq, Eq, prost::Message)]
23//! struct UserCreatedMessage {
24//!     #[prost(string, tag = "1")]
25//!     user_id: String,
26//! }
27//!
28//! impl<'a> hedwig::EncodableMessage for UserCreatedMessage {
29//!     type Error = validators::ProstValidatorError;
30//!     type Validator = validators::ProstValidator;
31//!     fn topic(&self) -> hedwig::Topic {
32//!         "user.created".into()
33//!     }
34//!     fn encode(&self, validator: &Self::Validator) -> Result<hedwig::ValidatedMessage, Self::Error> {
35//!         Ok(validator.validate(
36//!             uuid::Uuid::new_v4(),
37//!             SystemTime::now(),
38//!             "user.created/1.0",
39//!             Default::default(),
40//!             self,
41//!         )?)
42//!     }
43//! }
44//!
45//! impl hedwig::DecodableMessage for UserCreatedMessage {
46//!     type Error = validators::ProstDecodeError<validators::prost::SchemaMismatchError>;
47//!     type Decoder =
48//!         validators::ProstDecoder<validators::prost::ExactSchemaMatcher<UserCreatedMessage>>;
49//!
50//!     fn decode(msg: hedwig::ValidatedMessage, decoder: &Self::Decoder) -> Result<Self, Self::Error> {
51//!         decoder.decode(msg)
52//!     }
53//! }
54//!
55//!
56//! let publisher = /* Some publisher */
57//! # hedwig::mock::MockPublisher::new();
58//! let consumer = /* Consumer associated to that publisher */
59//! # publisher.new_consumer("user.created", "example_subscription");
60//!
61//! let mut publish_sink = Publisher::<UserCreatedMessage>::publish_sink(publisher, validators::ProstValidator::new());
62//! let mut consumer_stream = consumer.consume::<UserCreatedMessage>(
63//!     validators::ProstDecoder::new(validators::prost::ExactSchemaMatcher::new("user.created/1.0")),
64//! );
65//!
66//! publish_sink.send(UserCreatedMessage { user_id: String::from("U_123") }).await?;
67//!
68//! assert_eq!(
69//!     "U_123",
70//!     consumer_stream.next().await.unwrap()?.ack().await?.user_id
71//! );
72//!
73//! # Ok(())
74//! # }
75//! ```
76#![cfg_attr(docsrs, feature(doc_cfg))]
77#![deny(missing_docs)]
78
79pub use hedwig_core::{message, Headers, Topic, ValidatedMessage};
80
81mod backends;
82mod consumer;
83mod publisher;
84mod tests;
85pub mod validators;
86
87#[allow(unused_imports)]
88pub use backends::*;
89
90pub use consumer::*;
91pub use publisher::*;
92
93// TODO make these public somewhere?
94#[cfg(feature = "google")]
95pub(crate) const HEDWIG_ID: &str = "hedwig_id";
96#[cfg(feature = "google")]
97pub(crate) const HEDWIG_MESSAGE_TIMESTAMP: &str = "hedwig_message_timestamp";
98#[cfg(feature = "google")]
99pub(crate) const HEDWIG_SCHEMA: &str = "hedwig_schema";
100#[cfg(feature = "google")]
101pub(crate) const HEDWIG_PUBLISHER: &str = "hedwig_publisher";
102#[cfg(feature = "google")]
103pub(crate) const HEDWIG_FORMAT_VERSION: &str = "hedwig_format_version";
104
105/// All errors that may be returned when operating top level APIs.
106#[derive(Debug, thiserror::Error)]
107#[non_exhaustive]
108pub enum Error {
109    /// Unable to encode message payload
110    #[error("Unable to encode message payload")]
111    EncodeMessage(#[source] Box<dyn std::error::Error + Send + Sync>),
112}