chatterbox 2.4.0

streamlined text notifications via telegram, email, slack, discord, gotify and resend
Documentation
use serde::{Deserialize, Serialize};
use serde_json::json;
use tokio::sync::broadcast::Receiver;

use crate::dispatcher::{Example, Handler};
use crate::message::Message;

#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)]
pub struct Discord {
    pub bot_token: String,
    pub channel_id: u64,
}

impl Example for Discord {
    fn example() -> Self {
        Discord {
            bot_token: "92349823049:DFIPJEXAMPLE-EXAMPLE123d-EXAMPLE".to_string(),
            channel_id: 1234567890,
        }
    }
}

impl Handler for Discord {
    fn start_handler(self, receiver: Receiver<String>) {
        let mut handler = DiscordHandler {
            config: self,
            receiver,
        };
        tokio::spawn(async move {
            handler.start().await;
        });
    }
}

async fn send_message(
    bot_token: &str,
    channel_id: &u64,
    message: Message,
) -> Result<(), reqwest::Error> {
    let client = reqwest::Client::new();
    let response = client
        .post(format!(
            "https://discord.com/api/v10/channels/{}/messages",
            channel_id
        ))
        .header("Authorization", format!("Bot {}", bot_token))
        .header("Content-Type", "application/json")
        .json(&json!({
                "embeds": [{
                    "title": message.title,
                    "description": message.body,
                }]
        }))
        .send()
        .await?;

    response.error_for_status()?;

    Ok(())
}

pub struct DiscordHandler {
    pub(crate) config: Discord,
    pub(crate) receiver: Receiver<String>,
}

impl DiscordHandler {
    pub async fn start(&mut self) {
        while let Ok(data) = self.receiver.recv().await {
            let message = Message::from_json(data);
            send_message(&self.config.bot_token, &self.config.channel_id, message)
                .await
                .expect("failed sending message");
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    use std;

    #[test]
    fn test_example() {
        Discord::example();
    }

    #[tokio::test]
    async fn test_dispatch_example() {
        let bot_token = std::env::var("CHATTERBOX_DISCORD_BOT_TOKEN").unwrap();
        let channel_id = std::env::var("CHATTERBOX_DISCORD_CHANNEL_ID").unwrap();
        let channel_id = channel_id.parse::<u64>().unwrap();
        let test_message = Message::test_example();
        send_message(&bot_token, &channel_id, test_message)
            .await
            .unwrap();
    }
}