atagen

matrix-rust-sdk

public
Star0
Watch0
ssh://brewery@pls.lobotomise.me:33/atagen/matrix-rust-sdk.git
crates/matrix-sdk/src/attachment.rsRust378 lines10.5 KB
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
17
use std::time::Duration;
18
19
use ruma::{
20
    OwnedTransactionId, UInt, assign,
21
    events::{
22
        Mentions,
23
        room::{
24
            ImageInfo, ThumbnailInfo,
25
            message::{AudioInfo, FileInfo, TextMessageEventContent, VideoInfo},
26
        },
27
    },
28
};
29
30
use crate::room::reply::Reply;
31
32
/// Base metadata about an image.
33
#[derive(Debug, Clone, Default)]
34
pub struct BaseImageInfo {
35
    /// The height of the image in pixels.
36
    pub height: Option<UInt>,
37
    /// The width of the image in pixels.
38
    pub width: Option<UInt>,
39
    /// The file size of the image in bytes.
40
    pub size: Option<UInt>,
41
    /// The [BlurHash](https://blurha.sh/) for this image.
42
    pub blurhash: Option<String>,
43
    /// Whether this image is animated.
44
    pub is_animated: Option<bool>,
45
}
46
47
/// Base metadata about a video.
48
#[derive(Debug, Clone, Default)]
49
pub struct BaseVideoInfo {
50
    /// The duration of the video.
51
    pub duration: Option<Duration>,
52
    /// The height of the video in pixels.
53
    pub height: Option<UInt>,
54
    /// The width of the video in pixels.
55
    pub width: Option<UInt>,
56
    /// The file size of the video in bytes.
57
    pub size: Option<UInt>,
58
    /// The [BlurHash](https://blurha.sh/) for this video.
59
    pub blurhash: Option<String>,
60
}
61
62
/// Base metadata about an audio clip.
63
#[derive(Debug, Clone, Default)]
64
pub struct BaseAudioInfo {
65
    /// The duration of the audio clip.
66
    pub duration: Option<Duration>,
67
    /// The file size of the audio clip in bytes.
68
    pub size: Option<UInt>,
69
    /// The waveform of the audio clip.
70
    ///
71
    /// Must only include values between 0 and 1.
72
    pub waveform: Option<Vec<f32>>,
73
}
74
75
/// Base metadata about a file.
76
#[derive(Debug, Clone, Default)]
77
pub struct BaseFileInfo {
78
    /// The size of the file in bytes.
79
    pub size: Option<UInt>,
80
}
81
82
/// Types of metadata for an attachment.
83
#[derive(Debug)]
84
pub enum AttachmentInfo {
85
    /// The metadata of an image.
86
    Image(BaseImageInfo),
87
    /// The metadata of a video.
88
    Video(BaseVideoInfo),
89
    /// The metadata of an audio clip.
90
    Audio(BaseAudioInfo),
91
    /// The metadata of a file.
92
    File(BaseFileInfo),
93
    /// The metadata of a voice message
94
    Voice(BaseAudioInfo),
95
}
96
97
impl 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
112
impl 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
127
impl From<AttachmentInfo> for AudioInfo {
128
    fn from(info: AttachmentInfo) -> Self {
129
        match info {
130
            AttachmentInfo::Audio(info) | AttachmentInfo::Voice(info) => {
131
                assign!(AudioInfo::new(), {
132
                    duration: info.duration,
133
                    size: info.size,
134
                })
135
            }
136
            _ => AudioInfo::new(),
137
        }
138
    }
139
}
140
141
impl From<AttachmentInfo> for FileInfo {
142
    fn from(info: AttachmentInfo) -> Self {
143
        match info {
144
            AttachmentInfo::File(info) => assign!(FileInfo::new(), {
145
                size: info.size,
146
            }),
147
            _ => FileInfo::new(),
148
        }
149
    }
150
}
151
152
/// A thumbnail to upload and send for an attachment.
153
#[derive(Debug)]
154
pub struct Thumbnail {
155
    /// The raw bytes of the thumbnail.
156
    pub data: Vec<u8>,
157
    /// The type of the thumbnail, this will be used as the content-type header.
158
    pub content_type: mime::Mime,
159
    /// The height of the thumbnail in pixels.
160
    pub height: UInt,
161
    /// The width of the thumbnail in pixels.
162
    pub width: UInt,
163
    /// The file size of the thumbnail in bytes.
164
    pub size: UInt,
165
}
166
167
impl Thumbnail {
168
    /// Convert this `Thumbnail` into a `(data, content_type, info)` tuple.
169
    pub fn into_parts(self) -> (Vec<u8>, mime::Mime, Box<ThumbnailInfo>) {
170
        let thumbnail_info = assign!(ThumbnailInfo::new(), {
171
            height: Some(self.height),
172
            width: Some(self.width),
173
            size: Some(self.size),
174
            mimetype: Some(self.content_type.to_string())
175
        });
176
        (self.data, self.content_type, Box::new(thumbnail_info))
177
    }
178
}
179
180
/// Configuration for sending an attachment.
181
#[derive(Debug, Default)]
182
pub struct AttachmentConfig {
183
    /// A fixed transaction id to be used for sending this attachment.
184
    ///
185
    /// Otherwise, a random one will be generated.
186
    pub txn_id: Option<OwnedTransactionId>,
187
188
    /// Type-specific metadata about the attachment.
189
    pub info: Option<AttachmentInfo>,
190
191
    /// An optional thumbnail to send with the attachment.
192
    pub thumbnail: Option<Thumbnail>,
193
194
    /// An optional caption for the attachment.
195
    pub caption: Option<TextMessageEventContent>,
196
197
    /// Intentional mentions to be included in the media event.
198
    pub mentions: Option<Mentions>,
199
200
    /// Reply parameters for the attachment (replied-to event and thread-related
201
    /// metadata).
202
    pub reply: Option<Reply>,
203
}
204
205
impl AttachmentConfig {
206
    /// Create a new empty `AttachmentConfig`.
207
    pub fn new() -> Self {
208
        Self::default()
209
    }
210
211
    /// Set the thumbnail to send.
212
    ///
213
    /// # Arguments
214
    ///
215
    /// * `thumbnail` - The thumbnail of the media. If the `content_type` does
216
    ///   not support it (e.g. audio clips), it is ignored.
217
    #[must_use]
218
    pub fn thumbnail(mut self, thumbnail: Option<Thumbnail>) -> Self {
219
        self.thumbnail = thumbnail;
220
        self
221
    }
222
223
    /// Set the transaction ID to send.
224
    ///
225
    /// # Arguments
226
    ///
227
    /// * `txn_id` - A unique ID that can be attached to a `MessageEvent` held
228
    ///   in its unsigned field as `transaction_id`. If not given, one is
229
    ///   created for the message.
230
    #[must_use]
231
    pub fn txn_id(mut self, txn_id: OwnedTransactionId) -> Self {
232
        self.txn_id = Some(txn_id);
233
        self
234
    }
235
236
    /// Set the media metadata to send.
237
    ///
238
    /// # Arguments
239
    ///
240
    /// * `info` - The metadata of the media. If the `AttachmentInfo` type
241
    ///   doesn't match the `content_type`, it is ignored.
242
    #[must_use]
243
    pub fn info(mut self, info: AttachmentInfo) -> Self {
244
        self.info = Some(info);
245
        self
246
    }
247
248
    /// Set the optional caption.
249
    ///
250
    /// # Arguments
251
    ///
252
    /// * `caption` - The optional caption.
253
    pub fn caption(mut self, caption: Option<TextMessageEventContent>) -> Self {
254
        self.caption = caption;
255
        self
256
    }
257
258
    /// Set the mentions of the message.
259
    ///
260
    /// # Arguments
261
    ///
262
    /// * `mentions` - The mentions of the message.
263
    pub fn mentions(mut self, mentions: Option<Mentions>) -> Self {
264
        self.mentions = mentions;
265
        self
266
    }
267
268
    /// Set the reply information of the message.
269
    ///
270
    /// # Arguments
271
    ///
272
    /// * `reply` - The reply information of the message.
273
    pub fn reply(mut self, reply: Option<Reply>) -> Self {
274
        self.reply = reply;
275
        self
276
    }
277
}
278
279
/// Configuration for sending a gallery.
280
#[cfg(feature = "unstable-msc4274")]
281
#[derive(Debug, Default)]
282
pub struct GalleryConfig {
283
    pub(crate) txn_id: Option<OwnedTransactionId>,
284
    pub(crate) items: Vec<GalleryItemInfo>,
285
    pub(crate) caption: Option<TextMessageEventContent>,
286
    pub(crate) mentions: Option<Mentions>,
287
    pub(crate) reply: Option<Reply>,
288
}
289
290
#[cfg(feature = "unstable-msc4274")]
291
impl GalleryConfig {
292
    /// Create a new empty `GalleryConfig`.
293
    pub fn new() -> Self {
294
        Self::default()
295
    }
296
297
    /// Set the transaction ID to send.
298
    ///
299
    /// # Arguments
300
    ///
301
    /// * `txn_id` - A unique ID that can be attached to a `MessageEvent` held
302
    ///   in its unsigned field as `transaction_id`. If not given, one is
303
    ///   created for the message.
304
    #[must_use]
305
    pub fn txn_id(mut self, txn_id: OwnedTransactionId) -> Self {
306
        self.txn_id = Some(txn_id);
307
        self
308
    }
309
310
    /// Adds a media item to the gallery.
311
    ///
312
    /// # Arguments
313
    ///
314
    /// * `item` - Information about the item to be added.
315
    #[must_use]
316
    pub fn add_item(mut self, item: GalleryItemInfo) -> Self {
317
        self.items.push(item);
318
        self
319
    }
320
321
    /// Set the optional caption.
322
    ///
323
    /// # Arguments
324
    ///
325
    /// * `caption` - The optional caption.
326
    pub fn caption(mut self, caption: Option<TextMessageEventContent>) -> Self {
327
        self.caption = caption;
328
        self
329
    }
330
331
    /// Set the mentions of the message.
332
    ///
333
    /// # Arguments
334
    ///
335
    /// * `mentions` - The mentions of the message.
336
    pub fn mentions(mut self, mentions: Option<Mentions>) -> Self {
337
        self.mentions = mentions;
338
        self
339
    }
340
341
    /// Set the reply information of the message.
342
    ///
343
    /// # Arguments
344
    ///
345
    /// * `reply` - The reply information of the message.
346
    pub fn reply(mut self, reply: Option<Reply>) -> Self {
347
        self.reply = reply;
348
        self
349
    }
350
351
    /// Returns the number of media items in the gallery.
352
    pub fn len(&self) -> usize {
353
        self.items.len()
354
    }
355
356
    /// Checks whether the gallery contains any media items or not.
357
    pub fn is_empty(&self) -> bool {
358
        self.items.is_empty()
359
    }
360
}
361
362
#[cfg(feature = "unstable-msc4274")]
363
#[derive(Debug)]
364
/// Metadata for a gallery item
365
pub struct GalleryItemInfo {
366
    /// The filename.
367
    pub filename: String,
368
    /// The mime type.
369
    pub content_type: mime::Mime,
370
    /// The binary data.
371
    pub data: Vec<u8>,
372
    /// The attachment info.
373
    pub attachment_info: AttachmentInfo,
374
    /// The caption.
375
    pub caption: Option<TextMessageEventContent>,
376
    /// The thumbnail.
377
    pub thumbnail: Option<Thumbnail>,
378
}