Skip to main content

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 sequentially, collecting one `Result` per message
33    /// in the same order as the input slice.
34    /// A failure for one message does **not** abort the others.
35    ///
36    /// # Example
37    ///
38    /// ```rust,ignore
39    /// let results = sender.send_batch(&[&msg_a, &msg_b, &msg_c]).await;
40    /// for result in results {
41    ///     result?;
42    /// }
43    /// ```
44    fn send_batch<'a>(
45        &'a self,
46        messages: &'a [&'a Self::Message],
47    ) -> impl Future<Output = Vec<Result<(), Self::Error>>> + Send + 'a
48    where
49        Self: Sync,
50        Self::Error: Send,
51    {
52        // Build the futures outside the async block so the slice iterator is
53        // not captured (which would require Self::Message: Sync).
54        let futs: Vec<_> = messages.iter().copied().map(|m| self.send(m)).collect();
55        async move {
56            let mut results = Vec::with_capacity(futs.len());
57            for fut in futs {
58                results.push(fut.await);
59            }
60            results
61        }
62    }
63}