use std::{borrow::Cow, io::Read};
use reqwest::multipart::{Form, Part};
use crate::models::attachment::AttachmentPayload;
use super::*;
pub async fn edit_message(channel_id: &str, message_id: &str, data: impl Into<CreateMessageData>) {
let url = format!("channels/{channel_id}/messages/{message_id}");
let data: CreateMessageData = data.into();
request(
Method::PATCH,
&url,
Some(json::parse(&data.to_json()).unwrap()),
)
.await;
}
pub async fn fetch_message(
channel_id: &str,
message_id: &str,
) -> Result<Message, Box<dyn std::error::Error>> {
if let Some(message) = MESSAGE_CACHE.lock().await.get(message_id).cloned() {
return Ok(message);
}
let url = format!("channels/{channel_id}/messages/{message_id}");
let resp = request(Method::GET, &url, None).await.text().await.unwrap();
Message::deserialize_json(&resp).map_err(|e| e.into())
}
pub async fn delete_message(channel_id: &str, message_id: &str) -> bool {
let url = format!("channels/{channel_id}/messages/{message_id}");
let resp = request(Method::DELETE, &url, None).await;
resp.status() == StatusCode::NO_CONTENT
}
pub async fn remove_reaction(channel_id: &str, message_id: &str, user_id: &str, emoji: &str) {
let url = format!("channels/{channel_id}/messages/{message_id}/reactions/{emoji}/{user_id}");
request(Method::DELETE, &url, None).await;
}
pub async fn react(channel_id: &str, message_id: &str, emoji: &str) {
let url = format!(
"channels/{channel_id}/messages/{message_id}/reactions/{emoji}/@me",
emoji = emoji.trim_matches(['<', '>', ':'])
);
request(Method::PUT, &url, None).await;
}
pub async fn send(
channel_id: &str,
reference_message_id: Option<&str>,
data: impl Into<CreateMessageData>,
) -> Message {
let data: CreateMessageData = data.into();
let mut body = json::parse(&data.to_json()).unwrap();
if let Some(message_id) = reference_message_id {
body.insert(
"message_reference",
object! {
message_id: message_id,
channel_id: channel_id,
},
);
}
let endpoint = format!("channels/{channel_id}/messages");
let multipart = get_message_multipart(channel_id, data.attachments, Some(body.dump()))
.await
.unwrap();
let mut headers = get_headers();
headers.remove("Content-Type");
let client = reqwest::Client::new()
.post(&format!("{API}/{endpoint}"))
.headers(headers);
let response = client.multipart(multipart).send().await.unwrap();
let response_text = response.text().await.unwrap();
Message::deserialize_json(&response_text.to_string()).unwrap_or_else(|e| {
panic!(
"Failed to send message, error: {}",
json::parse(&response_text).unwrap()["message"]
.as_str()
.unwrap()
)
})
}
pub async fn get_message_multipart(
channel_id: &str,
attachments: Vec<AttachmentPayload>,
payload_json: Option<String>,
) -> Result<Form, Box<dyn std::error::Error>> {
let mut form = Form::new();
if let Some(payload_json) = payload_json {
let msg = Part::text(Cow::Owned(payload_json.to_string()))
.mime_str("application/json")
.unwrap();
form = form.part("payload_json", msg);
}
for (
file_idx,
AttachmentPayload {
file_name,
file_path,
mime_type,
},
) in attachments.iter().enumerate()
{
let mut file = std::fs::File::open(file_path)?;
let mut buf = Vec::new();
file.read_to_end(&mut buf)?;
let file_part = Part::bytes(Cow::Owned(buf))
.file_name(Cow::Owned(file_name.to_string()))
.mime_str(&mime_type)
.unwrap();
form = form.part(Cow::Owned(format!("file[{file_idx}]")), file_part);
}
Ok(form)
}