anvil_core/
notification.rs1use async_trait::async_trait;
4
5use crate::container::Container;
6use crate::mail::OutgoingMessage;
7use crate::Error;
8
9#[derive(Debug, Clone)]
10pub enum Channel {
11 Mail,
12 Database,
13 Slack,
14}
15
16#[async_trait]
17pub trait Notification: Send + Sync {
18 fn channels(&self) -> Vec<Channel>;
19
20 async fn to_mail(&self, _container: &Container) -> Result<Option<OutgoingMessage>, Error> {
21 Ok(None)
22 }
23
24 async fn to_database(
25 &self,
26 _container: &Container,
27 ) -> Result<Option<serde_json::Value>, Error> {
28 Ok(None)
29 }
30
31 async fn to_slack(&self, _container: &Container) -> Result<Option<SlackMessage>, Error> {
32 Ok(None)
33 }
34}
35
36#[derive(Debug, Clone, serde::Serialize)]
37pub struct SlackMessage {
38 pub webhook: String,
39 pub text: String,
40}
41
42pub async fn notify<N: Notification>(container: &Container, notification: &N) -> Result<(), Error> {
43 for channel in notification.channels() {
44 match channel {
45 Channel::Mail => {
46 if let Some(msg) = notification.to_mail(container).await? {
47 container.mailer().send(msg).await?;
48 }
49 }
50 Channel::Database => {
51 if let Some(payload) = notification.to_database(container).await? {
52 tracing::info!(
53 ?payload,
54 "notification stored in database channel (POC stub)"
55 );
56 }
57 }
58 Channel::Slack => {
59 if let Some(slack) = notification.to_slack(container).await? {
60 tracing::info!(?slack, "notification posted to slack channel (POC stub)");
61 }
62 }
63 }
64 }
65 Ok(())
66}