55
55
//! user_id: String,
56
56
//! }
57
57
//!
58
- //! impl<'a> hedwig::Message for &'a UserCreatedMessage {
58
+ //! impl<'a> hedwig::publish::EncodableMessage for &'a UserCreatedMessage {
59
59
//! type Error = hedwig::validators::JsonSchemaValidatorError;
60
60
//! type Validator = hedwig::validators::JsonSchemaValidator;
61
61
//! fn topic(&self) -> hedwig::Topic { "user.created" }
72
72
//! }
73
73
//!
74
74
//! let publisher = /* Some publisher */
75
- //! # hedwig::publishers ::NullPublisher;
75
+ //! # hedwig::publish ::NullPublisher;
76
76
//! let validator = hedwig::validators::JsonSchemaValidator::new(schema)?;
77
- //! let mut batch = hedwig::PublishBatch::new();
77
+ //! let mut batch = hedwig::publish:: PublishBatch::new();
78
78
//! batch.message(&validator, &UserCreatedMessage { user_id: String::from("U_123") });
79
79
//! let mut result_stream = batch.publish(&publisher);
80
- //! let mut next_batch = hedwig::PublishBatch::new();
80
+ //! let mut next_batch = hedwig::publish:: PublishBatch::new();
81
81
//! async {
82
82
//! while let Some(result) = result_stream.next().await {
83
83
//! match result {
105
105
#![ cfg_attr( not( test) , deny( unused) ) ]
106
106
#![ cfg_attr( docsrs, feature( doc_cfg) ) ]
107
107
108
- use std:: {
109
- collections:: BTreeMap ,
110
- pin:: Pin ,
111
- task:: { Context , Poll } ,
112
- time:: SystemTime ,
113
- } ;
108
+ use std:: { collections:: BTreeMap , time:: SystemTime } ;
114
109
115
- use futures_util:: {
116
- ready,
117
- stream:: { self , Stream } ,
118
- } ;
119
- use pin_project:: pin_project;
120
110
use uuid:: Uuid ;
121
111
122
- pub mod publishers;
112
+ #[ cfg( feature = "publish" ) ]
113
+ #[ cfg_attr( docsrs, doc( cfg( feature = "publish" ) ) ) ]
114
+ pub mod publish;
115
+
123
116
#[ cfg( test) ]
124
117
mod tests;
125
118
pub mod validators;
126
119
127
- #[ cfg( feature = "sink" ) ]
128
- #[ cfg_attr( docsrs, doc( cfg( feature = "sink" ) ) ) ]
129
- pub mod sink;
130
-
131
120
/// A message queue topic name to which messages can be published
132
121
pub type Topic = & ' static str ;
133
122
@@ -140,46 +129,6 @@ pub enum Error {
140
129
EncodeMessage ( #[ source] Box < dyn std:: error:: Error + Send + Sync > ) ,
141
130
}
142
131
143
- /// Message publishers.
144
- ///
145
- /// Message publishers deliver a validated message to an endpoint, possibly a remote one. Message
146
- /// publishers may also additionally validate a message for publisher-specific requirements (e.g.
147
- /// size).
148
- pub trait Publisher {
149
- /// The identifier for a successfully published message.
150
- type MessageId : ' static ;
151
-
152
- /// The error that this publisher returns when publishing of a message fails.
153
- type MessageError : std:: error:: Error + Send + Sync + ' static ;
154
-
155
- /// The stream of results that the `publish` method returns.
156
- type PublishStream : Stream < Item = Result < Self :: MessageId , Self :: MessageError > > ;
157
-
158
- /// Publish a batch of messages.
159
- ///
160
- /// The output stream shall return a result for each message in `messages` slice in order.
161
- fn publish < ' a , I > ( & self , topic : Topic , messages : I ) -> Self :: PublishStream
162
- where
163
- I : Iterator < Item = & ' a ValidatedMessage > + DoubleEndedIterator + ExactSizeIterator ;
164
- }
165
-
166
- /// Types that can be encoded and published.
167
- pub trait Message {
168
- /// The errors that can occur when calling the [`Message::encode`] method.
169
- ///
170
- /// Will typically match the errors returned by the [`Message::Validator`].
171
- type Error : std:: error:: Error + Send + Sync + ' static ;
172
-
173
- /// The validator to use for this message.
174
- type Validator ;
175
-
176
- /// Topic into which this message shall be published.
177
- fn topic ( & self ) -> Topic ;
178
-
179
- /// Encode the message payload.
180
- fn encode ( self , validator : & Self :: Validator ) -> Result < ValidatedMessage , Self :: Error > ;
181
- }
182
-
183
132
/// Custom headers associated with a message.
184
133
pub type Headers = BTreeMap < String , String > ;
185
134
@@ -236,138 +185,3 @@ impl ValidatedMessage {
236
185
& self . data
237
186
}
238
187
}
239
-
240
- /// A convenience builder for publishing in batches.
241
- #[ derive( Default , Debug ) ]
242
- pub struct PublishBatch {
243
- messages : BTreeMap < Topic , Vec < ValidatedMessage > > ,
244
- }
245
-
246
- impl PublishBatch {
247
- /// Construct a new batch.
248
- pub fn new ( ) -> Self {
249
- Self :: default ( )
250
- }
251
-
252
- /// Number of messages currently queued.
253
- pub fn len ( & self ) -> usize {
254
- self . messages . iter ( ) . fold ( 0 , |acc, ( _, v) | acc + v. len ( ) )
255
- }
256
-
257
- /// Whether the batch is empty.
258
- pub fn is_empty ( & self ) -> bool {
259
- self . messages . iter ( ) . all ( |( _, v) | v. is_empty ( ) )
260
- }
261
-
262
- /// Add an already validated message to be published in this batch.
263
- pub fn push ( & mut self , topic : Topic , validated : ValidatedMessage ) -> & mut Self {
264
- self . messages . entry ( topic) . or_default ( ) . push ( validated) ;
265
- self
266
- }
267
-
268
- /// Validate and add a message to be published in this batch.
269
- pub fn message < M : Message > (
270
- & mut self ,
271
- validator : & M :: Validator ,
272
- msg : M ,
273
- ) -> Result < & mut Self , Error > {
274
- let topic = msg. topic ( ) ;
275
- let validated = msg
276
- . encode ( validator)
277
- . map_err ( |e| Error :: EncodeMessage ( e. into ( ) ) ) ?;
278
- Ok ( self . push ( topic, validated) )
279
- }
280
-
281
- /// Publish all the enqueued messages, batching them for high efficiency.
282
- ///
283
- /// The order in which messages were added to the batch and the order of messages as seen by
284
- /// the publisher is not strictly preserved. As thus, the output stream will not preserve the
285
- /// message ordering either.
286
- ///
287
- /// Some kinds of errors that occur during publishing may not be transient. An example of such
288
- /// an error is attempting to publish a too large message with the [`GooglePubSubPublisher`].
289
- /// For
290
- /// errors like these retrying is most likely incorrect as they would just fail again.
291
- /// Publisher-specific error types may have methods to make a decision easier.
292
- ///
293
- /// [`GooglePubSubPublisher`]: publishers::GooglePubSubPublisher
294
- pub fn publish < P > ( self , publisher : & P ) -> PublishBatchStream < P :: PublishStream >
295
- where
296
- P : Publisher ,
297
- P :: PublishStream : Unpin ,
298
- {
299
- PublishBatchStream (
300
- self . messages
301
- . into_iter ( )
302
- . map ( |( topic, msgs) | TopicPublishStream :: new ( topic, msgs, publisher) )
303
- . collect :: < stream:: SelectAll < _ > > ( ) ,
304
- )
305
- }
306
- }
307
-
308
- /// The stream returned by the method [`PublishBatch::publish`](PublishBatch::publish)
309
- // This stream and TopicPublishStream are made explicit types instead of combinators like
310
- // map/zip/etc so that callers can refer to a concrete return type instead of `impl Stream`
311
- #[ pin_project]
312
- #[ derive( Debug ) ]
313
- pub struct PublishBatchStream < P > ( #[ pin] stream:: SelectAll < TopicPublishStream < P > > ) ;
314
-
315
- impl < P > Stream for PublishBatchStream < P >
316
- where
317
- P : Stream + Unpin ,
318
- {
319
- type Item = ( P :: Item , Topic , ValidatedMessage ) ;
320
-
321
- fn poll_next ( self : Pin < & mut Self > , cx : & mut Context ) -> Poll < Option < Self :: Item > > {
322
- self . project ( ) . 0 . poll_next ( cx)
323
- }
324
- }
325
-
326
- #[ pin_project]
327
- #[ derive( Debug ) ]
328
- struct TopicPublishStream < P > {
329
- topic : Topic ,
330
- messages : std:: vec:: IntoIter < ValidatedMessage > ,
331
-
332
- #[ pin]
333
- publish_stream : P ,
334
- }
335
-
336
- impl < P > TopicPublishStream < P > {
337
- fn new < Pub > ( topic : Topic , messages : Vec < ValidatedMessage > , publisher : & Pub ) -> Self
338
- where
339
- Pub : Publisher < PublishStream = P > ,
340
- P : Stream < Item = Result < Pub :: MessageId , Pub :: MessageError > > ,
341
- {
342
- let publish_stream = publisher. publish ( topic, messages. iter ( ) ) ;
343
- Self {
344
- topic,
345
- messages : messages. into_iter ( ) ,
346
- publish_stream,
347
- }
348
- }
349
- }
350
-
351
- impl < P > Stream for TopicPublishStream < P >
352
- where
353
- P : Stream ,
354
- {
355
- type Item = ( P :: Item , Topic , ValidatedMessage ) ;
356
-
357
- fn poll_next ( self : Pin < & mut Self > , cx : & mut Context ) -> Poll < Option < Self :: Item > > {
358
- let this = self . project ( ) ;
359
-
360
- // `map` has lifetime constraints that aren't nice here
361
- #[ allow( clippy:: manual_map) ]
362
- Poll :: Ready ( match ready ! ( this. publish_stream. poll_next( cx) ) {
363
- None => None ,
364
- Some ( stream_item) => Some ( (
365
- stream_item,
366
- this. topic ,
367
- this. messages
368
- . next ( )
369
- . expect ( "should be as many messages as publishes" ) ,
370
- ) ) ,
371
- } )
372
- }
373
- }
0 commit comments