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(&self, _container: &Container) -> Result<Option<serde_json::Value>, Error> {
25 Ok(None)
26 }
27
28 async fn to_slack(&self, _container: &Container) -> Result<Option<SlackMessage>, Error> {
29 Ok(None)
30 }
31}
32
33#[derive(Debug, Clone, serde::Serialize)]
34pub struct SlackMessage {
35 pub webhook: String,
36 pub text: String,
37}
38
39pub async fn notify<N: Notification>(
40 container: &Container,
41 notification: &N,
42) -> 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!(?payload, "notification stored in database channel (POC stub)");
53 }
54 }
55 Channel::Slack => {
56 if let Some(slack) = notification.to_slack(container).await? {
57 tracing::info!(?slack, "notification posted to slack channel (POC stub)");
58 }
59 }
60 }
61 }
62 Ok(())
63}