use std::{fmt, sync::Arc};
use async_trait::async_trait;
use matrix_sdk_common::{AsyncTraitDeps, cross_process_lock::CrossProcessLockGeneration};
use ruma::{MxcUri, time::SystemTime};
#[cfg(doc)]
use crate::media::store::MediaService;
use crate::media::{
MediaRequestParameters,
store::{IgnoreMediaRetentionPolicy, MediaRetentionPolicy, MediaStoreError},
};
#[cfg_attr(target_family = "wasm", async_trait(?Send))]
#[cfg_attr(not(target_family = "wasm"), async_trait)]
pub trait MediaStore: AsyncTraitDeps {
type Error: fmt::Debug + Into<MediaStoreError>;
async fn try_take_leased_lock(
&self,
lease_duration_ms: u32,
key: &str,
holder: &str,
) -> Result<Option<CrossProcessLockGeneration>, Self::Error>;
async fn add_media_content(
&self,
request: &MediaRequestParameters,
content: Vec<u8>,
ignore_policy: IgnoreMediaRetentionPolicy,
) -> Result<(), Self::Error>;
async fn replace_media_key(
&self,
from: &MediaRequestParameters,
to: &MediaRequestParameters,
) -> Result<(), Self::Error>;
async fn get_media_content(
&self,
request: &MediaRequestParameters,
) -> Result<Option<Vec<u8>>, Self::Error>;
async fn remove_media_content(
&self,
request: &MediaRequestParameters,
) -> Result<(), Self::Error>;
async fn get_media_content_for_uri(&self, uri: &MxcUri)
-> Result<Option<Vec<u8>>, Self::Error>;
async fn remove_media_content_for_uri(&self, uri: &MxcUri) -> Result<(), Self::Error>;
async fn set_media_retention_policy(
&self,
policy: MediaRetentionPolicy,
) -> Result<(), Self::Error>;
fn media_retention_policy(&self) -> MediaRetentionPolicy;
async fn set_ignore_media_retention_policy(
&self,
request: &MediaRequestParameters,
ignore_policy: IgnoreMediaRetentionPolicy,
) -> Result<(), Self::Error>;
async fn clean(&self) -> Result<(), Self::Error>;
#[doc(hidden)]
async fn optimize(&self) -> Result<(), Self::Error>;
async fn get_size(&self) -> Result<Option<usize>, Self::Error>;
}
#[cfg_attr(target_family = "wasm", async_trait(?Send))]
#[cfg_attr(not(target_family = "wasm"), async_trait)]
pub trait MediaStoreInner: AsyncTraitDeps + Clone {
type Error: fmt::Debug + fmt::Display + Into<MediaStoreError>;
async fn media_retention_policy_inner(
&self,
) -> Result<Option<MediaRetentionPolicy>, Self::Error>;
async fn set_media_retention_policy_inner(
&self,
policy: MediaRetentionPolicy,
) -> Result<(), Self::Error>;
async fn add_media_content_inner(
&self,
request: &MediaRequestParameters,
content: Vec<u8>,
current_time: SystemTime,
policy: MediaRetentionPolicy,
ignore_policy: IgnoreMediaRetentionPolicy,
) -> Result<(), Self::Error>;
async fn set_ignore_media_retention_policy_inner(
&self,
request: &MediaRequestParameters,
ignore_policy: IgnoreMediaRetentionPolicy,
) -> Result<(), Self::Error>;
async fn get_media_content_inner(
&self,
request: &MediaRequestParameters,
current_time: SystemTime,
) -> Result<Option<Vec<u8>>, Self::Error>;
async fn get_media_content_for_uri_inner(
&self,
uri: &MxcUri,
current_time: SystemTime,
) -> Result<Option<Vec<u8>>, Self::Error>;
async fn clean_inner(
&self,
policy: MediaRetentionPolicy,
current_time: SystemTime,
) -> Result<(), Self::Error>;
async fn last_media_cleanup_time_inner(&self) -> Result<Option<SystemTime>, Self::Error>;
}
#[repr(transparent)]
struct EraseMediaStoreError<T>(T);
#[cfg(not(tarpaulin_include))]
impl<T: fmt::Debug> fmt::Debug for EraseMediaStoreError<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.fmt(f)
}
}
#[cfg_attr(target_family = "wasm", async_trait(?Send))]
#[cfg_attr(not(target_family = "wasm"), async_trait)]
impl<T: MediaStore> MediaStore for EraseMediaStoreError<T> {
type Error = MediaStoreError;
async fn try_take_leased_lock(
&self,
lease_duration_ms: u32,
key: &str,
holder: &str,
) -> Result<Option<CrossProcessLockGeneration>, Self::Error> {
self.0.try_take_leased_lock(lease_duration_ms, key, holder).await.map_err(Into::into)
}
async fn add_media_content(
&self,
request: &MediaRequestParameters,
content: Vec<u8>,
ignore_policy: IgnoreMediaRetentionPolicy,
) -> Result<(), Self::Error> {
self.0.add_media_content(request, content, ignore_policy).await.map_err(Into::into)
}
async fn replace_media_key(
&self,
from: &MediaRequestParameters,
to: &MediaRequestParameters,
) -> Result<(), Self::Error> {
self.0.replace_media_key(from, to).await.map_err(Into::into)
}
async fn get_media_content(
&self,
request: &MediaRequestParameters,
) -> Result<Option<Vec<u8>>, Self::Error> {
self.0.get_media_content(request).await.map_err(Into::into)
}
async fn remove_media_content(
&self,
request: &MediaRequestParameters,
) -> Result<(), Self::Error> {
self.0.remove_media_content(request).await.map_err(Into::into)
}
async fn get_media_content_for_uri(
&self,
uri: &MxcUri,
) -> Result<Option<Vec<u8>>, Self::Error> {
self.0.get_media_content_for_uri(uri).await.map_err(Into::into)
}
async fn remove_media_content_for_uri(&self, uri: &MxcUri) -> Result<(), Self::Error> {
self.0.remove_media_content_for_uri(uri).await.map_err(Into::into)
}
async fn set_media_retention_policy(
&self,
policy: MediaRetentionPolicy,
) -> Result<(), Self::Error> {
self.0.set_media_retention_policy(policy).await.map_err(Into::into)
}
fn media_retention_policy(&self) -> MediaRetentionPolicy {
self.0.media_retention_policy()
}
async fn set_ignore_media_retention_policy(
&self,
request: &MediaRequestParameters,
ignore_policy: IgnoreMediaRetentionPolicy,
) -> Result<(), Self::Error> {
self.0.set_ignore_media_retention_policy(request, ignore_policy).await.map_err(Into::into)
}
async fn clean(&self) -> Result<(), Self::Error> {
self.0.clean().await.map_err(Into::into)
}
async fn optimize(&self) -> Result<(), Self::Error> {
self.0.optimize().await.map_err(Into::into)
}
async fn get_size(&self) -> Result<Option<usize>, Self::Error> {
self.0.get_size().await.map_err(Into::into)
}
}
pub type DynMediaStore = dyn MediaStore<Error = MediaStoreError>;
pub trait IntoMediaStore {
#[doc(hidden)]
fn into_media_store(self) -> Arc<DynMediaStore>;
}
impl IntoMediaStore for Arc<DynMediaStore> {
fn into_media_store(self) -> Arc<DynMediaStore> {
self
}
}
impl<T> IntoMediaStore for T
where
T: MediaStore + Sized + 'static,
{
fn into_media_store(self) -> Arc<DynMediaStore> {
Arc::new(EraseMediaStoreError(self))
}
}
impl<T> IntoMediaStore for Arc<T>
where
T: MediaStore + 'static,
{
fn into_media_store(self) -> Arc<DynMediaStore> {
let ptr: *const T = Arc::into_raw(self);
let ptr_erased = ptr as *const EraseMediaStoreError<T>;
unsafe { Arc::from_raw(ptr_erased) }
}
}