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

1use reqwest::Method;
2use serde::{Deserialize, Serialize};
3
4use crate::{
5    core::{
6        api_req::ApiRequest,
7        api_resp::{ApiResponseTrait, BaseResponse},
8        constants::AccessTokenType,
9        http::Transport,
10        req_option::RequestOption,
11        standard_response::StandardResponse,
12        validation::{self, ValidationResult},
13        SDKResult,
14    },
15    service::im::v1::message::{ListMessageIterator, Message},
16};
17
18use super::MessageService;
19
20/// 列表消息请求
21#[derive(Default, Clone)]
22pub struct ListMessageRequest {
23    pub api_req: ApiRequest,
24}
25
26impl ListMessageRequest {
27    pub fn builder() -> ListMessageRequestBuilder {
28        ListMessageRequestBuilder::default()
29    }
30}
31
32#[derive(Default)]
33pub struct ListMessageRequestBuilder {
34    request: ListMessageRequest,
35}
36
37impl ListMessageRequestBuilder {
38    /// 容器类型 ,目前可选值仅有"chat",包含单聊(p2p)和群聊(group)
39    ///
40    /// 示例值:chat
41    pub fn container_id_type(mut self, container_id_type: impl ToString) -> Self {
42        self.request
43            .api_req
44            .query_params
45            .insert("container_id_type", container_id_type.to_string());
46        self
47    }
48
49    /// 容器的id,即chat的id,详情参见[群ID 说明](https://open.feishu.cn/document/uAjLw4CM/ukTMukTMukTM/reference/im-v1/chat-id-description)
50    ///
51    /// 示例值:oc_234jsi43d3ssi993d43545f
52    pub fn container_id(mut self, container_id: impl ToString) -> Self {
53        self.request
54            .api_req
55            .query_params
56            .insert("container_id", container_id.to_string());
57        self
58    }
59
60    /// 历史信息的起始时间(秒级时间戳)
61    ///
62    /// 示例值:1609296809
63    pub fn start_time(mut self, start_time: i64) -> Self {
64        self.request
65            .api_req
66            .query_params
67            .insert("start_time", start_time.to_string());
68        self
69    }
70
71    /// 历史信息的结束时间(秒级时间戳)
72    ///
73    /// 示例值:1608594809
74    pub fn end_time(mut self, end_time: i64) -> Self {
75        self.request
76            .api_req
77            .query_params
78            .insert("end_time", end_time.to_string());
79        self
80    }
81
82    /// 消息排序方式
83    ///
84    /// 示例值:ByCreateTimeAsc
85    pub fn sort_type(mut self, sort_type: impl ToString) -> Self {
86        self.request
87            .api_req
88            .query_params
89            .insert("sort_type", sort_type.to_string());
90        self
91    }
92
93    /// 分页标记,第一次请求不填,表示从头开始遍历;分页查询结果还有更多项时会同时返回新的
94    /// page_token,下次遍历可采用该 page_token 获取查询结果
95    pub fn page_token(mut self, page_token: impl ToString) -> Self {
96        self.request
97            .api_req
98            .query_params
99            .insert("page_token", page_token.to_string());
100        self
101    }
102
103    /// 分页大小
104    ///
105    /// 示例值:20
106    ///
107    /// # 验证规则
108    ///
109    /// 分页大小必须在 1-500 之间,推荐值为 50
110    pub fn page_size(mut self, page_size: i32) -> Self {
111        // 验证分页大小
112        match validation::validate_page_size(page_size as u32, "page_size") {
113            ValidationResult::Valid => {}
114            ValidationResult::Warning(msg) => {
115                log::warn!("Page size validation warning: {}", msg);
116            }
117            ValidationResult::Invalid(msg) => {
118                log::error!("Invalid page size: {}", msg);
119                // 仍然设置值,但记录错误,让用户决定是否继续
120            }
121        }
122        self.request
123            .api_req
124            .query_params
125            .insert("page_size", page_size.to_string());
126        self
127    }
128
129    pub fn build(self) -> ListMessageRequest {
130        // 验证分页标记(如果存在)
131        if let Some(page_token) = self.request.api_req.query_params.get("page_token") {
132            match validation::validate_page_token(page_token, "page_token") {
133                ValidationResult::Valid => {}
134                ValidationResult::Warning(msg) => {
135                    log::warn!("Page token validation warning: {}", msg);
136                }
137                ValidationResult::Invalid(msg) => {
138                    log::error!("Invalid page token: {}", msg);
139                    // 仍然设置值,但记录错误
140                }
141            }
142        }
143
144        self.request
145    }
146
147    /// 使用分页验证构建器设置分页参数
148    ///
149    /// 这个方法提供了一个更安全的分页参数设置方式,会自动验证参数的有效性
150    pub fn with_pagination(
151        mut self,
152        page_size: Option<u32>,
153        page_token: Option<String>,
154    ) -> SDKResult<Self> {
155        let mut pagination_builder =
156            validation::pagination::PaginationRequestBuilder::<ListMessageRespData>::new();
157
158        if let Some(size) = page_size {
159            pagination_builder = pagination_builder.with_page_size(size);
160        }
161
162        if let Some(token) = page_token {
163            pagination_builder = pagination_builder.with_page_token(token);
164        }
165
166        // 构建分页参数
167        let params = pagination_builder.build()?;
168
169        // 应用到请求中
170        for (key, value) in params {
171            self.request.api_req.query_params.insert(key, value);
172        }
173
174        Ok(self)
175    }
176}
177
178crate::impl_executable_builder_owned!(
179    ListMessageRequestBuilder,
180    MessageService,
181    ListMessageRequest,
182    ListMessageRespData,
183    list
184);
185
186/// Response data for message listing
187#[derive(Debug, Serialize, Deserialize)]
188pub struct ListMessageRespData {
189    /// 是否还有更多项
190    pub has_more: bool,
191    /// 分页标记,当 has_more 为 true 时,会同时返回新的 page_token,否则不返回 page_token
192    pub page_token: Option<String>,
193    pub items: Vec<Message>,
194}
195
196impl ApiResponseTrait for ListMessageRespData {
197    fn data_format() -> crate::core::api_resp::ResponseFormat {
198        crate::core::api_resp::ResponseFormat::Data
199    }
200}
201
202impl MessageService {
203    /// 获取会话历史消息
204    ///
205    /// 获取会话(包括单聊、群组)的历史消息(聊天记录)
206    ///
207    /// <https://open.feishu.cn/document/server-docs/im-v1/message/list>
208    pub async fn list(
209        &self,
210        list_message_request: ListMessageRequest,
211        option: Option<RequestOption>,
212    ) -> SDKResult<ListMessageRespData> {
213        let mut api_req = list_message_request.api_req;
214        api_req.http_method = Method::GET;
215        api_req.api_path = crate::core::endpoints::im::IM_V1_LIST_MESSAGE.to_string();
216        api_req.supported_access_token_types = vec![AccessTokenType::Tenant, AccessTokenType::User];
217
218        let api_resp: BaseResponse<ListMessageRespData> =
219            Transport::request(api_req, &self.config, option).await?;
220
221        api_resp.into_result()
222    }
223
224    /// 创建消息列表迭代器
225    ///
226    /// 提供便捷的方式遍历所有消息,自动处理分页
227    pub fn list_iter(
228        &self,
229        list_message_request: ListMessageRequest,
230        _option: Option<RequestOption>,
231    ) -> ListMessageIterator<'_> {
232        ListMessageIterator::new(self, list_message_request)
233    }
234
235    /// 使用分页验证创建消息列表请求
236    ///
237    /// 提供一个更安全的方式来创建消息列表请求,自动验证分页参数
238    pub async fn list_with_validated_pagination(
239        &self,
240        container_id: impl ToString,
241        container_id_type: impl ToString,
242        page_size: Option<u32>,
243        page_token: Option<String>,
244        option: Option<RequestOption>,
245    ) -> SDKResult<ListMessageRespData> {
246        // 创建请求构建器
247        let builder = ListMessageRequest::builder()
248            .container_id(container_id)
249            .container_id_type(container_id_type)
250            .with_pagination(page_size, page_token)?;
251
252        self.list(builder.build(), option).await
253    }
254}