Skip to main content

twilight_model/http/
attachment.rs

1//! Models used when sending attachments to Discord.
2
3use serde::{Deserialize, Serialize};
4
5/// Attachments used in messages.
6///
7/// # Examples
8///
9/// Create an attachment of a short JSON blob describing a cat with a
10/// description for screen readers:
11///
12/// ```
13/// use twilight_model::http::attachment::Attachment;
14///
15/// let filename = "twilight_sparkle.json".to_owned();
16/// let file_content = br#"{
17///     "best_friend": "Spike",
18///     "cutie_mark": "sparkles",
19///     "name": "Twilight Sparkle"
20/// }"#
21/// .to_vec();
22/// let id = 1;
23///
24/// let mut attachment = Attachment::from_bytes(filename, file_content, id);
25/// attachment.description("Raw data about Twilight Sparkle".to_owned());
26/// ```
27#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
28pub struct Attachment {
29    /// Title of the file.
30    #[serde(skip_serializing_if = "Option::is_none")]
31    pub title: Option<String>,
32    /// Description of the attachment, useful for screen readers and users
33    /// requiring alt text.
34    #[serde(skip_serializing_if = "Option::is_none")]
35    pub description: Option<String>,
36    /// Content of the file.
37    #[serde(skip)]
38    pub file: Vec<u8>,
39    /// Name of the file.
40    ///
41    /// Examples may be `twilight_sparkle.png`, `cat.jpg`, or `logs.txt`.
42    pub filename: String,
43    /// Unique ID of the attachment in the message.
44    ///
45    /// While attachment IDs can be the same as attachments in other messages,
46    /// they must be unique within the same message. Attachment IDs don't need
47    /// to be in any particular format; for example, IDs of 0, 100, the current
48    /// timestamp, and so on are all valid.
49    pub id: u64,
50    /// Duration of the audio or video file.
51    ///
52    /// Required for voice messages.
53    #[serde(skip_serializing_if = "Option::is_none")]
54    pub duration_secs: Option<f64>,
55    /// Base64 encoded bytearray representing a sampled waveform.
56    ///
57    /// Required for voice messages.
58    #[serde(skip_serializing_if = "Option::is_none")]
59    pub waveform: Option<String>,
60    /// Whether the attachment should be marked as a spoiler and blurred until clicked.
61    ///
62    /// This sets the [`IS_SPOILER`] attachment flag.
63    ///
64    /// [`IS_SPOILER`]: twilight_model::channel::attachment_flags::AttachmentFlags::IS_SPOILER
65    #[serde(skip_serializing_if = "Option::is_none")]
66    pub is_spoiler: Option<bool>,
67}
68
69impl Attachment {
70    /// Create an attachment from a filename and bytes.
71    ///
72    /// # Examples
73    ///
74    /// Create an attachment with a grocery list named "grocerylist.txt":
75    ///
76    /// ```
77    /// use twilight_model::http::attachment::Attachment;
78    ///
79    /// let filename = "grocerylist.txt".to_owned();
80    /// let file_content = b"Apples\nGrapes\nLemonade".to_vec();
81    /// let id = 1;
82    ///
83    /// let attachment = Attachment::from_bytes(filename, file_content, id);
84    /// ```
85    pub const fn from_bytes(filename: String, file: Vec<u8>, id: u64) -> Self {
86        Self {
87            title: None,
88            description: None,
89            file,
90            filename,
91            id,
92            duration_secs: None,
93            waveform: None,
94            is_spoiler: None,
95        }
96    }
97
98    /// Set the description of the attachment.
99    ///
100    /// Attachment descriptions are useful for those requiring screen readers
101    /// and are displayed as alt text.
102    pub fn description(&mut self, description: String) {
103        self.description = Some(description);
104    }
105}