Skip to main content

dingtalk_stream/client/stream_/
send_message.rs

1use crate::frames::up_message::robot_message::{RobotGroupMessage, RobotMessage, RobotPrivateMessage};
2use crate::frames::{SendMessageCallback, SendMessageCallbackData};
3use crate::{ROBOT_SEND_GROUP_MESSAGE, ROBOT_SEND_PRIVATE_MESSAGE};
4use anyhow::anyhow;
5use serde_json::json;
6use tracing::info;
7
8impl super::DingTalkStream {
9    pub async fn send_message<M: Into<RobotMessage>>(&self, message: M) -> crate::Result<()> {
10        let message = message.into();
11        let http_client = self.http_client.clone();
12        let credential = self.credential.clone();
13        let access_token = self.get_access_token().await?;
14        match message {
15            RobotMessage::Private {
16                message,
17                send_result_cb,
18            } => {
19                let _ = Self::send_private_message(
20                    &http_client,
21                    &access_token,
22                    &credential.client_id,
23                    &message,
24                    send_result_cb.as_ref(),
25                )
26                .await?;
27            }
28            RobotMessage::Group {
29                message,
30                send_result_cb,
31            } => {
32                let _ = Self::send_group_message(
33                    &http_client,
34                    &access_token,
35                    &credential.client_id,
36                    &message,
37                    send_result_cb.as_ref(),
38                )
39                .await?;
40            }
41        };
42        Ok(())
43    }
44}
45
46impl super::DingTalkStream {
47    async fn send_private_message(
48        http_client: &reqwest::Client,
49        access_token: &str,
50        client_id: &str,
51        RobotPrivateMessage { user_ids, content }: &RobotPrivateMessage,
52        send_result_cb: Option<&SendMessageCallback>,
53    ) -> crate::Result<()> {
54        let (msg_key, msg_param) = content.to_up_msg()?;
55        let msg_md5 = format!("{:x}", md5::compute(&msg_param));
56        info!("Sending private robot-message[{}]: {}", msg_md5, msg_param);
57        let response = http_client
58            .post(ROBOT_SEND_PRIVATE_MESSAGE)
59            .header("x-acs-dingtalk-access-token", access_token)
60            .header("Content-Type", "application/json")
61            .json(&json!({
62                "robotCode": client_id,
63                "userIds": user_ids,
64                "msgParam": msg_param,
65                "msgKey": msg_key
66            }))
67            .send()
68            .await;
69        if let Some(cb) = send_result_cb {
70            Self::exec_send_cb(response, cb).await;
71        }
72        info!("Send private robot-message[{}] ok", msg_md5);
73        Ok(())
74    }
75
76    async fn send_group_message(
77        http_client: &reqwest::Client,
78        access_token: &str,
79        client_id: &str,
80        RobotGroupMessage { group_id, content }: &RobotGroupMessage,
81        send_result_cb: Option<&SendMessageCallback>,
82    ) -> crate::Result<()> {
83        let (msg_key, msg_param) = content.to_up_msg()?;
84        let msg_md5 = format!("{:x}", md5::compute(&msg_param));
85        info!("Sending group robot-message[{}]: {}", msg_md5, msg_param);
86        let response = http_client
87            .post(ROBOT_SEND_GROUP_MESSAGE)
88            .header("x-acs-dingtalk-access-token", access_token)
89            .header("Content-Type", "application/json")
90            .json(&json!({
91                "robotCode": client_id,
92                "openConversationId": group_id,
93                "msgParam": msg_param,
94                "msgKey": msg_key
95            }))
96            .send()
97            .await;
98        if let Some(cb) = send_result_cb {
99            Self::exec_send_cb(response, cb).await;
100        }
101        info!("Send group robot-message[{}] ok", msg_md5);
102        Ok(())
103    }
104
105    async fn exec_send_cb(
106        response: Result<reqwest::Response, reqwest::Error>,
107        cb: &SendMessageCallback,
108    ) {
109        match response {
110            Ok(response) => {
111                let code = response.status();
112                match response.text().await {
113                    Ok(text) => cb(Ok(SendMessageCallbackData {
114                        http_status: code.as_u16(),
115                        text,
116                    })),
117                    Err(err) => cb(Err(anyhow!("{err}"))),
118                }
119            }
120            Err(err) => cb(Err(anyhow!("{err}"))),
121        }
122    }
123}