twilight_http/request/channel/message/
create_message.rs1use crate::{
2 client::Client,
3 error::Error,
4 request::{
5 attachment::{AttachmentManager, PartialAttachment},
6 Nullable, Request, TryIntoRequest,
7 },
8 response::{Response, ResponseFuture},
9 routing::Route,
10};
11use serde::Serialize;
12use std::future::IntoFuture;
13use twilight_model::{
14 channel::message::{
15 AllowedMentions, Component, Embed, Message, MessageFlags, MessageReference,
16 MessageReferenceType,
17 },
18 http::attachment::Attachment,
19 id::{
20 marker::{ChannelMarker, MessageMarker, StickerMarker},
21 Id,
22 },
23 poll::Poll,
24};
25use twilight_validate::message::{
26 attachment as validate_attachment, components as validate_components,
27 content as validate_content, embeds as validate_embeds, sticker_ids as validate_sticker_ids,
28 MessageValidationError,
29};
30
31#[derive(Serialize)]
32pub(crate) struct CreateMessageFields<'a> {
33 #[serde(skip_serializing_if = "Option::is_none")]
34 allowed_mentions: Option<Nullable<&'a AllowedMentions>>,
35 #[serde(skip_serializing_if = "Option::is_none")]
36 attachments: Option<Vec<PartialAttachment<'a>>>,
37 #[serde(skip_serializing_if = "Option::is_none")]
38 components: Option<&'a [Component]>,
39 #[serde(skip_serializing_if = "Option::is_none")]
40 content: Option<&'a str>,
41 #[serde(skip_serializing_if = "Option::is_none")]
42 embeds: Option<&'a [Embed]>,
43 #[serde(skip_serializing_if = "Option::is_none")]
44 flags: Option<MessageFlags>,
45 #[serde(skip_serializing_if = "Option::is_none")]
46 message_reference: Option<MessageReference>,
47 #[serde(skip_serializing_if = "Option::is_none")]
48 nonce: Option<u64>,
49 #[serde(skip_serializing_if = "Option::is_none")]
50 payload_json: Option<&'a [u8]>,
51 #[serde(skip_serializing_if = "Option::is_none")]
52 poll: Option<&'a Poll>,
53 #[serde(skip_serializing_if = "Option::is_none")]
54 sticker_ids: Option<&'a [Id<StickerMarker>]>,
55 #[serde(skip_serializing_if = "Option::is_none")]
56 tts: Option<bool>,
57}
58
59#[must_use = "requests must be configured and executed"]
88pub struct CreateMessage<'a> {
89 attachment_manager: AttachmentManager<'a>,
90 channel_id: Id<ChannelMarker>,
91 fields: Result<CreateMessageFields<'a>, MessageValidationError>,
92 http: &'a Client,
93}
94
95impl<'a> CreateMessage<'a> {
96 pub(crate) const fn new(http: &'a Client, channel_id: Id<ChannelMarker>) -> Self {
97 Self {
98 attachment_manager: AttachmentManager::new(),
99 channel_id,
100 fields: Ok(CreateMessageFields {
101 attachments: None,
102 components: None,
103 content: None,
104 embeds: None,
105 flags: None,
106 message_reference: None,
107 nonce: None,
108 payload_json: None,
109 poll: None,
110 allowed_mentions: None,
111 sticker_ids: None,
112 tts: None,
113 }),
114 http,
115 }
116 }
117
118 pub fn allowed_mentions(mut self, allowed_mentions: Option<&'a AllowedMentions>) -> Self {
123 if let Ok(fields) = self.fields.as_mut() {
124 fields.allowed_mentions = Some(Nullable(allowed_mentions));
125 }
126
127 self
128 }
129
130 pub fn attachments(mut self, attachments: &'a [Attachment]) -> Self {
145 if self.fields.is_ok() {
146 if let Err(source) = attachments.iter().try_for_each(validate_attachment) {
147 self.fields = Err(source);
148 } else {
149 self.attachment_manager = self
150 .attachment_manager
151 .set_files(attachments.iter().collect());
152 }
153 }
154
155 self
156 }
157
158 pub fn components(mut self, components: &'a [Component]) -> Self {
168 self.fields = self.fields.and_then(|mut fields| {
169 validate_components(components)?;
170 fields.components = Some(components);
171
172 Ok(fields)
173 });
174
175 self
176 }
177
178 pub fn content(mut self, content: &'a str) -> Self {
189 self.fields = self.fields.and_then(|mut fields| {
190 validate_content(content)?;
191 fields.content.replace(content);
192
193 Ok(fields)
194 });
195
196 self
197 }
198
199 pub fn embeds(mut self, embeds: &'a [Embed]) -> Self {
220 self.fields = self.fields.and_then(|mut fields| {
221 validate_embeds(embeds)?;
222 fields.embeds = Some(embeds);
223
224 Ok(fields)
225 });
226
227 self
228 }
229
230 pub fn poll(mut self, poll: &'a Poll) -> Self {
232 if let Ok(fields) = self.fields.as_mut() {
233 fields.poll = Some(poll);
234 }
235
236 self
237 }
238
239 pub fn fail_if_not_exists(mut self, fail_if_not_exists: bool) -> Self {
243 if let Ok(fields) = self.fields.as_mut() {
244 if let Some(reference) = fields.message_reference.as_mut() {
245 reference.fail_if_not_exists = Some(fail_if_not_exists);
246 } else {
247 fields.message_reference = Some(MessageReference {
248 kind: MessageReferenceType::default(),
249 channel_id: None,
250 guild_id: None,
251 message_id: None,
252 fail_if_not_exists: Some(fail_if_not_exists),
253 });
254 }
255 }
256
257 self
258 }
259
260 pub fn flags(mut self, flags: MessageFlags) -> Self {
268 if let Ok(fields) = self.fields.as_mut() {
269 fields.flags = Some(flags);
270 }
271
272 self
273 }
274
275 pub fn nonce(mut self, nonce: u64) -> Self {
277 if let Ok(fields) = self.fields.as_mut() {
278 fields.nonce = Some(nonce);
279 }
280
281 self
282 }
283
284 pub fn payload_json(mut self, payload_json: &'a [u8]) -> Self {
297 if let Ok(fields) = self.fields.as_mut() {
298 fields.payload_json = Some(payload_json);
299 }
300
301 self
302 }
303
304 pub fn reply(mut self, other: Id<MessageMarker>) -> Self {
306 self.fields = self.fields.map(|mut fields| {
307 let channel_id = self.channel_id;
308
309 let reference = if let Some(reference) = fields.message_reference {
310 MessageReference {
311 channel_id: Some(channel_id),
312 message_id: Some(other),
313 ..reference
314 }
315 } else {
316 MessageReference {
317 kind: MessageReferenceType::Default,
318 channel_id: Some(channel_id),
319 guild_id: None,
320 message_id: Some(other),
321 fail_if_not_exists: None,
322 }
323 };
324
325 fields.message_reference = Some(reference);
326
327 fields
328 });
329
330 self
331 }
332
333 pub fn forward(mut self, other: Id<MessageMarker>) -> Self {
335 self.fields = self.fields.map(|mut fields| {
336 let channel_id = self.channel_id;
337
338 let reference = if let Some(reference) = fields.message_reference {
339 MessageReference {
340 channel_id: Some(channel_id),
341 message_id: Some(other),
342 ..reference
343 }
344 } else {
345 MessageReference {
346 kind: MessageReferenceType::Forward,
347 channel_id: Some(channel_id),
348 guild_id: None,
349 message_id: Some(other),
350 fail_if_not_exists: None,
351 }
352 };
353
354 fields.message_reference = Some(reference);
355
356 fields
357 });
358
359 self
360 }
361
362 pub fn sticker_ids(mut self, sticker_ids: &'a [Id<StickerMarker>]) -> Self {
370 self.fields = self.fields.and_then(|mut fields| {
371 validate_sticker_ids(sticker_ids)?;
372 fields.sticker_ids = Some(sticker_ids);
373
374 Ok(fields)
375 });
376
377 self
378 }
379
380 pub fn tts(mut self, tts: bool) -> Self {
382 if let Ok(fields) = self.fields.as_mut() {
383 fields.tts = Some(tts);
384 }
385
386 self
387 }
388}
389
390impl IntoFuture for CreateMessage<'_> {
391 type Output = Result<Response<Message>, Error>;
392
393 type IntoFuture = ResponseFuture<Message>;
394
395 fn into_future(self) -> Self::IntoFuture {
396 let http = self.http;
397
398 match self.try_into_request() {
399 Ok(request) => http.request(request),
400 Err(source) => ResponseFuture::error(source),
401 }
402 }
403}
404
405impl TryIntoRequest for CreateMessage<'_> {
406 fn try_into_request(self) -> Result<Request, Error> {
407 let mut fields = self.fields.map_err(Error::validation)?;
408 let mut request = Request::builder(&Route::CreateMessage {
409 channel_id: self.channel_id.get(),
410 });
411
412 if fields.allowed_mentions.is_none() {
414 if let Some(allowed_mentions) = self.http.default_allowed_mentions() {
415 fields.allowed_mentions = Some(Nullable(Some(allowed_mentions)));
416 }
417 }
418
419 if !self.attachment_manager.is_empty() {
422 let form = if let Some(payload_json) = fields.payload_json {
423 self.attachment_manager.build_form(payload_json)
424 } else {
425 fields.attachments = Some(self.attachment_manager.get_partial_attachments());
426
427 let fields = crate::json::to_vec(&fields).map_err(Error::json)?;
428
429 self.attachment_manager.build_form(fields.as_ref())
430 };
431
432 request = request.form(form);
433 } else if let Some(payload_json) = fields.payload_json {
434 request = request.body(payload_json.to_vec());
435 } else {
436 request = request.json(&fields);
437 }
438
439 request.build()
440 }
441}