Add delete operation to Discord wrapper

This commit is contained in:
lemon-sh 2022-01-21 12:48:41 +01:00
parent d7e68e827e
commit c58db54696

View file

@ -1,12 +1,16 @@
use crate::Bytes;
use anyhow::anyhow;
use log::debug;
use log::{debug, trace, warn};
use once_cell::sync::OnceCell;
use reqwest::header::HeaderMap;
use reqwest::multipart::{Form, Part};
use reqwest::{Body, Client, IntoUrl};
use reqwest::{Body, Client, IntoUrl, StatusCode};
use serde_json::Value;
use std::fmt::Display;
use std::time::Duration;
use tokio::time::sleep;
// note: only delete has rate-limit handling
static CLIENT: OnceCell<Client> = OnceCell::new();
@ -14,21 +18,22 @@ pub async fn upload_webhook<T: Into<Body>>(
webhook: &str,
file: T,
filename: &str,
) -> anyhow::Result<String> {
) -> anyhow::Result<(String, u64)> {
debug!("Uploading '{}' to Discord", filename);
let client = CLIENT.get_or_init(Client::new);
let form = Form::new().part("file", Part::stream(file).file_name(filename.to_string()));
let req = client
let resp = client
.post(webhook)
.multipart(form)
.send()
.await?
.json::<Value>()
.await?;
if let Some(u) = req["attachments"][0]["url"].as_str() {
Ok(u.into())
trace!("Received JSON from Discord: {}", resp);
if let (Some(u), Some(i)) = (resp["attachments"][0]["url"].as_str(), resp["id"].as_str().and_then(|f| f.parse::<u64>().ok())) {
Ok((u.into(), i))
} else {
Err(anyhow!("Discord response didn't include the URL"))
Err(anyhow!("Discord response didn't include the URL or message ID"))
}
}
@ -67,3 +72,33 @@ pub async fn get<U: IntoUrl + Display>(url: U) -> anyhow::Result<(u64, String, B
Err(anyhow!("Discord response didn't include the URL"))
}
}
pub async fn delete(webhook: &str, mid: u64) -> anyhow::Result<()> {
debug!("Deleting message with ID {}", mid);
let client = CLIENT.get_or_init(Client::new);
let resp = client.delete(format!("{}/messages/{}", webhook, mid)).send().await?;
if resp.status() != StatusCode::NO_CONTENT {
Err(anyhow!(resp.text().await?))
} else {
let rt_header = resp.headers()
.get("X-RateLimit-Remaining")
.and_then(|v| v.to_str().ok()?.parse::<u64>().ok())
.and_then(|v| {
if v == 0 {
resp.headers()
.get("X-RateLimit-Reset-After")
.and_then(|v| v.to_str().ok()?.parse::<f64>().ok())
} else {
Some(0.0)
}
});
if let Some(rt) = rt_header {
if rt > 0.0 {
sleep(Duration::from_secs_f64(rt)).await;
}
} else {
warn!("Couldn't await the rate-limit, because there was a problem with the rate-limit header in Discord's response")
}
Ok(())
}
}