1use std::{fmt, sync::Arc};
16
17use async_trait::async_trait;
18use matrix_sdk_common::{
19 AsyncTraitDeps,
20 linked_chunk::{
21 ChunkIdentifier, ChunkIdentifierGenerator, ChunkMetadata, LinkedChunkId, Position,
22 RawChunk, Update,
23 },
24};
25use ruma::{EventId, MxcUri, OwnedEventId, RoomId, events::relation::RelationType};
26
27use super::{
28 EventCacheStoreError,
29 media::{IgnoreMediaRetentionPolicy, MediaRetentionPolicy},
30};
31use crate::{
32 event_cache::{Event, Gap},
33 media::MediaRequestParameters,
34};
35
36pub const DEFAULT_CHUNK_CAPACITY: usize = 128;
40
41#[cfg_attr(target_family = "wasm", async_trait(?Send))]
44#[cfg_attr(not(target_family = "wasm"), async_trait)]
45pub trait EventCacheStore: AsyncTraitDeps {
46 type Error: fmt::Debug + Into<EventCacheStoreError>;
48
49 async fn try_take_leased_lock(
51 &self,
52 lease_duration_ms: u32,
53 key: &str,
54 holder: &str,
55 ) -> Result<bool, Self::Error>;
56
57 async fn handle_linked_chunk_updates(
61 &self,
62 linked_chunk_id: LinkedChunkId<'_>,
63 updates: Vec<Update<Event, Gap>>,
64 ) -> Result<(), Self::Error>;
65
66 async fn remove_room(&self, room_id: &RoomId) -> Result<(), Self::Error> {
68 self.handle_linked_chunk_updates(LinkedChunkId::Room(room_id), vec![Update::Clear]).await
71 }
72
73 #[doc(hidden)]
76 async fn load_all_chunks(
77 &self,
78 linked_chunk_id: LinkedChunkId<'_>,
79 ) -> Result<Vec<RawChunk<Event, Gap>>, Self::Error>;
80
81 async fn load_all_chunks_metadata(
86 &self,
87 linked_chunk_id: LinkedChunkId<'_>,
88 ) -> Result<Vec<ChunkMetadata>, Self::Error>;
89
90 async fn load_last_chunk(
95 &self,
96 linked_chunk_id: LinkedChunkId<'_>,
97 ) -> Result<(Option<RawChunk<Event, Gap>>, ChunkIdentifierGenerator), Self::Error>;
98
99 async fn load_previous_chunk(
105 &self,
106 linked_chunk_id: LinkedChunkId<'_>,
107 before_chunk_identifier: ChunkIdentifier,
108 ) -> Result<Option<RawChunk<Event, Gap>>, Self::Error>;
109
110 async fn clear_all_linked_chunks(&self) -> Result<(), Self::Error>;
121
122 async fn filter_duplicated_events(
125 &self,
126 linked_chunk_id: LinkedChunkId<'_>,
127 events: Vec<OwnedEventId>,
128 ) -> Result<Vec<(OwnedEventId, Position)>, Self::Error>;
129
130 async fn find_event(
135 &self,
136 room_id: &RoomId,
137 event_id: &EventId,
138 ) -> Result<Option<Event>, Self::Error>;
139
140 async fn find_event_relations(
157 &self,
158 room_id: &RoomId,
159 event_id: &EventId,
160 filter: Option<&[RelationType]>,
161 ) -> Result<Vec<(Event, Option<Position>)>, Self::Error>;
162
163 async fn save_event(&self, room_id: &RoomId, event: Event) -> Result<(), Self::Error>;
172
173 async fn add_media_content(
181 &self,
182 request: &MediaRequestParameters,
183 content: Vec<u8>,
184 ignore_policy: IgnoreMediaRetentionPolicy,
185 ) -> Result<(), Self::Error>;
186
187 async fn replace_media_key(
207 &self,
208 from: &MediaRequestParameters,
209 to: &MediaRequestParameters,
210 ) -> Result<(), Self::Error>;
211
212 async fn get_media_content(
218 &self,
219 request: &MediaRequestParameters,
220 ) -> Result<Option<Vec<u8>>, Self::Error>;
221
222 async fn remove_media_content(
228 &self,
229 request: &MediaRequestParameters,
230 ) -> Result<(), Self::Error>;
231
232 async fn get_media_content_for_uri(&self, uri: &MxcUri)
247 -> Result<Option<Vec<u8>>, Self::Error>;
248
249 async fn remove_media_content_for_uri(&self, uri: &MxcUri) -> Result<(), Self::Error>;
259
260 async fn set_media_retention_policy(
267 &self,
268 policy: MediaRetentionPolicy,
269 ) -> Result<(), Self::Error>;
270
271 fn media_retention_policy(&self) -> MediaRetentionPolicy;
273
274 async fn set_ignore_media_retention_policy(
286 &self,
287 request: &MediaRequestParameters,
288 ignore_policy: IgnoreMediaRetentionPolicy,
289 ) -> Result<(), Self::Error>;
290
291 async fn clean_up_media_cache(&self) -> Result<(), Self::Error>;
295}
296
297#[repr(transparent)]
298struct EraseEventCacheStoreError<T>(T);
299
300#[cfg(not(tarpaulin_include))]
301impl<T: fmt::Debug> fmt::Debug for EraseEventCacheStoreError<T> {
302 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
303 self.0.fmt(f)
304 }
305}
306
307#[cfg_attr(target_family = "wasm", async_trait(?Send))]
308#[cfg_attr(not(target_family = "wasm"), async_trait)]
309impl<T: EventCacheStore> EventCacheStore for EraseEventCacheStoreError<T> {
310 type Error = EventCacheStoreError;
311
312 async fn try_take_leased_lock(
313 &self,
314 lease_duration_ms: u32,
315 key: &str,
316 holder: &str,
317 ) -> Result<bool, Self::Error> {
318 self.0.try_take_leased_lock(lease_duration_ms, key, holder).await.map_err(Into::into)
319 }
320
321 async fn handle_linked_chunk_updates(
322 &self,
323 linked_chunk_id: LinkedChunkId<'_>,
324 updates: Vec<Update<Event, Gap>>,
325 ) -> Result<(), Self::Error> {
326 self.0.handle_linked_chunk_updates(linked_chunk_id, updates).await.map_err(Into::into)
327 }
328
329 async fn load_all_chunks(
330 &self,
331 linked_chunk_id: LinkedChunkId<'_>,
332 ) -> Result<Vec<RawChunk<Event, Gap>>, Self::Error> {
333 self.0.load_all_chunks(linked_chunk_id).await.map_err(Into::into)
334 }
335
336 async fn load_all_chunks_metadata(
337 &self,
338 linked_chunk_id: LinkedChunkId<'_>,
339 ) -> Result<Vec<ChunkMetadata>, Self::Error> {
340 self.0.load_all_chunks_metadata(linked_chunk_id).await.map_err(Into::into)
341 }
342
343 async fn load_last_chunk(
344 &self,
345 linked_chunk_id: LinkedChunkId<'_>,
346 ) -> Result<(Option<RawChunk<Event, Gap>>, ChunkIdentifierGenerator), Self::Error> {
347 self.0.load_last_chunk(linked_chunk_id).await.map_err(Into::into)
348 }
349
350 async fn load_previous_chunk(
351 &self,
352 linked_chunk_id: LinkedChunkId<'_>,
353 before_chunk_identifier: ChunkIdentifier,
354 ) -> Result<Option<RawChunk<Event, Gap>>, Self::Error> {
355 self.0
356 .load_previous_chunk(linked_chunk_id, before_chunk_identifier)
357 .await
358 .map_err(Into::into)
359 }
360
361 async fn clear_all_linked_chunks(&self) -> Result<(), Self::Error> {
362 self.0.clear_all_linked_chunks().await.map_err(Into::into)
363 }
364
365 async fn filter_duplicated_events(
366 &self,
367 linked_chunk_id: LinkedChunkId<'_>,
368 events: Vec<OwnedEventId>,
369 ) -> Result<Vec<(OwnedEventId, Position)>, Self::Error> {
370 self.0.filter_duplicated_events(linked_chunk_id, events).await.map_err(Into::into)
371 }
372
373 async fn find_event(
374 &self,
375 room_id: &RoomId,
376 event_id: &EventId,
377 ) -> Result<Option<Event>, Self::Error> {
378 self.0.find_event(room_id, event_id).await.map_err(Into::into)
379 }
380
381 async fn find_event_relations(
382 &self,
383 room_id: &RoomId,
384 event_id: &EventId,
385 filter: Option<&[RelationType]>,
386 ) -> Result<Vec<(Event, Option<Position>)>, Self::Error> {
387 self.0.find_event_relations(room_id, event_id, filter).await.map_err(Into::into)
388 }
389
390 async fn save_event(&self, room_id: &RoomId, event: Event) -> Result<(), Self::Error> {
391 self.0.save_event(room_id, event).await.map_err(Into::into)
392 }
393
394 async fn add_media_content(
395 &self,
396 request: &MediaRequestParameters,
397 content: Vec<u8>,
398 ignore_policy: IgnoreMediaRetentionPolicy,
399 ) -> Result<(), Self::Error> {
400 self.0.add_media_content(request, content, ignore_policy).await.map_err(Into::into)
401 }
402
403 async fn replace_media_key(
404 &self,
405 from: &MediaRequestParameters,
406 to: &MediaRequestParameters,
407 ) -> Result<(), Self::Error> {
408 self.0.replace_media_key(from, to).await.map_err(Into::into)
409 }
410
411 async fn get_media_content(
412 &self,
413 request: &MediaRequestParameters,
414 ) -> Result<Option<Vec<u8>>, Self::Error> {
415 self.0.get_media_content(request).await.map_err(Into::into)
416 }
417
418 async fn remove_media_content(
419 &self,
420 request: &MediaRequestParameters,
421 ) -> Result<(), Self::Error> {
422 self.0.remove_media_content(request).await.map_err(Into::into)
423 }
424
425 async fn get_media_content_for_uri(
426 &self,
427 uri: &MxcUri,
428 ) -> Result<Option<Vec<u8>>, Self::Error> {
429 self.0.get_media_content_for_uri(uri).await.map_err(Into::into)
430 }
431
432 async fn remove_media_content_for_uri(&self, uri: &MxcUri) -> Result<(), Self::Error> {
433 self.0.remove_media_content_for_uri(uri).await.map_err(Into::into)
434 }
435
436 async fn set_media_retention_policy(
437 &self,
438 policy: MediaRetentionPolicy,
439 ) -> Result<(), Self::Error> {
440 self.0.set_media_retention_policy(policy).await.map_err(Into::into)
441 }
442
443 fn media_retention_policy(&self) -> MediaRetentionPolicy {
444 self.0.media_retention_policy()
445 }
446
447 async fn set_ignore_media_retention_policy(
448 &self,
449 request: &MediaRequestParameters,
450 ignore_policy: IgnoreMediaRetentionPolicy,
451 ) -> Result<(), Self::Error> {
452 self.0.set_ignore_media_retention_policy(request, ignore_policy).await.map_err(Into::into)
453 }
454
455 async fn clean_up_media_cache(&self) -> Result<(), Self::Error> {
456 self.0.clean_up_media_cache().await.map_err(Into::into)
457 }
458}
459
460pub type DynEventCacheStore = dyn EventCacheStore<Error = EventCacheStoreError>;
462
463pub trait IntoEventCacheStore {
469 #[doc(hidden)]
470 fn into_event_cache_store(self) -> Arc<DynEventCacheStore>;
471}
472
473impl IntoEventCacheStore for Arc<DynEventCacheStore> {
474 fn into_event_cache_store(self) -> Arc<DynEventCacheStore> {
475 self
476 }
477}
478
479impl<T> IntoEventCacheStore for T
480where
481 T: EventCacheStore + Sized + 'static,
482{
483 fn into_event_cache_store(self) -> Arc<DynEventCacheStore> {
484 Arc::new(EraseEventCacheStoreError(self))
485 }
486}
487
488impl<T> IntoEventCacheStore for Arc<T>
491where
492 T: EventCacheStore + 'static,
493{
494 fn into_event_cache_store(self) -> Arc<DynEventCacheStore> {
495 let ptr: *const T = Arc::into_raw(self);
496 let ptr_erased = ptr as *const EraseEventCacheStoreError<T>;
497 unsafe { Arc::from_raw(ptr_erased) }
500 }
501}