hooksmith_core/sender.rs
1use std::future::Future;
2
3/// Common interface implemented by every hooksmith webhook client.
4///
5/// Each service crate defines its own [`Message`](WebhookSender::Message) and
6/// [`Error`](WebhookSender::Error) types and implements this trait. Application
7/// code can then be generic over the notification backend:
8///
9/// ```rust,ignore
10/// use hooksmith_core::WebhookSender;
11///
12/// async fn notify<S>(sender: &S, msg: &S::Message) -> Result<(), S::Error>
13/// where
14/// S: WebhookSender,
15/// {
16/// sender.send(msg).await
17/// }
18/// ```
19pub trait WebhookSender {
20 /// The message type accepted by this sender.
21 type Message;
22
23 /// The error type returned on failure.
24 type Error: std::error::Error;
25
26 /// Send a single message to the configured webhook endpoint.
27 fn send(
28 &self,
29 message: &Self::Message,
30 ) -> impl Future<Output = Result<(), Self::Error>> + Send;
31
32 /// Send multiple messages concurrently, fanning them out with
33 /// [`futures::future::join_all`].
34 ///
35 /// Returns one `Result` per message in the same order as the input slice.
36 /// A failure for one message does **not** abort the others.
37 ///
38 /// # Example
39 ///
40 /// ```rust,ignore
41 /// let results = sender.send_batch(&[&msg_a, &msg_b, &msg_c]).await;
42 /// for result in results {
43 /// result?;
44 /// }
45 /// ```
46 fn send_batch<'a>(
47 &'a self,
48 messages: &'a [&'a Self::Message],
49 ) -> impl Future<Output = Vec<Result<(), Self::Error>>> + Send + 'a
50 where
51 Self: Sync,
52 Self::Error: Send,
53 {
54 let futs: Vec<_> = messages.iter().copied().map(|m| self.send(m)).collect();
55 async move { futures::future::join_all(futs).await }
56 }
57}