1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
use anyhow::{anyhow, Context};
use reqwest::{Response, StatusCode};

pub mod types;

use types::*;

#[derive(Debug, Clone)]
pub struct Client {
    url: String,
    http_client: reqwest::Client,
}

impl Client {
    pub fn new(url: &str) -> Client {
        Client {
            url: url.to_string(),
            http_client: reqwest::Client::new(),
        }
    }

    pub async fn send_message(
        &self,
        text: impl Into<String>,
        blocks: impl Into<Option<Vec<Block>>>,
    ) -> anyhow::Result<Response> {
        let res = self
            .http_client
            .post(&self.url)
            .header("Content-Type", "application/json")
            .json(&SlackMessageBody {
                text: text.into(),
                blocks: blocks.into(),
            })
            .send()
            .await?;
        let status = res.status();
        if status == StatusCode::OK {
            Ok(res)
        } else {
            let text = res.text().await.context(format!("status: {status}"))?;
            Err(anyhow!("status: {status} | text: {text}"))
        }
    }

    pub async fn send_message_with_header(
        &self,
        header: impl Into<String>,
        info: impl Into<Option<String>>,
    ) -> anyhow::Result<Response> {
        let header: String = header.into();
        let info: Option<String> = info.into();
        let blocks = match &info {
            Some(info) => Some(vec![Block::header(header.clone()), Block::section(info)]),
            None => Some(vec![Block::header(header.clone())]),
        };
        self.send_message(header, blocks).await
    }

    pub async fn send_mrkdwn_message(&self, text: impl Into<String>) -> anyhow::Result<Response> {
        let text = text.into();
        self.send_message(&text, vec![Block::section(&text)]).await
    }
}