use reqwest::multipart::{Form, Part};
use serde::Deserialize;
use crate::client::WeChatClient;
use crate::error::{Result, WeChatError};
use crate::models::material::{
MaterialCountResponse, MaterialListResponse, MaterialType, UploadPermanentMediaResponse,
UploadTempMediaResponse, VideoDescription,
};
const WECHAT_API_BASE: &str = "https://api.weixin.qq.com/cgi-bin";
#[derive(Deserialize)]
struct ApiResponse {
errcode: Option<i64>,
errmsg: Option<String>,
}
impl WeChatClient {
pub async fn upload_temp_media(
&self,
media_type: MaterialType,
file_name: &str,
file_data: Vec<u8>,
) -> Result<UploadTempMediaResponse> {
let token = self.access_token().await?;
let url = format!(
"{}/media/upload?access_token={}&type={}",
WECHAT_API_BASE,
token,
media_type.as_str()
);
let part = Part::bytes(file_data).file_name(file_name.to_string());
let form = Form::new().part("media", part);
let resp = self.http.post(&url).multipart(form).send().await?;
let text = resp.text().await?;
if let Ok(err) = serde_json::from_str::<ApiResponse>(&text) {
if let Some(errcode) = err.errcode {
if errcode != 0 {
return Err(WeChatError::Api {
errcode,
errmsg: err.errmsg.unwrap_or_default(),
});
}
}
}
Ok(serde_json::from_str(&text)?)
}
pub async fn get_temp_media(&self, media_id: &str) -> Result<Vec<u8>> {
let token = self.access_token().await?;
let url = format!(
"{}/media/get?access_token={}&media_id={}",
WECHAT_API_BASE, token, media_id
);
let resp = self.http.get(&url).send().await?;
let content_type = resp
.headers()
.get("content-type")
.and_then(|v| v.to_str().ok())
.unwrap_or("")
.to_string();
let bytes = resp.bytes().await?.to_vec();
if content_type.contains("application/json") || content_type.contains("text/plain") {
if let Ok(text) = std::str::from_utf8(&bytes) {
if let Ok(err) = serde_json::from_str::<ApiResponse>(text) {
if let Some(errcode) = err.errcode {
if errcode != 0 {
return Err(WeChatError::Api {
errcode,
errmsg: err.errmsg.unwrap_or_default(),
});
}
}
}
}
}
Ok(bytes)
}
pub async fn upload_permanent_media(
&self,
media_type: MaterialType,
file_name: &str,
file_data: Vec<u8>,
) -> Result<UploadPermanentMediaResponse> {
let token = self.access_token().await?;
let url = format!(
"{}/material/add_material?access_token={}&type={}",
WECHAT_API_BASE,
token,
media_type.as_str()
);
let part = Part::bytes(file_data).file_name(file_name.to_string());
let form = Form::new().part("media", part);
let resp = self.http.post(&url).multipart(form).send().await?;
let text = resp.text().await?;
if let Ok(err) = serde_json::from_str::<ApiResponse>(&text) {
if let Some(errcode) = err.errcode {
if errcode != 0 {
return Err(WeChatError::Api {
errcode,
errmsg: err.errmsg.unwrap_or_default(),
});
}
}
}
Ok(serde_json::from_str(&text)?)
}
pub async fn upload_permanent_video(
&self,
file_name: &str,
file_data: Vec<u8>,
description: &VideoDescription,
) -> Result<UploadPermanentMediaResponse> {
let token = self.access_token().await?;
let url = format!(
"{}/material/add_material?access_token={}&type=video",
WECHAT_API_BASE, token
);
let part = Part::bytes(file_data).file_name(file_name.to_string());
let desc_json = serde_json::to_string(description)?;
let form = Form::new()
.part("media", part)
.text("description", desc_json);
let resp = self.http.post(&url).multipart(form).send().await?;
let text = resp.text().await?;
if let Ok(err) = serde_json::from_str::<ApiResponse>(&text) {
if let Some(errcode) = err.errcode {
if errcode != 0 {
return Err(WeChatError::Api {
errcode,
errmsg: err.errmsg.unwrap_or_default(),
});
}
}
}
Ok(serde_json::from_str(&text)?)
}
pub async fn get_material_count(&self) -> Result<MaterialCountResponse> {
self.get("/material/get_materialcount", &[]).await
}
pub async fn get_material_list(
&self,
media_type: MaterialType,
offset: i32,
count: i32,
) -> Result<MaterialListResponse> {
let body = serde_json::json!({
"type": media_type.as_str(),
"offset": offset,
"count": count
});
self.post_json("/material/batchget_material", &body).await
}
pub async fn delete_material(&self, media_id: &str) -> Result<()> {
let body = serde_json::json!({
"media_id": media_id
});
let _: ApiResponse = self.post_json("/material/del_material", &body).await?;
Ok(())
}
}