use crate::common::api_endpoints::DriveApi;
use openlark_core::{
api::{ApiRequest, Response},
config::Config,
http::Transport,
req_option::RequestOption,
SDKResult,
};
#[derive(Debug)]
pub struct DownloadMediaRequest {
config: Config,
pub file_token: String,
pub extra: Option<String>,
pub range: Option<String>,
}
impl DownloadMediaRequest {
pub fn new(config: Config, file_token: impl Into<String>) -> Self {
Self {
config,
file_token: file_token.into(),
extra: None,
range: None,
}
}
pub fn extra(mut self, extra: impl Into<String>) -> Self {
self.extra = Some(extra.into());
self
}
pub fn range(mut self, range: impl Into<String>) -> Self {
self.range = Some(range.into());
self
}
pub async fn execute(self) -> SDKResult<Response<Vec<u8>>> {
self.execute_with_options(RequestOption::default()).await
}
pub async fn execute_with_options(self, option: RequestOption) -> SDKResult<Response<Vec<u8>>> {
if self.file_token.is_empty() {
return Err(openlark_core::error::validation_error(
"file_token",
"file_token 不能为空",
));
}
if let Some(range) = &self.range {
if !range.starts_with("bytes=") || !range.contains('-') {
return Err(openlark_core::error::validation_error(
"range",
"range 格式必须为 bytes=start-end(例如 bytes=0-1024)",
));
}
}
let api_endpoint = DriveApi::DownloadMedia(self.file_token.clone());
let mut request =
ApiRequest::<Vec<u8>>::get(&api_endpoint.to_url()).query_opt("extra", self.extra);
if let Some(r) = self.range {
request = request.header("Range", &r);
}
Transport::request(request, &self.config, Some(option)).await
}
}
#[cfg(test)]
mod tests {
use super::*;
use openlark_core::testing::prelude::test_runtime;
#[test]
fn test_download_media_request() {
let config = Config::default();
let request = DownloadMediaRequest::new(config, "media_token")
.extra("extra")
.range("bytes=0-100");
assert_eq!(request.file_token, "media_token");
assert_eq!(request.extra, Some("extra".to_string()));
assert_eq!(request.range, Some("bytes=0-100".to_string()));
}
#[test]
fn test_empty_file_token_validation() {
let config = Config::default();
let request = DownloadMediaRequest::new(config, "");
let result = std::thread::spawn(move || {
let rt = test_runtime();
rt.block_on(async move {
let _ = request.execute().await;
})
})
.join();
assert!(result.is_ok());
}
#[test]
fn test_range_format_validation() {
let config = Config::default();
let request1 = DownloadMediaRequest::new(config.clone(), "token").range("0-100");
let result1 = std::thread::spawn(move || {
let rt = test_runtime();
rt.block_on(async move {
let _ = request1.execute().await;
})
})
.join();
assert!(result1.is_ok());
let request2 = DownloadMediaRequest::new(config.clone(), "token").range("bytes=0100");
let result2 = std::thread::spawn(move || {
let rt = test_runtime();
rt.block_on(async move {
let _ = request2.execute().await;
})
})
.join();
assert!(result2.is_ok());
}
#[test]
fn test_valid_range_formats() {
let config = Config::default();
let request1 = DownloadMediaRequest::new(config.clone(), "token").range("bytes=0-1024");
assert_eq!(request1.range, Some("bytes=0-1024".to_string()));
let request2 = DownloadMediaRequest::new(config.clone(), "token").range("bytes=0-0");
assert_eq!(request2.range, Some("bytes=0-0".to_string()));
let request3 = DownloadMediaRequest::new(config.clone(), "token").range("bytes=0-999999");
assert_eq!(request3.range, Some("bytes=0-999999".to_string()));
}
#[test]
fn test_optional_parameters() {
let config = Config::default();
let request1 = DownloadMediaRequest::new(config.clone(), "token");
assert!(request1.extra.is_none());
assert!(request1.range.is_none());
let request2 = DownloadMediaRequest::new(config.clone(), "token").extra("extra_param");
assert_eq!(request2.extra, Some("extra_param".to_string()));
let request3 = DownloadMediaRequest::new(config, "token").range("bytes=0-100");
assert_eq!(request3.range, Some("bytes=0-100".to_string()));
}
}