messenger_rs/
slack.rs

1use anyhow::{Context, Result};
2use reqwest::Client;
3use serde::Serialize;
4
5const SLACK_API_URL: &str = "https://slack.com/api/chat.postMessage";
6
7#[derive(Debug, Clone)]
8pub struct SlackClient {
9    token: String,
10    channel: String,
11    client: Client,
12}
13
14#[derive(Serialize)]
15struct SlackMessage<'a> {
16    channel: &'a str,
17    text: String,
18}
19
20pub trait IntoFormattedMessage {
21    fn into_formatted_message(self) -> String;
22}
23
24impl IntoFormattedMessage for String {
25    fn into_formatted_message(self) -> String {
26        self
27    }
28}
29
30impl IntoFormattedMessage for Vec<String> {
31    fn into_formatted_message(self) -> String {
32        self.join("\n")
33    }
34}
35
36impl SlackClient {
37    /// Create a new client.
38    pub fn new(token: String, channel: String) -> Self {
39        SlackClient {
40            token,
41            channel,
42            client: Client::new(),
43        }
44    }
45
46    /// Send slack message through Slack's API.
47    pub async fn send_message<T: IntoFormattedMessage>(&self, message: T) -> Result<()> {
48        let formatted_message = message.into_formatted_message();
49
50        let request = SlackMessage {
51            channel: &self.channel,
52            text: formatted_message,
53        };
54
55        let response = self
56            .client
57            .post(SLACK_API_URL)
58            .header("Content-type", "application/json;charset=utf-8")
59            .header("Authorization", format!("Bearer {}", self.token))
60            .json(&request)
61            .send()
62            .await
63            .context("Failed to send Slack message.")?
64            .json::<serde_json::Value>()
65            .await
66            .context("Failed to parse Slack response.")?;
67
68        if response["ok"] != true {
69            return Err(anyhow::anyhow!("Slack API error: {}", response["error"]));
70        }
71
72        Ok(())
73    }
74
75    /// Send slack message through Slack's API synchronously.
76    /// Ignores the future
77    pub fn send_message_sync<T: IntoFormattedMessage>(&self, message: T) -> Result<()> {
78        let formatted_message = message.into_formatted_message();
79
80        let request = SlackMessage {
81            channel: &self.channel,
82            text: formatted_message,
83        };
84        
85        self
86            .client
87            .post(SLACK_API_URL)
88            .header("Content-type", "application/json;charset=utf-8")
89            .header("Authorization", format!("Bearer {}", self.token))
90            .json(&request)
91            .send();
92
93        Ok(())
94    }
95}