discord_webhook2/
webhook.rs1use std::collections::BTreeMap;
2
3use reqwest::multipart::{Form, Part};
4use reqwest::{Client, Url};
5
6use crate::error::DiscordWebhookError;
7use crate::id::DiscordID;
8use crate::message::Message;
9
10pub struct DiscordWebhook {
11 client: Client,
12 url: Url,
13}
14
15#[cfg(not(feature = "rustls-tls"))]
16fn build_client() -> Result<Client, DiscordWebhookError> {
17 Ok(reqwest::Client::new())
18}
19
20#[cfg(feature = "rustls-tls")]
21fn build_client() -> Result<Client, DiscordWebhookError> {
22 reqwest::ClientBuilder::new()
23 .use_rustls_tls()
24 .build()
25 .map_err(DiscordWebhookError::ReqwestError)
26}
27
28impl DiscordWebhook {
29 pub fn new(url: impl Into<String>) -> Result<Self, DiscordWebhookError> {
30 let url = url.into();
31 let url = Url::parse(url.as_str()).map_err(DiscordWebhookError::UrlParseError)?;
32
33 let client = build_client()?;
34
35 Ok(Self { client, url })
36 }
37
38 pub fn from_url(url: Url) -> Self {
39 Self {
40 client: Client::new(),
41 url,
42 }
43 }
44
45 pub async fn send(&self, message: &Message) -> Result<DiscordID, DiscordWebhookError> {
47 let send_result = self
48 .client
49 .post(self.url.join("?wait=true")?.clone())
50 .json(message)
51 .send()
52 .await;
53
54 let response = send_result.map_err(DiscordWebhookError::ReqwestError)?;
55
56 match response.status().is_success() {
57 true => {
58 let posted_message: Message = response
59 .json::<Message>()
60 .await
61 .map_err(DiscordWebhookError::ReqwestError)?;
62
63 match posted_message.id {
64 None => Err(DiscordWebhookError::FormatError(String::from(
65 "Missing field `id` in response",
66 ))),
67 Some(v) => Ok(v),
68 }
69 }
70 false => Err(DiscordWebhookError::FormatError(
71 response.text().await?.to_string(),
72 )),
73 }
74 }
75
76 pub async fn send_with_files(
78 &self,
79 message: &Message,
80 files_entries: BTreeMap<String, Vec<u8>>,
81 ) -> Result<DiscordID, DiscordWebhookError> {
82 let mut form = Form::new().text("payload_json", serde_json::to_string(message).unwrap());
83
84 for (i, (name, data)) in files_entries.into_iter().enumerate() {
85 let mut part = Part::bytes(data);
86
87 part = part.file_name(name);
88
89 form = form.part(format!("files[{i}]"), part);
90 }
91
92 let send_result = self
93 .client
94 .post(self.url.join("?wait=true")?.clone())
95 .multipart(form)
96 .send()
97 .await;
98
99 let response = send_result.map_err(DiscordWebhookError::ReqwestError)?;
100
101 match response.status().is_success() {
102 true => {
103 let posted_message: Message = response
104 .json::<Message>()
105 .await
106 .map_err(DiscordWebhookError::ReqwestError)?;
107
108 match posted_message.id {
109 None => Err(DiscordWebhookError::FormatError(String::from(
110 "Missing field `id` in response",
111 ))),
112 Some(v) => Ok(v),
113 }
114 }
115 false => Err(DiscordWebhookError::FormatError(
116 response.text().await?.to_string(),
117 )),
118 }
119 }
120
121 pub async fn get(&self, message_id: &DiscordID) -> Result<Message, DiscordWebhookError> {
123 let url = Url::parse(&format!("{}/", self.url.as_str()))?;
124
125 let send_result = self
126 .client
127 .get(
128 url.join(format!("messages/{}?wait=true", message_id.0).as_str())?
129 .clone(),
130 )
131 .send()
132 .await;
133
134 let response = send_result.map_err(DiscordWebhookError::ReqwestError)?;
135
136 match response.status().is_success() {
137 true => Ok(response
138 .json::<Message>()
139 .await
140 .map_err(DiscordWebhookError::ReqwestError)?),
141 false => Err(DiscordWebhookError::FormatError(
142 response.text().await?.to_string(),
143 )),
144 }
145 }
146
147 pub async fn edit(
149 &self,
150 message_id: &DiscordID,
151 message: &Message,
152 ) -> Result<DiscordID, DiscordWebhookError> {
153 let url = Url::parse(&format!("{}/", self.url.as_str()))?;
154
155 let send_result = self
156 .client
157 .patch(
158 url.join(format!("messages/{}?wait=true", message_id.0).as_str())?
159 .clone(),
160 )
161 .json(message)
162 .send()
163 .await;
164
165 let response = send_result.map_err(DiscordWebhookError::ReqwestError)?;
166
167 match response.status().is_success() {
168 true => {
169 let posted_message: Message = response
170 .json::<Message>()
171 .await
172 .map_err(DiscordWebhookError::ReqwestError)?;
173
174 match posted_message.id {
175 None => Err(DiscordWebhookError::FormatError(String::from(
176 "Missing field `id` in response",
177 ))),
178 Some(v) => Ok(v),
179 }
180 }
181 false => Err(DiscordWebhookError::FormatError(
182 response.text().await?.to_string(),
183 )),
184 }
185 }
186
187 pub async fn delete(&self, message_id: &DiscordID) -> Result<(), DiscordWebhookError> {
189 let url = Url::parse(&format!("{}/", &self.url))?;
190
191 let send_result = self
192 .client
193 .delete(url.join(&format!("messages/{}", message_id.0))?.clone())
194 .send()
195 .await;
196
197 send_result.map_err(DiscordWebhookError::ReqwestError)?;
198
199 Ok(())
200 }
201}