matrix_sdk/
attachment.rs

1// Copyright 2022 Kévin Commaille
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Types and traits for attachments.
16
17use std::time::Duration;
18
19use ruma::{
20    assign,
21    events::{
22        room::{
23            message::{AudioInfo, FileInfo, FormattedBody, VideoInfo},
24            ImageInfo, ThumbnailInfo,
25        },
26        Mentions,
27    },
28    OwnedTransactionId, TransactionId, UInt,
29};
30
31/// Base metadata about an image.
32#[derive(Debug, Clone, Default)]
33pub struct BaseImageInfo {
34    /// The height of the image in pixels.
35    pub height: Option<UInt>,
36    /// The width of the image in pixels.
37    pub width: Option<UInt>,
38    /// The file size of the image in bytes.
39    pub size: Option<UInt>,
40    /// The [BlurHash](https://blurha.sh/) for this image.
41    pub blurhash: Option<String>,
42    /// Whether this image is animated.
43    pub is_animated: Option<bool>,
44}
45
46/// Base metadata about a video.
47#[derive(Debug, Clone, Default)]
48pub struct BaseVideoInfo {
49    /// The duration of the video.
50    pub duration: Option<Duration>,
51    /// The height of the video in pixels.
52    pub height: Option<UInt>,
53    /// The width of the video in pixels.
54    pub width: Option<UInt>,
55    /// The file size of the video in bytes.
56    pub size: Option<UInt>,
57    /// The [BlurHash](https://blurha.sh/) for this video.
58    pub blurhash: Option<String>,
59}
60
61/// Base metadata about an audio clip.
62#[derive(Debug, Clone, Default)]
63pub struct BaseAudioInfo {
64    /// The duration of the audio clip.
65    pub duration: Option<Duration>,
66    /// The file size of the audio clip in bytes.
67    pub size: Option<UInt>,
68}
69
70/// Base metadata about a file.
71#[derive(Debug, Clone, Default)]
72pub struct BaseFileInfo {
73    /// The size of the file in bytes.
74    pub size: Option<UInt>,
75}
76
77/// Types of metadata for an attachment.
78#[derive(Debug)]
79pub enum AttachmentInfo {
80    /// The metadata of an image.
81    Image(BaseImageInfo),
82    /// The metadata of a video.
83    Video(BaseVideoInfo),
84    /// The metadata of an audio clip.
85    Audio(BaseAudioInfo),
86    /// The metadata of a file.
87    File(BaseFileInfo),
88    /// The metadata of a voice message
89    Voice {
90        /// The audio info
91        audio_info: BaseAudioInfo,
92        /// The waveform of the voice message
93        waveform: Option<Vec<u16>>,
94    },
95}
96
97impl From<AttachmentInfo> for ImageInfo {
98    fn from(info: AttachmentInfo) -> Self {
99        match info {
100            AttachmentInfo::Image(info) => assign!(ImageInfo::new(), {
101                height: info.height,
102                width: info.width,
103                size: info.size,
104                blurhash: info.blurhash,
105                is_animated: info.is_animated,
106            }),
107            _ => ImageInfo::new(),
108        }
109    }
110}
111
112impl From<AttachmentInfo> for VideoInfo {
113    fn from(info: AttachmentInfo) -> Self {
114        match info {
115            AttachmentInfo::Video(info) => assign!(VideoInfo::new(), {
116                duration: info.duration,
117                height: info.height,
118                width: info.width,
119                size: info.size,
120                blurhash: info.blurhash,
121            }),
122            _ => VideoInfo::new(),
123        }
124    }
125}
126
127impl From<AttachmentInfo> for AudioInfo {
128    fn from(info: AttachmentInfo) -> Self {
129        match info {
130            AttachmentInfo::Audio(info) => assign!(AudioInfo::new(), {
131                duration: info.duration,
132                size: info.size,
133            }),
134            AttachmentInfo::Voice { audio_info, .. } => assign!(AudioInfo::new(), {
135                duration: audio_info.duration,
136                size: audio_info.size,
137            }),
138            _ => AudioInfo::new(),
139        }
140    }
141}
142
143impl From<AttachmentInfo> for FileInfo {
144    fn from(info: AttachmentInfo) -> Self {
145        match info {
146            AttachmentInfo::File(info) => assign!(FileInfo::new(), {
147                size: info.size,
148            }),
149            _ => FileInfo::new(),
150        }
151    }
152}
153
154/// A thumbnail to upload and send for an attachment.
155#[derive(Debug)]
156pub struct Thumbnail {
157    /// The raw bytes of the thumbnail.
158    pub data: Vec<u8>,
159    /// The type of the thumbnail, this will be used as the content-type header.
160    pub content_type: mime::Mime,
161    /// The height of the thumbnail in pixels.
162    pub height: UInt,
163    /// The width of the thumbnail in pixels.
164    pub width: UInt,
165    /// The file size of the thumbnail in bytes.
166    pub size: UInt,
167}
168
169impl Thumbnail {
170    /// Convert this `Thumbnail` into a `(data, content_type, info)` tuple.
171    pub fn into_parts(self) -> (Vec<u8>, mime::Mime, Box<ThumbnailInfo>) {
172        let thumbnail_info = assign!(ThumbnailInfo::new(), {
173            height: Some(self.height),
174            width: Some(self.width),
175            size: Some(self.size),
176            mimetype: Some(self.content_type.to_string())
177        });
178        (self.data, self.content_type, Box::new(thumbnail_info))
179    }
180}
181
182/// Configuration for sending an attachment.
183#[derive(Debug, Default)]
184pub struct AttachmentConfig {
185    pub(crate) txn_id: Option<OwnedTransactionId>,
186    pub(crate) info: Option<AttachmentInfo>,
187    pub(crate) thumbnail: Option<Thumbnail>,
188    pub(crate) caption: Option<String>,
189    pub(crate) formatted_caption: Option<FormattedBody>,
190    pub(crate) mentions: Option<Mentions>,
191}
192
193impl AttachmentConfig {
194    /// Create a new empty `AttachmentConfig`.
195    pub fn new() -> Self {
196        Self::default()
197    }
198
199    /// Set the thumbnail to send.
200    ///
201    /// # Arguments
202    ///
203    /// * `thumbnail` - The thumbnail of the media. If the `content_type` does
204    ///   not support it (e.g. audio clips), it is ignored.
205    #[must_use]
206    pub fn thumbnail(mut self, thumbnail: Option<Thumbnail>) -> Self {
207        self.thumbnail = thumbnail;
208        self
209    }
210
211    /// Set the transaction ID to send.
212    ///
213    /// # Arguments
214    ///
215    /// * `txn_id` - A unique ID that can be attached to a `MessageEvent` held
216    ///   in its unsigned field as `transaction_id`. If not given, one is
217    ///   created for the message.
218    #[must_use]
219    pub fn txn_id(mut self, txn_id: &TransactionId) -> Self {
220        self.txn_id = Some(txn_id.to_owned());
221        self
222    }
223
224    /// Set the media metadata to send.
225    ///
226    /// # Arguments
227    ///
228    /// * `info` - The metadata of the media. If the `AttachmentInfo` type
229    ///   doesn't match the `content_type`, it is ignored.
230    #[must_use]
231    pub fn info(mut self, info: AttachmentInfo) -> Self {
232        self.info = Some(info);
233        self
234    }
235
236    /// Set the optional caption
237    ///
238    /// # Arguments
239    ///
240    /// * `caption` - The optional caption
241    pub fn caption(mut self, caption: Option<String>) -> Self {
242        self.caption = caption;
243        self
244    }
245
246    /// Set the optional formatted caption
247    ///
248    /// # Arguments
249    ///
250    /// * `formatted_caption` - The optional formatted caption
251    pub fn formatted_caption(mut self, formatted_caption: Option<FormattedBody>) -> Self {
252        self.formatted_caption = formatted_caption;
253        self
254    }
255
256    /// Set the mentions of the message.
257    ///
258    /// # Arguments
259    ///
260    /// * `mentions` - The mentions of the message
261    pub fn mentions(mut self, mentions: Option<Mentions>) -> Self {
262        self.mentions = mentions;
263        self
264    }
265}