Add MediaEventContent trait and implement it for corresponding room events
Add helper methods in Clientmaster
parent
b805670c8a
commit
df883d3328
|
@ -45,7 +45,7 @@ use matrix_sdk_base::{
|
||||||
deserialized_responses::SyncResponse,
|
deserialized_responses::SyncResponse,
|
||||||
events::AnyMessageEventContent,
|
events::AnyMessageEventContent,
|
||||||
identifiers::MxcUri,
|
identifiers::MxcUri,
|
||||||
media::{MediaFormat, MediaRequest, MediaType},
|
media::{MediaEventContent, MediaFormat, MediaRequest, MediaThumbnailSize, MediaType},
|
||||||
BaseClient, BaseClientConfig, SendAccessToken, Session, Store,
|
BaseClient, BaseClientConfig, SendAccessToken, Session, Store,
|
||||||
};
|
};
|
||||||
use mime::{self, Mime};
|
use mime::{self, Mime};
|
||||||
|
@ -2503,7 +2503,7 @@ impl Client {
|
||||||
let content = {
|
let content = {
|
||||||
let mut cursor = Cursor::new(content);
|
let mut cursor = Cursor::new(content);
|
||||||
let mut reader =
|
let mut reader =
|
||||||
AttachmentDecryptor::new(&mut cursor, file.clone().into())?;
|
AttachmentDecryptor::new(&mut cursor, file.as_ref().clone().into())?;
|
||||||
|
|
||||||
let mut decrypted = Vec::new();
|
let mut decrypted = Vec::new();
|
||||||
reader.read_to_end(&mut decrypted)?;
|
reader.read_to_end(&mut decrypted)?;
|
||||||
|
@ -2557,6 +2557,120 @@ impl Client {
|
||||||
pub async fn remove_media_content_for_uri(&self, uri: &MxcUri) -> Result<()> {
|
pub async fn remove_media_content_for_uri(&self, uri: &MxcUri) -> Result<()> {
|
||||||
Ok(self.base_client.store().remove_media_content_for_uri(&uri).await?)
|
Ok(self.base_client.store().remove_media_content_for_uri(&uri).await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the file of the given media event content.
|
||||||
|
///
|
||||||
|
/// If the content is encrypted and encryption is enabled, the content will
|
||||||
|
/// be decrypted.
|
||||||
|
///
|
||||||
|
/// Returns `Ok(None)` if the event content has no file.
|
||||||
|
///
|
||||||
|
/// This is a convenience method that calls the
|
||||||
|
/// [`get_media_content`](#method.get_media_content) method.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `event_content` - The media event content.
|
||||||
|
///
|
||||||
|
/// * `use_cache` - If we should use the media cache for this file.
|
||||||
|
pub async fn get_file(
|
||||||
|
&self,
|
||||||
|
event_content: impl MediaEventContent,
|
||||||
|
use_cache: bool,
|
||||||
|
) -> Result<Option<Vec<u8>>> {
|
||||||
|
if let Some(media_type) = event_content.file() {
|
||||||
|
Ok(Some(
|
||||||
|
self.get_media_content(
|
||||||
|
&MediaRequest { media_type, format: MediaFormat::File },
|
||||||
|
use_cache,
|
||||||
|
)
|
||||||
|
.await?,
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove the file of the given media event content from the cache.
|
||||||
|
///
|
||||||
|
/// This is a convenience method that calls the
|
||||||
|
/// [`remove_media_content`](#method.remove_media_content) method.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `event_content` - The media event content.
|
||||||
|
pub async fn remove_file(&self, event_content: impl MediaEventContent) -> Result<()> {
|
||||||
|
if let Some(media_type) = event_content.file() {
|
||||||
|
self.remove_media_content(&MediaRequest { media_type, format: MediaFormat::File })
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get a thumbnail of the given media event content.
|
||||||
|
///
|
||||||
|
/// If the content is encrypted and encryption is enabled, the content will
|
||||||
|
/// be decrypted.
|
||||||
|
///
|
||||||
|
/// Returns `Ok(None)` if the event content has no thumbnail.
|
||||||
|
///
|
||||||
|
/// This is a convenience method that calls the
|
||||||
|
/// [`get_media_content`](#method.get_media_content) method.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `event_content` - The media event content.
|
||||||
|
///
|
||||||
|
/// * `size` - The _desired_ size of the thumbnail. The actual thumbnail may
|
||||||
|
/// not match the size specified.
|
||||||
|
///
|
||||||
|
/// * `use_cache` - If we should use the media cache for this thumbnail.
|
||||||
|
pub async fn get_thumbnail(
|
||||||
|
&self,
|
||||||
|
event_content: impl MediaEventContent,
|
||||||
|
size: MediaThumbnailSize,
|
||||||
|
use_cache: bool,
|
||||||
|
) -> Result<Option<Vec<u8>>> {
|
||||||
|
if let Some(media_type) = event_content.thumbnail() {
|
||||||
|
Ok(Some(
|
||||||
|
self.get_media_content(
|
||||||
|
&MediaRequest { media_type, format: MediaFormat::Thumbnail(size) },
|
||||||
|
use_cache,
|
||||||
|
)
|
||||||
|
.await?,
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove the thumbnail of the given media event content from the cache.
|
||||||
|
///
|
||||||
|
/// This is a convenience method that calls the
|
||||||
|
/// [`remove_media_content`](#method.remove_media_content) method.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `event_content` - The media event content.
|
||||||
|
///
|
||||||
|
/// * `size` - The _desired_ size of the thumbnail. Must match the size
|
||||||
|
/// requested with [`get_thumbnail`](#method.get_thumbnail).
|
||||||
|
pub async fn remove_thumbnail(
|
||||||
|
&self,
|
||||||
|
event_content: impl MediaEventContent,
|
||||||
|
size: MediaThumbnailSize,
|
||||||
|
) -> Result<()> {
|
||||||
|
if let Some(media_type) = event_content.file() {
|
||||||
|
self.remove_media_content(&MediaRequest {
|
||||||
|
media_type,
|
||||||
|
format: MediaFormat::Thumbnail(size),
|
||||||
|
})
|
||||||
|
.await?
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -1,8 +1,19 @@
|
||||||
//! Common types for [media content](https://matrix.org/docs/spec/client_server/r0.6.1#id66).
|
//! Common types for [media content](https://matrix.org/docs/spec/client_server/r0.6.1#id66).
|
||||||
|
|
||||||
use matrix_sdk_common::{
|
use matrix_sdk_common::{
|
||||||
api::r0::media::get_content_thumbnail::Method, events::room::EncryptedFile,
|
api::r0::media::get_content_thumbnail::Method,
|
||||||
identifiers::MxcUri, UInt,
|
events::{
|
||||||
|
room::{
|
||||||
|
message::{
|
||||||
|
AudioMessageEventContent, FileMessageEventContent, ImageMessageEventContent,
|
||||||
|
LocationMessageEventContent, VideoMessageEventContent,
|
||||||
|
},
|
||||||
|
EncryptedFile,
|
||||||
|
},
|
||||||
|
sticker::StickerEventContent,
|
||||||
|
},
|
||||||
|
identifiers::MxcUri,
|
||||||
|
UInt,
|
||||||
};
|
};
|
||||||
|
|
||||||
const UNIQUE_SEPARATOR: &str = "_";
|
const UNIQUE_SEPARATOR: &str = "_";
|
||||||
|
@ -61,7 +72,7 @@ pub enum MediaType {
|
||||||
Uri(MxcUri),
|
Uri(MxcUri),
|
||||||
|
|
||||||
/// An encrypted media content.
|
/// An encrypted media content.
|
||||||
Encrypted(EncryptedFile),
|
Encrypted(Box<EncryptedFile>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl UniqueKey for MediaType {
|
impl UniqueKey for MediaType {
|
||||||
|
@ -88,3 +99,118 @@ impl UniqueKey for MediaRequest {
|
||||||
format!("{}{}{}", self.media_type.unique_key(), UNIQUE_SEPARATOR, self.format.unique_key())
|
format!("{}{}{}", self.media_type.unique_key(), UNIQUE_SEPARATOR, self.format.unique_key())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Trait for media event content.
|
||||||
|
pub trait MediaEventContent {
|
||||||
|
/// Get the type of the file for `Self`.
|
||||||
|
///
|
||||||
|
/// Returns `None` if `Self` has no file.
|
||||||
|
fn file(&self) -> Option<MediaType>;
|
||||||
|
|
||||||
|
/// Get the type of the thumbnail for `Self`.
|
||||||
|
///
|
||||||
|
/// Returns `None` if `Self` has no thumbnail.
|
||||||
|
fn thumbnail(&self) -> Option<MediaType>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MediaEventContent for StickerEventContent {
|
||||||
|
fn file(&self) -> Option<MediaType> {
|
||||||
|
Some(MediaType::Uri(self.url.clone()))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn thumbnail(&self) -> Option<MediaType> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MediaEventContent for AudioMessageEventContent {
|
||||||
|
fn file(&self) -> Option<MediaType> {
|
||||||
|
self.url
|
||||||
|
.as_ref()
|
||||||
|
.map(|uri| MediaType::Uri(uri.clone()))
|
||||||
|
.or_else(|| self.file.as_ref().map(|e| MediaType::Encrypted(e.clone())))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn thumbnail(&self) -> Option<MediaType> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MediaEventContent for FileMessageEventContent {
|
||||||
|
fn file(&self) -> Option<MediaType> {
|
||||||
|
self.url
|
||||||
|
.as_ref()
|
||||||
|
.map(|uri| MediaType::Uri(uri.clone()))
|
||||||
|
.or_else(|| self.file.as_ref().map(|e| MediaType::Encrypted(e.clone())))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn thumbnail(&self) -> Option<MediaType> {
|
||||||
|
self.info.as_ref().and_then(|info| {
|
||||||
|
if let Some(uri) = info.thumbnail_url.as_ref() {
|
||||||
|
Some(MediaType::Uri(uri.clone()))
|
||||||
|
} else {
|
||||||
|
info.thumbnail_file.as_ref().map(|file| MediaType::Encrypted(file.clone()))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MediaEventContent for ImageMessageEventContent {
|
||||||
|
fn file(&self) -> Option<MediaType> {
|
||||||
|
self.url
|
||||||
|
.as_ref()
|
||||||
|
.map(|uri| MediaType::Uri(uri.clone()))
|
||||||
|
.or_else(|| self.file.as_ref().map(|e| MediaType::Encrypted(e.clone())))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn thumbnail(&self) -> Option<MediaType> {
|
||||||
|
self.info
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|info| {
|
||||||
|
if let Some(uri) = info.thumbnail_url.as_ref() {
|
||||||
|
Some(MediaType::Uri(uri.clone()))
|
||||||
|
} else {
|
||||||
|
info.thumbnail_file.as_ref().map(|file| MediaType::Encrypted(file.clone()))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.or_else(|| self.url.as_ref().map(|uri| MediaType::Uri(uri.clone())))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MediaEventContent for VideoMessageEventContent {
|
||||||
|
fn file(&self) -> Option<MediaType> {
|
||||||
|
self.url
|
||||||
|
.as_ref()
|
||||||
|
.map(|uri| MediaType::Uri(uri.clone()))
|
||||||
|
.or_else(|| self.file.as_ref().map(|e| MediaType::Encrypted(e.clone())))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn thumbnail(&self) -> Option<MediaType> {
|
||||||
|
self.info
|
||||||
|
.as_ref()
|
||||||
|
.and_then(|info| {
|
||||||
|
if let Some(uri) = info.thumbnail_url.as_ref() {
|
||||||
|
Some(MediaType::Uri(uri.clone()))
|
||||||
|
} else {
|
||||||
|
info.thumbnail_file.as_ref().map(|file| MediaType::Encrypted(file.clone()))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.or_else(|| self.url.as_ref().map(|uri| MediaType::Uri(uri.clone())))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MediaEventContent for LocationMessageEventContent {
|
||||||
|
fn file(&self) -> Option<MediaType> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn thumbnail(&self) -> Option<MediaType> {
|
||||||
|
self.info.as_ref().and_then(|info| {
|
||||||
|
if let Some(uri) = info.thumbnail_url.as_ref() {
|
||||||
|
Some(MediaType::Uri(uri.clone()))
|
||||||
|
} else {
|
||||||
|
info.thumbnail_file.as_ref().map(|file| MediaType::Encrypted(file.clone()))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue