open_lark/service/cloud_docs/drive/v1/
files.rs

1use log;
2use reqwest::Method;
3use serde::{Deserialize, Serialize};
4
5use crate::{
6    core::{
7        api_req::ApiRequest,
8        api_resp::{ApiResponseTrait, BaseResponse, BinaryResponse, ResponseFormat},
9        config::Config,
10        constants::AccessTokenType,
11        endpoints::cloud_docs::*,
12        http::Transport,
13        req_option::RequestOption,
14        standard_response::StandardResponse,
15        validation::{validate_file_name, validate_upload_file, ValidateBuilder, ValidationResult},
16        SDKResult,
17    },
18    impl_executable_builder_owned,
19};
20
21pub struct FilesService {
22    config: Config,
23}
24
25/// 上传文件 请求体
26#[derive(Debug, Clone, Default, Serialize, Deserialize)]
27pub struct UploadAllRequest {
28    /// 请求体
29    #[serde(skip)]
30    api_req: ApiRequest,
31    /// 文件名。
32    ///
33    /// 示例值:"demo.pdf"
34    file_name: String,
35    /// 上传点类型。
36    ///
37    /// 示例值:"explorer"
38    parent_type: String,
39    /// 文件夹token,获取方式见 概述
40    ///
41    /// 示例值:"fldbcO1UuPz8VwnpPx5a92abcef"
42    parent_node: String,
43    /// 文件大小(以字节为单位)。
44    ///
45    /// 示例值:1024
46    size: i32,
47    /// 文件adler32校验和(可选)。
48    checksum: Option<String>,
49}
50
51impl UploadAllRequest {
52    pub fn builder() -> UploadAllRequestBuilder {
53        UploadAllRequestBuilder::default()
54    }
55}
56
57/// 上传文件 请求体构建器
58#[derive(Default)]
59pub struct UploadAllRequestBuilder {
60    request: UploadAllRequest,
61}
62
63impl UploadAllRequestBuilder {
64    /// 文件名
65    pub fn file_name(mut self, file_name: impl ToString) -> Self {
66        self.request.file_name = file_name.to_string();
67        self
68    }
69
70    /// 上传点类型。
71    pub fn parent_type(mut self, parent_type: impl ToString) -> Self {
72        self.request.parent_type = parent_type.to_string();
73        self
74    }
75
76    /// 文件夹token
77    pub fn parent_node(mut self, parent_node: impl ToString) -> Self {
78        self.request.parent_node = parent_node.to_string();
79        self
80    }
81
82    /// 文件大小(以字节为单位)
83    pub fn size(mut self, size: i32) -> Self {
84        self.request.size = size;
85        self
86    }
87
88    /// 文件adler32校验和(可选)
89    pub fn checksum(mut self, checksum: impl ToString) -> Self {
90        self.request.checksum = Some(checksum.to_string());
91        self
92    }
93
94    /// 文件二进制内容。
95    pub fn file(mut self, file: Vec<u8>) -> Self {
96        self.request.api_req.file = file;
97        self
98    }
99
100    pub fn build(mut self) -> UploadAllRequest {
101        // 验证必填字段
102        if self.request.file_name.is_empty() {
103            log::error!("file_name is required for upload");
104            return UploadAllRequest {
105                api_req: ApiRequest {
106                    body: Vec::new(),
107                    ..Default::default()
108                },
109                ..self.request
110            };
111        }
112
113        if self.request.parent_type.is_empty() {
114            log::error!("parent_type is required for upload");
115            return UploadAllRequest {
116                api_req: ApiRequest {
117                    body: Vec::new(),
118                    ..Default::default()
119                },
120                ..self.request
121            };
122        }
123
124        if self.request.parent_node.is_empty() {
125            log::error!("parent_node is required for upload");
126            return UploadAllRequest {
127                api_req: ApiRequest {
128                    body: Vec::new(),
129                    ..Default::default()
130                },
131                ..self.request
132            };
133        }
134
135        // 验证文件大小
136        if self.request.size <= 0 {
137            log::error!("file size must be greater than 0");
138            return UploadAllRequest {
139                api_req: ApiRequest {
140                    body: Vec::new(),
141                    ..Default::default()
142                },
143                ..self.request
144            };
145        }
146
147        // 验证文件名
148        let (_, name_result) = validate_file_name(&self.request.file_name);
149        if !name_result.is_valid() {
150            log::error!(
151                "Invalid file_name: {}",
152                name_result.error().unwrap_or("unknown error")
153            );
154            return UploadAllRequest {
155                api_req: ApiRequest {
156                    body: Vec::new(),
157                    ..Default::default()
158                },
159                ..self.request
160            };
161        }
162
163        // 验证文件数据(如果有)
164        if !self.request.api_req.file.is_empty() {
165            let upload_result =
166                validate_upload_file(&self.request.api_req.file, &self.request.file_name, false);
167            if !upload_result.is_valid() {
168                log::error!(
169                    "File validation failed: {}",
170                    upload_result.error().unwrap_or("unknown error")
171                );
172                return UploadAllRequest {
173                    api_req: ApiRequest {
174                        body: Vec::new(),
175                        ..Default::default()
176                    },
177                    ..self.request
178                };
179            }
180        }
181
182        self.request.api_req.body = match serde_json::to_vec(&self.request) {
183            Ok(body) => body,
184            Err(e) => {
185                log::error!("Failed to serialize upload request: {}", e);
186                return UploadAllRequest {
187                    api_req: ApiRequest {
188                        body: Vec::new(),
189                        ..Default::default()
190                    },
191                    ..self.request
192                };
193            }
194        };
195        self.request
196    }
197}
198
199impl ValidateBuilder for UploadAllRequestBuilder {
200    fn validate(&self) -> ValidationResult {
201        // 验证必填字段
202        if self.request.file_name.is_empty() {
203            return ValidationResult::Invalid("file_name is required".to_string());
204        }
205
206        if self.request.parent_type.is_empty() {
207            return ValidationResult::Invalid("parent_type is required".to_string());
208        }
209
210        if self.request.parent_node.is_empty() {
211            return ValidationResult::Invalid("parent_node is required".to_string());
212        }
213
214        // 验证文件大小
215        if self.request.size <= 0 {
216            return ValidationResult::Invalid("file size must be greater than 0".to_string());
217        }
218
219        // 验证文件名
220        let (_, name_result) = validate_file_name(&self.request.file_name);
221        if !name_result.is_valid() {
222            return name_result;
223        }
224
225        // 验证文件数据(如果有)
226        if !self.request.api_req.file.is_empty() {
227            validate_upload_file(&self.request.api_req.file, &self.request.file_name, false)
228        } else {
229            ValidationResult::Valid
230        }
231    }
232}
233
234impl FilesService {
235    pub fn new(config: Config) -> Self {
236        Self { config }
237    }
238
239    /// 创建上传文件Builder
240    pub fn upload_all_builder(&self) -> UploadAllRequestBuilder {
241        UploadAllRequestBuilder::default()
242    }
243
244    /// 创建下载文件Builder  
245    pub fn download_builder(&self) -> DownloadRequestBuilder {
246        DownloadRequestBuilder::default()
247    }
248
249    /// 使用Builder上传文件(带验证)
250    pub async fn upload_all_with_builder(
251        &self,
252        builder_result: SDKResult<UploadAllRequest>,
253        option: Option<RequestOption>,
254    ) -> SDKResult<UploadAllResponse> {
255        let request = builder_result?;
256        self.upload_all(request, option).await
257    }
258
259    /// 上传文件
260    pub async fn upload_all(
261        &self,
262        upload_all_request: UploadAllRequest,
263        option: Option<RequestOption>,
264    ) -> SDKResult<UploadAllResponse> {
265        let mut api_req = upload_all_request.api_req;
266        api_req.http_method = Method::POST;
267        api_req.api_path = DRIVE_V1_FILES_UPLOAD_ALL.to_string();
268        api_req.supported_access_token_types = vec![AccessTokenType::Tenant, AccessTokenType::User];
269
270        let api_resp: BaseResponse<UploadAllResponse> =
271            Transport::request(api_req, &self.config, option).await?;
272
273        api_resp.into_result()
274    }
275
276    /// 下载文件
277    pub async fn download(
278        &self,
279        request: DownloadRequest,
280        option: Option<RequestOption>,
281    ) -> SDKResult<BinaryResponse> {
282        let mut api_req = request.api_req;
283        api_req.http_method = Method::GET;
284        api_req.api_path = DRIVE_V1_FILE_DOWNLOAD.replace("{}", &request.file_token);
285        api_req.supported_access_token_types = vec![AccessTokenType::Tenant, AccessTokenType::User];
286
287        let api_resp: BaseResponse<BinaryResponse> =
288            Transport::request(api_req, &self.config, option).await?;
289
290        api_resp.into_result()
291    }
292}
293
294/// 上传文件响应体
295#[derive(Debug, Serialize, Deserialize)]
296pub struct UploadAllResponse {
297    /// 新创建文件的 token
298    pub file_token: String,
299}
300
301impl ApiResponseTrait for UploadAllResponse {
302    fn data_format() -> ResponseFormat {
303        ResponseFormat::Data
304    }
305}
306
307/// 下载文件 请求体
308#[derive(Default, Serialize, Deserialize)]
309pub struct DownloadRequest {
310    /// 请求体
311    #[serde(skip)]
312    api_req: ApiRequest,
313    /// 文件的 token
314    file_token: String,
315}
316
317/// 下载文件 请求体构建器
318#[derive(Default)]
319pub struct DownloadRequestBuilder {
320    req: DownloadRequest,
321}
322
323impl DownloadRequestBuilder {
324    pub fn file_token(mut self, file_token: impl ToString) -> Self {
325        self.req.file_token = file_token.to_string();
326        self
327    }
328
329    pub fn build(self) -> DownloadRequest {
330        self.req
331    }
332}
333
334impl DownloadRequest {
335    pub fn builder() -> DownloadRequestBuilder {
336        DownloadRequestBuilder::default()
337    }
338}
339
340// === 宏实现 ===
341
342impl_executable_builder_owned!(
343    UploadAllRequestBuilder,
344    FilesService,
345    UploadAllRequest,
346    UploadAllResponse,
347    upload_all
348);
349
350impl_executable_builder_owned!(
351    DownloadRequestBuilder,
352    FilesService,
353    DownloadRequest,
354    BinaryResponse,
355    download
356);