mirror of
https://github.com/matrix-org/matrix-rust-sdk.git
synced 2026-05-06 15:04:11 -04:00
feat(sdk): Create AttachmentConfig struct
This commit is contained in:
@@ -147,7 +147,7 @@ impl<'a, R: Read + 'a> AttachmentDecryptor<'a, R> {
|
||||
}
|
||||
|
||||
/// A wrapper that transparently encrypts anything that implements `Read`.
|
||||
pub struct AttachmentEncryptor<'a, R: Read + 'a> {
|
||||
pub struct AttachmentEncryptor<'a, R: Read + ?Sized + 'a> {
|
||||
finished: bool,
|
||||
inner: &'a mut R,
|
||||
web_key: JsonWebKey,
|
||||
@@ -157,7 +157,7 @@ pub struct AttachmentEncryptor<'a, R: Read + 'a> {
|
||||
sha: Sha256,
|
||||
}
|
||||
|
||||
impl<'a, R: 'a + Read + std::fmt::Debug> std::fmt::Debug for AttachmentEncryptor<'a, R> {
|
||||
impl<'a, R: 'a + Read + std::fmt::Debug + ?Sized> std::fmt::Debug for AttachmentEncryptor<'a, R> {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("AttachmentEncryptor")
|
||||
.field("inner", &self.inner)
|
||||
@@ -166,7 +166,7 @@ impl<'a, R: 'a + Read + std::fmt::Debug> std::fmt::Debug for AttachmentEncryptor
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, R: Read + 'a> Read for AttachmentEncryptor<'a, R> {
|
||||
impl<'a, R: Read + ?Sized + 'a> Read for AttachmentEncryptor<'a, R> {
|
||||
fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
|
||||
let read_bytes = self.inner.read(buf)?;
|
||||
|
||||
@@ -185,7 +185,7 @@ impl<'a, R: Read + 'a> Read for AttachmentEncryptor<'a, R> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, R: Read + 'a> AttachmentEncryptor<'a, R> {
|
||||
impl<'a, R: Read + ?Sized + 'a> AttachmentEncryptor<'a, R> {
|
||||
/// Wrap the given reader encrypting all the data we read from it.
|
||||
///
|
||||
/// After all the reads are done, and all the data is encrypted that we wish
|
||||
|
||||
@@ -9,7 +9,7 @@ use std::{
|
||||
|
||||
use matrix_sdk::{
|
||||
self,
|
||||
attachment::Thumbnail,
|
||||
attachment::AttachmentConfig,
|
||||
config::SyncSettings,
|
||||
room::Room,
|
||||
ruma::events::room::message::{
|
||||
@@ -39,9 +39,8 @@ async fn on_room_message(event: SyncRoomMessageEvent, room: Room, image: Arc<Mut
|
||||
if msg_body.contains("!image") {
|
||||
println!("sending image");
|
||||
let mut image = image.lock().await;
|
||||
let none_thumbnail: Option<Thumbnail<&[u8]>> = None;
|
||||
|
||||
room.send_attachment("cat", &mime::IMAGE_JPEG, &mut *image, None, none_thumbnail, None)
|
||||
room.send_attachment("cat", &mime::IMAGE_JPEG, &mut *image, AttachmentConfig::new())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ use ruma::{
|
||||
message::{AudioInfo, FileInfo, VideoInfo},
|
||||
ImageInfo, ThumbnailInfo,
|
||||
},
|
||||
UInt,
|
||||
TransactionId, UInt,
|
||||
};
|
||||
|
||||
#[cfg(feature = "image_proc")]
|
||||
@@ -157,8 +157,114 @@ pub struct Thumbnail<'a, R: Read> {
|
||||
pub info: Option<BaseThumbnailInfo>,
|
||||
}
|
||||
|
||||
/// Typed `None` for an `<Option<Thumbnail>>`.
|
||||
pub const NONE_THUMBNAIL: Option<Thumbnail<&[u8]>> = None;
|
||||
impl Thumbnail<'static, &'static [u8]> {
|
||||
/// Typed `None` for an `<Option<Thumbnail>>`.
|
||||
pub const NONE: Option<Thumbnail<'static, &'static [u8]>> = None;
|
||||
}
|
||||
|
||||
/// Configuration for sending an attachment.
|
||||
#[derive(Debug)]
|
||||
pub struct AttachmentConfig<'a, R: Read> {
|
||||
pub(crate) txn_id: Option<&'a TransactionId>,
|
||||
pub(crate) info: Option<AttachmentInfo>,
|
||||
pub(crate) thumbnail: Option<Thumbnail<'a, R>>,
|
||||
#[cfg(feature = "image_proc")]
|
||||
pub(crate) generate_thumbnail: bool,
|
||||
#[cfg(feature = "image_proc")]
|
||||
pub(crate) thumbnail_size: Option<(u32, u32)>,
|
||||
}
|
||||
|
||||
impl AttachmentConfig<'static, &'static [u8]> {
|
||||
/// Create a new default `AttachmentConfig` without providing a thumbnail.
|
||||
///
|
||||
/// To provide a thumbnail use [`with_thumbnail()`].
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
txn_id: Default::default(),
|
||||
info: Default::default(),
|
||||
thumbnail: None,
|
||||
#[cfg(feature = "image_proc")]
|
||||
generate_thumbnail: Default::default(),
|
||||
#[cfg(feature = "image_proc")]
|
||||
thumbnail_size: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate the thumbnail to send for this media.
|
||||
///
|
||||
/// Uses [`attachment::generate_image_thumbnail()`].
|
||||
///
|
||||
/// Thumbnails can only be generated for supported image attachments. For
|
||||
/// more information, see the [image](https://github.com/image-rs/image)
|
||||
/// crate.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `size` - The size of the thumbnail in pixels as a `(width, height)`
|
||||
/// tuple. If set to `None`, defaults to `(800, 600)`.
|
||||
#[cfg(feature = "image_proc")]
|
||||
#[must_use]
|
||||
pub fn generate_thumbnail(mut self, size: Option<(u32, u32)>) -> Self {
|
||||
self.generate_thumbnail = true;
|
||||
self.thumbnail_size = size;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for AttachmentConfig<'static, &'static [u8]> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, R: Read> AttachmentConfig<'a, R> {
|
||||
/// Create a new default `AttachmentConfig` with `thumbnail`.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `thumbnail` - The thumbnail of the media. If the `content_type` does
|
||||
/// not support it (eg audio clips), it is ignored.
|
||||
///
|
||||
/// To generate automatically a thumbnail from an image, use
|
||||
/// [`new()`] and
|
||||
/// [`generate_thumbnail()`].
|
||||
pub fn with_thumbnail(thumbnail: Thumbnail<'a, R>) -> Self {
|
||||
Self {
|
||||
txn_id: Default::default(),
|
||||
info: Default::default(),
|
||||
thumbnail: Some(thumbnail),
|
||||
#[cfg(feature = "image_proc")]
|
||||
generate_thumbnail: Default::default(),
|
||||
#[cfg(feature = "image_proc")]
|
||||
thumbnail_size: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Set the transaction ID to send.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `txn_id` - A unique ID that can be attached to a `MessageEvent` held
|
||||
/// in its unsigned field as `transaction_id`. If not given, one is created
|
||||
/// for the message.
|
||||
#[must_use]
|
||||
pub fn txn_id(mut self, txn_id: &'a TransactionId) -> Self {
|
||||
self.txn_id = Some(txn_id);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the media metadata to send.
|
||||
///
|
||||
/// # Arguments
|
||||
///
|
||||
/// * `info` - The metadata of the media. If the `AttachmentInfo` type
|
||||
/// doesn't match the `content_type`, it is ignored.
|
||||
#[must_use]
|
||||
pub fn info(mut self, info: AttachmentInfo) -> Self {
|
||||
self.info = Some(info);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Generate a thumbnail for an image.
|
||||
///
|
||||
@@ -178,14 +284,18 @@ pub const NONE_THUMBNAIL: Option<Thumbnail<&[u8]>> = None;
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use std::{path::PathBuf, fs::File, io::{BufReader, Read, Seek}};
|
||||
/// # use matrix_sdk::{Client, attachment::{Thumbnail, generate_image_thumbnail}, ruma::room_id};
|
||||
/// # use std::{path::PathBuf, fs::File, io::{BufReader, Cursor, Read, Seek}};
|
||||
/// # use matrix_sdk::{
|
||||
/// # Client,
|
||||
/// # attachment::{AttachmentConfig, Thumbnail, generate_image_thumbnail},
|
||||
/// # ruma::room_id
|
||||
/// # };
|
||||
/// # use url::Url;
|
||||
/// # use mime;
|
||||
/// # use futures::executor::block_on;
|
||||
/// # block_on(async {
|
||||
/// # let homeserver = Url::parse("http://localhost:8080")?;
|
||||
/// # let mut client = Client::new(homeserver)?;
|
||||
/// # let mut client = Client::new(homeserver).await?;
|
||||
/// # let room_id = room_id!("!test:localhost");
|
||||
/// let path = PathBuf::from("/home/example/my-cat.jpg");
|
||||
/// let mut image = BufReader::new(File::open(path)?);
|
||||
@@ -195,11 +305,12 @@ pub const NONE_THUMBNAIL: Option<Thumbnail<&[u8]>> = None;
|
||||
/// &mut image,
|
||||
/// None
|
||||
/// )?;
|
||||
/// let thumbnail = Thumbnail {
|
||||
/// reader: &mut thumbnail_data.as_slice(),
|
||||
/// let mut cursor = Cursor::new(thumbnail_data);
|
||||
/// let config = AttachmentConfig::with_thumbnail(Thumbnail {
|
||||
/// reader: &mut cursor,
|
||||
/// content_type: &mime::IMAGE_JPEG,
|
||||
/// info: Some(thumbnail_info),
|
||||
/// };
|
||||
/// });
|
||||
///
|
||||
/// image.rewind()?;
|
||||
///
|
||||
@@ -208,9 +319,7 @@ pub const NONE_THUMBNAIL: Option<Thumbnail<&[u8]>> = None;
|
||||
/// "My favorite cat",
|
||||
/// &mime::IMAGE_JPEG,
|
||||
/// &mut image,
|
||||
/// None,
|
||||
/// Some(thumbnail),
|
||||
/// None,
|
||||
/// config,
|
||||
/// ).await?;
|
||||
/// }
|
||||
/// # Result::<_, matrix_sdk::Error>::Ok(()) });
|
||||
|
||||
@@ -1623,7 +1623,7 @@ impl Client {
|
||||
pub async fn upload(
|
||||
&self,
|
||||
content_type: &Mime,
|
||||
reader: &mut impl Read,
|
||||
reader: &mut (impl Read + ?Sized),
|
||||
) -> Result<create_content::Response> {
|
||||
let mut data = Vec::new();
|
||||
reader.read_to_end(&mut data)?;
|
||||
@@ -2460,8 +2460,8 @@ pub(crate) mod test {
|
||||
use super::{Client, Session, Url};
|
||||
use crate::{
|
||||
attachment::{
|
||||
AttachmentInfo, BaseImageInfo, BaseThumbnailInfo, BaseVideoInfo, Thumbnail,
|
||||
NONE_THUMBNAIL,
|
||||
AttachmentConfig, AttachmentInfo, BaseImageInfo, BaseThumbnailInfo, BaseVideoInfo,
|
||||
Thumbnail,
|
||||
},
|
||||
config::{ClientConfig, RequestConfig, SyncSettings},
|
||||
HttpError, RoomMember,
|
||||
@@ -3279,7 +3279,7 @@ pub(crate) mod test {
|
||||
let mut media = Cursor::new("Hello world");
|
||||
|
||||
let response = room
|
||||
.send_attachment("image", &mime::IMAGE_JPEG, &mut media, None, NONE_THUMBNAIL, None)
|
||||
.send_attachment("image", &mime::IMAGE_JPEG, &mut media, AttachmentConfig::new())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
@@ -3328,24 +3328,15 @@ pub(crate) mod test {
|
||||
|
||||
let mut media = Cursor::new("Hello world");
|
||||
|
||||
let info = AttachmentInfo::Image(BaseImageInfo {
|
||||
let config = AttachmentConfig::new().info(AttachmentInfo::Image(BaseImageInfo {
|
||||
height: Some(uint!(600)),
|
||||
width: Some(uint!(800)),
|
||||
size: None,
|
||||
blurhash: None,
|
||||
});
|
||||
}));
|
||||
|
||||
let response = room
|
||||
.send_attachment(
|
||||
"image",
|
||||
&mime::IMAGE_JPEG,
|
||||
&mut media,
|
||||
Some(info),
|
||||
NONE_THUMBNAIL,
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let response =
|
||||
room.send_attachment("image", &mime::IMAGE_JPEG, &mut media, config).await.unwrap();
|
||||
|
||||
upload_mock.assert();
|
||||
assert_eq!(event_id!("$h29iv0s8:example.com"), response.event_id)
|
||||
@@ -3393,24 +3384,15 @@ pub(crate) mod test {
|
||||
|
||||
let mut media = Cursor::new("Hello world");
|
||||
|
||||
let info = AttachmentInfo::Video(BaseVideoInfo {
|
||||
let config = AttachmentConfig::new().info(AttachmentInfo::Video(BaseVideoInfo {
|
||||
height: Some(uint!(600)),
|
||||
width: Some(uint!(800)),
|
||||
duration: Some(uint!(3600)),
|
||||
size: None,
|
||||
blurhash: None,
|
||||
});
|
||||
}));
|
||||
|
||||
let response = room
|
||||
.send_attachment(
|
||||
"image",
|
||||
&mime::IMAGE_JPEG,
|
||||
&mut media,
|
||||
Some(info),
|
||||
NONE_THUMBNAIL,
|
||||
None,
|
||||
)
|
||||
.await;
|
||||
let response = room.send_attachment("image", &mime::IMAGE_JPEG, &mut media, config).await;
|
||||
|
||||
assert!(response.is_err())
|
||||
}
|
||||
@@ -3465,15 +3447,9 @@ pub(crate) mod test {
|
||||
|
||||
let mut media = Cursor::new("Hello world");
|
||||
|
||||
let info = AttachmentInfo::Image(BaseImageInfo {
|
||||
height: Some(uint!(600)),
|
||||
width: Some(uint!(800)),
|
||||
size: None,
|
||||
blurhash: None,
|
||||
});
|
||||
|
||||
let mut thumbnail_reader = Cursor::new("Thumbnail");
|
||||
let thumbnail = Thumbnail {
|
||||
|
||||
let config = AttachmentConfig::with_thumbnail(Thumbnail {
|
||||
reader: &mut thumbnail_reader,
|
||||
content_type: &mime::IMAGE_JPEG,
|
||||
info: Some(BaseThumbnailInfo {
|
||||
@@ -3481,19 +3457,16 @@ pub(crate) mod test {
|
||||
width: Some(uint!(480)),
|
||||
size: Some(uint!(3600)),
|
||||
}),
|
||||
};
|
||||
})
|
||||
.info(AttachmentInfo::Image(BaseImageInfo {
|
||||
height: Some(uint!(600)),
|
||||
width: Some(uint!(800)),
|
||||
size: None,
|
||||
blurhash: None,
|
||||
}));
|
||||
|
||||
let response = room
|
||||
.send_attachment(
|
||||
"image",
|
||||
&mime::IMAGE_JPEG,
|
||||
&mut media,
|
||||
Some(info),
|
||||
Some(thumbnail),
|
||||
None,
|
||||
)
|
||||
.await
|
||||
.unwrap();
|
||||
let response =
|
||||
room.send_attachment("image", &mime::IMAGE_JPEG, &mut media, config).await.unwrap();
|
||||
|
||||
upload_mock.assert();
|
||||
assert_eq!(event_id!("$h29iv0s8:example.com"), response.event_id)
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
#[cfg(feature = "image_proc")]
|
||||
use std::io::{BufReader, Seek};
|
||||
use std::io::Cursor;
|
||||
#[cfg(feature = "encryption")]
|
||||
use std::sync::Arc;
|
||||
use std::{io::Read, ops::Deref};
|
||||
use std::{
|
||||
io::{BufReader, Read, Seek},
|
||||
ops::Deref,
|
||||
};
|
||||
|
||||
use matrix_sdk_common::instant::{Duration, Instant};
|
||||
#[cfg(feature = "encryption")]
|
||||
@@ -34,9 +37,9 @@ use tracing::debug;
|
||||
use tracing::instrument;
|
||||
|
||||
#[cfg(feature = "image_proc")]
|
||||
use crate::attachment::generate_image_thumbnail;
|
||||
use crate::{attachment::generate_image_thumbnail, error::ImageError};
|
||||
use crate::{
|
||||
attachment::{AttachmentInfo, Thumbnail},
|
||||
attachment::{AttachmentConfig, Thumbnail},
|
||||
error::HttpResult,
|
||||
room::Common,
|
||||
BaseRoom, Client, Result, RoomType,
|
||||
@@ -606,21 +609,13 @@ impl Joined {
|
||||
/// * `reader` - A `Reader` that will be used to fetch the raw bytes of the
|
||||
/// media.
|
||||
///
|
||||
/// * `info` - The metadata of the media. If the
|
||||
/// `AttachmentInfo` type doesn't match the `content_type`, it is ignored.
|
||||
///
|
||||
/// * `thumbnail` - The thumbnail of the media. If the `content_type` does
|
||||
/// not support it (eg audio clips), it is ignored.
|
||||
///
|
||||
/// * `txn_id` - A unique ID that can be attached to a `MessageEvent`
|
||||
/// held in its unsigned field as `transaction_id`. If not given one is
|
||||
/// created for the message.
|
||||
/// * `config` - Metadata and configuration for the attachment.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use std::{path::PathBuf, fs::File, io::Read};
|
||||
/// # use matrix_sdk::{Client, ruma::room_id, attachment::NONE_THUMBNAIL};
|
||||
/// # use matrix_sdk::{Client, ruma::room_id, attachment::AttachmentConfig};
|
||||
/// # use url::Url;
|
||||
/// # use mime;
|
||||
/// # use futures::executor::block_on;
|
||||
@@ -636,54 +631,82 @@ impl Joined {
|
||||
/// "My favorite cat",
|
||||
/// &mime::IMAGE_JPEG,
|
||||
/// &mut image,
|
||||
/// None,
|
||||
/// NONE_THUMBNAIL,
|
||||
/// None,
|
||||
/// AttachmentConfig::new(),
|
||||
/// ).await?;
|
||||
/// }
|
||||
/// # Result::<_, matrix_sdk::Error>::Ok(()) });
|
||||
/// ```
|
||||
pub async fn send_attachment<R: Read, T: Read>(
|
||||
pub async fn send_attachment<'a, R: Read + Seek, T: Read>(
|
||||
&self,
|
||||
body: &str,
|
||||
content_type: &Mime,
|
||||
reader: &mut R,
|
||||
info: Option<AttachmentInfo>,
|
||||
thumbnail: Option<Thumbnail<'_, T>>,
|
||||
txn_id: Option<&TransactionId>,
|
||||
config: AttachmentConfig<'a, T>,
|
||||
) -> Result<send_message_event::Response> {
|
||||
#[cfg(feature = "encryption")]
|
||||
let content = if self.is_encrypted() {
|
||||
self.client
|
||||
.prepare_encrypted_attachment_message(body, content_type, reader, info, thumbnail)
|
||||
.await?
|
||||
let reader = &mut BufReader::new(reader);
|
||||
|
||||
#[cfg(feature = "image_proc")]
|
||||
let mut cursor;
|
||||
|
||||
if config.thumbnail.is_some() {
|
||||
self.prepare_and_send_attachment(body, content_type, reader, config).await
|
||||
} else {
|
||||
self.client
|
||||
.prepare_attachment_message(body, content_type, reader, info, thumbnail)
|
||||
.await?
|
||||
};
|
||||
#[cfg(not(feature = "image_proc"))]
|
||||
let thumbnail = Thumbnail::NONE;
|
||||
|
||||
#[cfg(not(feature = "encryption"))]
|
||||
let content = self
|
||||
.client
|
||||
.prepare_attachment_message(body, content_type, reader, info, thumbnail)
|
||||
.await?;
|
||||
#[cfg(feature = "image_proc")]
|
||||
let thumbnail = if config.generate_thumbnail {
|
||||
match generate_image_thumbnail(content_type, reader, config.thumbnail_size) {
|
||||
Ok((thumbnail_data, thumbnail_info)) => {
|
||||
reader.rewind()?;
|
||||
|
||||
self.send(RoomMessageEventContent::new(content), txn_id).await
|
||||
cursor = Cursor::new(thumbnail_data);
|
||||
Some(Thumbnail {
|
||||
reader: &mut cursor,
|
||||
content_type: &mime::IMAGE_JPEG,
|
||||
info: Some(thumbnail_info),
|
||||
})
|
||||
}
|
||||
Err(error)
|
||||
if matches!(
|
||||
error,
|
||||
ImageError::ThumbnailBiggerThanOriginal
|
||||
| ImageError::FormatNotSupported
|
||||
) =>
|
||||
{
|
||||
reader.rewind()?;
|
||||
None
|
||||
}
|
||||
Err(error) => return Err(error.into()),
|
||||
}
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let config = AttachmentConfig {
|
||||
txn_id: config.txn_id,
|
||||
info: config.info,
|
||||
thumbnail,
|
||||
#[cfg(feature = "image_proc")]
|
||||
generate_thumbnail: false,
|
||||
#[cfg(feature = "image_proc")]
|
||||
thumbnail_size: None,
|
||||
};
|
||||
|
||||
self.prepare_and_send_attachment(body, content_type, reader, config).await
|
||||
}
|
||||
}
|
||||
|
||||
/// Send an attachment with a generated thumbnail to this room.
|
||||
/// Prepare and send an attachment to this room.
|
||||
///
|
||||
/// This will upload the given data that the reader produces using the
|
||||
/// [`upload()`](#method.upload) method and post an event to the given room.
|
||||
/// If the room is encrypted and the encryption feature is enabled the
|
||||
/// upload will be encrypted.
|
||||
///
|
||||
/// This is a convenience method that calls the
|
||||
/// [`attachment::generate_image_thumbnail()`] and afterwards the
|
||||
/// [`send_attachment()`](#method.send_attachment).
|
||||
///
|
||||
/// Thumbnails can only be generated for supported image attachments. For
|
||||
/// more information, see the [image](https://github.com/image-rs/image)
|
||||
/// crate.
|
||||
///
|
||||
/// If the thumbnail generation fails, this will return an
|
||||
/// [`ImageError`](../enum.ImageError.html).
|
||||
/// [`Client::upload()`](#Client::method.upload) and afterwards the
|
||||
/// [`send()`](#method.send).
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `body` - A textual representation of the media that is going to be
|
||||
@@ -695,66 +718,44 @@ impl Joined {
|
||||
/// * `reader` - A `Reader` that will be used to fetch the raw bytes of the
|
||||
/// media.
|
||||
///
|
||||
/// * `info` - The metadata of the media. If the
|
||||
/// `AttachmentInfo` type doesn't match the `content_type`, it is ignored.
|
||||
///
|
||||
/// * `thumbnail_size` - The size of the thumbnail in pixels as a
|
||||
/// `(width, height)` tuple. If set to `None`, defaults to `(800, 600)`.
|
||||
///
|
||||
/// * `txn_id` - A unique `Uuid` that can be attached to a `MessageEvent`
|
||||
/// held in its unsigned field as `transaction_id`. If not given one is
|
||||
/// created for the message.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// # use std::{path::PathBuf, fs::File, io::Read};
|
||||
/// # use matrix_sdk::{Client, ruma::room_id};
|
||||
/// # use url::Url;
|
||||
/// # use mime;
|
||||
/// # use futures::executor::block_on;
|
||||
/// # block_on(async {
|
||||
/// # let homeserver = Url::parse("http://localhost:8080")?;
|
||||
/// # let mut client = Client::new(homeserver)?;
|
||||
/// # let room_id = room_id!("!test:localhost");
|
||||
/// let path = PathBuf::from("/home/example/my-cat.jpg");
|
||||
/// let mut image = File::open(path)?;
|
||||
///
|
||||
/// if let Some(room) = client.get_joined_room(&room_id) {
|
||||
/// room.send_attachment_with_generated_thumbnail(
|
||||
/// "My favorite cat",
|
||||
/// &mime::IMAGE_JPEG,
|
||||
/// &mut image,
|
||||
/// None,
|
||||
/// None,
|
||||
/// None,
|
||||
/// ).await?;
|
||||
/// }
|
||||
/// # Result::<_, matrix_sdk::Error>::Ok(()) });
|
||||
/// ```
|
||||
/// [`attachment::generate_image_thumbnail()`]:
|
||||
/// ../attachment/fn.generate_image_thumbnail.html
|
||||
#[cfg(feature = "image_proc")]
|
||||
pub async fn send_attachment_with_generated_thumbnail<R: Read + Seek>(
|
||||
/// * `config` - Metadata and configuration for the attachment.
|
||||
async fn prepare_and_send_attachment<'a, R: Read, T: Read>(
|
||||
&self,
|
||||
body: &str,
|
||||
content_type: &Mime,
|
||||
reader: &mut R,
|
||||
info: Option<AttachmentInfo>,
|
||||
thumbnail_size: Option<(u32, u32)>,
|
||||
txn_id: Option<&TransactionId>,
|
||||
config: AttachmentConfig<'a, T>,
|
||||
) -> Result<send_message_event::Response> {
|
||||
let mut reader = BufReader::new(reader);
|
||||
|
||||
let (thumbnail_data, thumbnail_info) =
|
||||
generate_image_thumbnail(content_type, &mut reader, thumbnail_size)?;
|
||||
let thumbnail = Thumbnail {
|
||||
reader: &mut thumbnail_data.as_slice(),
|
||||
content_type: &mime::IMAGE_JPEG,
|
||||
info: Some(thumbnail_info),
|
||||
#[cfg(feature = "encryption")]
|
||||
let content = if self.is_encrypted() {
|
||||
self.client
|
||||
.prepare_encrypted_attachment_message(
|
||||
body,
|
||||
content_type,
|
||||
reader,
|
||||
config.info,
|
||||
config.thumbnail,
|
||||
)
|
||||
.await?
|
||||
} else {
|
||||
self.client
|
||||
.prepare_attachment_message(
|
||||
body,
|
||||
content_type,
|
||||
reader,
|
||||
config.info,
|
||||
config.thumbnail,
|
||||
)
|
||||
.await?
|
||||
};
|
||||
reader.rewind()?;
|
||||
self.send_attachment(body, content_type, &mut reader, info, Some(thumbnail), txn_id).await
|
||||
|
||||
#[cfg(not(feature = "encryption"))]
|
||||
let content = self
|
||||
.client
|
||||
.prepare_attachment_message(body, content_type, reader, config.info, config.thumbnail)
|
||||
.await?;
|
||||
|
||||
self.send(RoomMessageEventContent::new(content), config.txn_id).await
|
||||
}
|
||||
|
||||
/// Send a room state event to the homeserver.
|
||||
|
||||
Reference in New Issue
Block a user