use base64::engine::general_purpose;
use base64::Engine;
use hmac::Hmac;
use reqwest::StatusCode;
use sha1::digest::Mac;
use crate::entity::{PolicyBuilder, PolicyResp};
use crate::error::OssError;
use crate::oss::{OSSInfo, API, OSS};
use crate::request::{RequestBuilder, RequestType};
use crate::{debug, util};
use crate::util::read_file;
impl OSS {
pub async fn get_object<S: AsRef<str>>(
&self,
key: S,
build: RequestBuilder,
) -> Result<Vec<u8>, OssError> {
let key = self.format_key(key);
let (url, headers) = self
.build_request(key.as_str(), build)
.map_err(|e| OssError::Err(format!("build request error: {}", e)))?;
debug!("oss logget object url: {} headers: {:?}", url,headers);
let client = reqwest::Client::new();
let response = client.get(url).headers(headers).send().await?;
return if response.status().is_success() {
let result = response.bytes().await?;
Ok(result.to_vec())
} else {
let status = response.status();
let result = response.text().await?;
debug!("oss log: get object status: {} error: {}", status,result);
Err(OssError::Err(format!(
"get object status: {} error: {}",
status, result
)))
};
}
pub fn get_upload_object_policy(&self, build: PolicyBuilder) -> Result<PolicyResp, OssError> {
let date = chrono::Local::now().naive_local() + chrono::Duration::seconds(build.expire);
let date_str = date.format("%Y-%m-%dT%H:%M:%S%.3fZ").to_string();
let mut json_data = r#"
{
"expiration": "{time}",
"conditions": [
{"bucket": "{bucket}" },
["content-length-range", 1, {size}],
["eq", "$success_action_status", "{success_action_status}"],
["starts-with", "$key", "{prefix}"],
["in", "$content-type", ["{content_type}"]]
]
}
"#
.to_string();
let success_action_status = 200;
json_data = json_data.replacen("{time}", &date_str, 1);
json_data = json_data.replacen("{bucket}", &self.bucket(), 1);
json_data = json_data.replacen("{size}", &build.max_upload_size.to_string(), 1); json_data = json_data.replacen(
"{success_action_status}",
success_action_status.to_string().as_str(),
1,
);
json_data = json_data.replacen("{prefix}", &build.upload_dir, 1); json_data = json_data.replacen("{content_type}", &build.content_type, 1);
debug!("oss log: policy json: {}", json_data);
let base64_policy = util::base64_encode(json_data.as_bytes());
let mut hasher: Hmac<sha1::Sha1> = Hmac::new_from_slice(self.key_secret().as_bytes())
.map_err(|_| OssError::Err("Hmac new from slice error".to_string()))?;
hasher.update(base64_policy.as_bytes());
let signature = util::base64_encode(&hasher.finalize().into_bytes());
Ok(PolicyResp {
access_id: self.key_id().to_string(),
host: format!("https://{}.{}", self.bucket(), self.endpoint()),
policy: base64_policy,
signature,
success_action_status,
})
}
pub async fn put_object_from_file<S: AsRef<str>>(
&self,
key: S,
file_path: S,
build: RequestBuilder,
) -> Result<(), OssError> {
let buffer = read_file(file_path)?;
let mut build = build.clone();
build.method = RequestType::Put;
let key = self.format_key(key);
let (url, headers) = self
.build_request(key.as_str(), build)
.map_err(|e| OssError::Err(format!("build request error: {}", e)))?;
debug!("oss log: put object from file: {} headers: {:?}", url,headers);
let client = reqwest::Client::new();
let response = client.put(url).headers(headers).body(buffer).send().await?;
return if response.status().is_success() {
Ok(())
} else {
let status = response.status();
let result = response.text().await?;
debug!("oss log: get object status: {} error: {}", status,result);
Err(OssError::Err(format!(
"get object status: {} error: {}",
status, result
)))
};
}
pub async fn pub_object_from_buffer<S: AsRef<str>>(
&self,
key: S,
buffer: &[u8],
build: RequestBuilder,
) -> Result<(), OssError> {
let mut build = build.clone();
build.method = RequestType::Put;
let key = self.format_key(key);
let (url, headers) = self
.build_request(key.as_str(), build)
.map_err(|e| OssError::Err(format!("build request error: {}", e)))?;
debug!("oss log: put object from file: {} headers: {:?}", url,headers);
let client = reqwest::Client::new();
let response = client
.put(url)
.headers(headers)
.body(buffer.to_owned())
.send()
.await?;
return if response.status().is_success() {
Ok(())
} else {
let status = response.status();
let result = response.text().await?;
debug!("oss log: get object status: {} error: {}", status,result);
Err(OssError::Err(format!(
"get object status: {} error: {}",
status, result
)))
};
}
pub async fn delete_object<S: AsRef<str>>(
&self,
key: S,
build: RequestBuilder,
) -> Result<(), OssError> {
let mut build = build.clone();
build.method = RequestType::Delete;
let key = self.format_key(key);
let (url, headers) = self
.build_request(key.as_str(), build)
.map_err(|e| OssError::Err(format!("build request error: {}", e)))?;
debug!("oss log: put object from file: {} headers: {:?}", url,headers);
let client = reqwest::Client::new();
let response = client.delete(url).headers(headers).send().await?;
return if response.status().is_success() {
Ok(())
} else {
let status = response.status();
let result = response.text().await?;
debug!("oss log: get object status: {} error: {}", status,result);
Err(OssError::Err(format!(
"get object status: {} error: {}",
status, result
)))
};
}
}