open_lark/service/im/v1/message/
builders.rs

1use log::error;
2use serde::{Deserialize, Serialize};
3
4use crate::{
5    core::{
6        api_req::ApiRequest,
7        validation::{
8            message_limits, uuid_limits, validate_content_size, validate_required,
9            validate_string_length,
10        },
11    },
12    service::im::v1::message::{Message, SendMessageTrait},
13};
14
15use super::MessageService;
16
17/// 请求体
18#[derive(Debug, Clone, Default)]
19pub struct CreateMessageRequest {
20    pub api_req: ApiRequest,
21}
22
23impl CreateMessageRequest {
24    pub fn builder() -> CreateMessageRequestBuilder {
25        CreateMessageRequestBuilder::default()
26    }
27}
28
29#[derive(Default)]
30pub struct CreateMessageRequestBuilder {
31    request: CreateMessageRequest,
32}
33
34impl CreateMessageRequestBuilder {
35    /// 设置接收者ID
36    ///
37    /// # 参数
38    /// - `receive_id`: 消息接收者的ID
39    pub fn receive_id(mut self, receive_id: impl ToString) -> Self {
40        self.request
41            .api_req
42            .query_params
43            .insert("receive_id", receive_id.to_string());
44        self
45    }
46
47    /// 设置消息类型
48    ///
49    /// # 参数
50    /// - `msg_type`: 消息类型
51    pub fn msg_type(mut self, msg_type: impl ToString) -> Self {
52        self.request
53            .api_req
54            .query_params
55            .insert("msg_type", msg_type.to_string());
56        self
57    }
58
59    /// 设置消息内容
60    ///
61    /// # 参数
62    /// - `content`: 消息内容
63    pub fn content(mut self, content: impl ToString) -> Self {
64        self.request
65            .api_req
66            .query_params
67            .insert("content", content.to_string());
68        self
69    }
70
71    /// 设置消息接收者ID类型
72    ///
73    /// # 参数
74    /// - `receive_id_type`: 接收者ID类型,可选值:
75    ///   - `"open_id"`: Open ID(推荐)
76    ///   - `"user_id"`: User ID
77    ///   - `"union_id"`: Union ID
78    ///   - `"email"`: 邮箱地址
79    ///   - `"chat_id"`: 群聊ID
80    pub fn receive_id_type(mut self, receive_id_type: impl ToString) -> Self {
81        self.request
82            .api_req
83            .query_params
84            .insert("receive_id_type", receive_id_type.to_string());
85        self
86    }
87
88    /// 设置消息请求体
89    ///
90    /// # 参数
91    /// - `body`: 包含接收者ID、消息类型和内容的请求体
92    pub fn request_body(mut self, body: CreateMessageRequestBody) -> Self {
93        match serde_json::to_vec(&body) {
94            Ok(bytes) => {
95                self.request.api_req.body = bytes;
96            }
97            Err(e) => {
98                error!("Failed to serialize request body: {}", e);
99                // 在序列化失败时使用空 body,避免 panic
100                // 这允许请求继续,但可能会被 API 拒绝
101                self.request.api_req.body = Vec::new();
102            }
103        }
104        self
105    }
106
107    /// 构建最终的请求对象
108    pub fn build(self) -> CreateMessageRequest {
109        self.request
110    }
111}
112
113// 应用ExecutableBuilder trait到CreateMessageRequestBuilder
114crate::impl_executable_builder_owned!(
115    CreateMessageRequestBuilder,
116    MessageService,
117    CreateMessageRequest,
118    Message,
119    create
120);
121
122/// 发送消息 请求体
123#[derive(Debug, Default, Clone, Serialize, Deserialize)]
124pub struct CreateMessageRequestBody {
125    /// 消息接收者的ID,ID类型应与查询参数receive_id_type 对应;
126    /// 推荐使用 OpenID,获取方式可参考文档如何获取 Open ID?
127    ///
128    /// 示例值:"ou_7d8a6e6df7621556ce0d21922b676706ccs"
129    pub receive_id: String,
130    /// 消息类型 包括:text、post、image、file、audio、media、sticker、interactive、share_chat、
131    /// share_user等,类型定义请参考发送消息内容
132    ///
133    /// 示例值:"text"
134    pub msg_type: String,
135    /// 消息内容,JSON结构序列化后的字符串。不同msg_type对应不同内容,具体格式说明参考:
136    /// 发送消息内容
137    ///
138    /// 注意:
139    /// JSON字符串需进行转义,如换行符转义后为\\n
140    /// 文本消息请求体最大不能超过150KB
141    /// 卡片及富文本消息请求体最大不能超过30KB
142    /// 示例值:"{\"text\":\"test content\"}"
143    pub content: String,
144    /// 由开发者生成的唯一字符串序列,用于发送消息请求去重;
145    /// 持有相同uuid的请求1小时内至多成功发送一条消息
146    ///
147    /// 示例值:"选填,每次调用前请更换,如a0d69e20-1dd1-458b-k525-dfeca4015204"
148    ///
149    /// 数据校验规则:
150    ///
151    /// 最大长度:50 字符
152    pub uuid: Option<String>,
153}
154
155impl CreateMessageRequestBody {
156    pub fn builder() -> CreateMessageRequestBodyBuilder {
157        CreateMessageRequestBodyBuilder::default()
158    }
159}
160
161#[derive(Default)]
162pub struct CreateMessageRequestBodyBuilder {
163    request: CreateMessageRequestBody,
164}
165
166impl CreateMessageRequestBodyBuilder {
167    /// 消息接收者的ID,ID类型应与查询参数receive_id_type 对应;
168    /// 推荐使用 OpenID,获取方式可参考文档如何获取 Open ID?
169    ///
170    /// 示例值:"ou_7d8a6e6df7621556ce0d21922b676706ccs"
171    pub fn receive_id(mut self, receive_id: impl ToString) -> Self {
172        self.request.receive_id = receive_id.to_string();
173        self
174    }
175
176    /// 消息类型 包括:text、post、image、file、audio、media、sticker、interactive、share_chat、
177    /// share_user等,类型定义请参考发送消息内容
178    ///
179    /// 示例值:"text"
180    pub fn msg_type(mut self, msg_type: impl ToString) -> Self {
181        self.request.msg_type = msg_type.to_string();
182        self
183    }
184
185    /// 消息内容,JSON结构序列化后的字符串。不同msg_type对应不同内容,具体格式说明参考:
186    /// 发送消息内容
187    ///
188    /// 注意:
189    /// JSON字符串需进行转义,如换行符转义后为\\n
190    /// 文本消息请求体最大不能超过150KB
191    /// 卡片及富文本消息请求体最大不能超过30KB
192    /// 示例值:"{\"text\":\"test content\"}"
193    pub fn content(mut self, content: impl ToString) -> Self {
194        self.request.content = content.to_string();
195        self
196    }
197
198    /// 由开发者生成的唯一字符串序列,用于发送消息请求去重;
199    /// 持有相同uuid的请求1小时内至多成功发送一条消息
200    ///
201    /// 示例值:"选填,每次调用前请更换,如a0d69e20-1dd1-458b-k525-dfeca4015204"
202    ///
203    /// 数据校验规则:
204    ///
205    /// 最大长度:50 字符
206    pub fn uuid(mut self, uuid: impl ToString) -> Self {
207        let uuid_str = uuid.to_string();
208        // 使用验证工具函数
209        let validated_uuid = validate_string_length(uuid_str, uuid_limits::MAX_LENGTH, "UUID");
210        self.request.uuid = Some(validated_uuid);
211        self
212    }
213
214    pub fn build(self) -> CreateMessageRequestBody {
215        // 验证必填字段
216        validate_required(&self.request.receive_id, "receive_id");
217        validate_required(&self.request.msg_type, "msg_type");
218        validate_required(&self.request.content, "content");
219
220        // 验证内容长度(根据消息类型)
221        match self.request.msg_type.as_str() {
222            "text" => {
223                validate_content_size(
224                    &self.request.content,
225                    message_limits::TEXT_MESSAGE_MAX_SIZE,
226                    "Text message",
227                );
228            }
229            "post" | "interactive" => {
230                validate_content_size(
231                    &self.request.content,
232                    message_limits::RICH_MESSAGE_MAX_SIZE,
233                    "Post/interactive message",
234                );
235            }
236            _ => {
237                // 其他消息类型不验证内容大小
238            }
239        }
240
241        self.request
242    }
243}
244
245/// 更新消息请求
246#[derive(Debug, Clone, Default)]
247pub struct UpdateMessageRequest {
248    pub api_req: ApiRequest,
249}
250
251impl UpdateMessageRequest {
252    pub fn builder() -> UpdateMessageRequestBuilder {
253        UpdateMessageRequestBuilder::default()
254    }
255}
256
257#[derive(Default)]
258pub struct UpdateMessageRequestBuilder {
259    request: UpdateMessageRequest,
260}
261
262impl UpdateMessageRequestBuilder {
263    /// 设置消息内容
264    ///
265    /// # 参数
266    /// - `content`: 消息内容
267    pub fn content(mut self, content: impl ToString) -> Self {
268        self.request
269            .api_req
270            .query_params
271            .insert("content", content.to_string());
272        self
273    }
274
275    pub fn build(self) -> UpdateMessageRequest {
276        self.request
277    }
278}
279
280/// 便捷方法:使用消息内容类型构建发送消息请求
281impl CreateMessageRequest {
282    /// 使用SendMessageTrait类型创建消息请求
283    pub fn with_msg<T: SendMessageTrait>(receive_id: &str, msg: T, receive_id_type: &str) -> Self {
284        let mut api_req = ApiRequest::default();
285        api_req
286            .query_params
287            .insert("receive_id", receive_id.to_string());
288        api_req.query_params.insert("msg_type", msg.msg_type());
289        api_req.query_params.insert("content", msg.content());
290        api_req
291            .query_params
292            .insert("receive_id_type", receive_id_type.to_string());
293
294        Self { api_req }
295    }
296}