mirror of
https://github.com/matrix-org/matrix-rust-sdk.git
synced 2026-05-14 11:05:32 -04:00
feat(sdk): Remove EventCacheStore, TimelineEntry, RoomInfo and MemoryStore.
This commit is contained in:
@@ -70,7 +70,7 @@ use tracing::{error, instrument, trace, warn};
|
||||
|
||||
use self::{
|
||||
linked_chunk::ChunkContent,
|
||||
store::{EventCacheStore, Gap, MemoryStore, PaginationToken, RoomEvents, TimelineEntry},
|
||||
store::{Gap, PaginationToken, RoomEvents},
|
||||
};
|
||||
use crate::{client::ClientInner, room::MessagesOptions, Client, Room};
|
||||
|
||||
@@ -767,7 +767,7 @@ mod tests {
|
||||
use matrix_sdk_test::{async_test, sync_timeline_event};
|
||||
use ruma::room_id;
|
||||
|
||||
use super::{store::TimelineEntry, EventCacheError};
|
||||
use super::EventCacheError;
|
||||
use crate::{event_cache::store::PaginationToken, test_utils::logged_in_client};
|
||||
|
||||
#[async_test]
|
||||
|
||||
@@ -12,199 +12,19 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::{collections::BTreeMap, fmt, iter::once, result::Result as StdResult};
|
||||
use std::{fmt, iter::once, result::Result};
|
||||
|
||||
use async_trait::async_trait;
|
||||
use matrix_sdk_common::deserialized_responses::SyncTimelineEvent;
|
||||
use ruma::{OwnedRoomId, RoomId};
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
use super::{
|
||||
linked_chunk::{
|
||||
Chunk, ChunkIdentifier, LinkedChunk, LinkedChunkError, LinkedChunkIter,
|
||||
LinkedChunkIterBackward, Position,
|
||||
},
|
||||
Result,
|
||||
use super::linked_chunk::{
|
||||
Chunk, ChunkIdentifier, LinkedChunk, LinkedChunkError, LinkedChunkIter,
|
||||
LinkedChunkIterBackward, Position,
|
||||
};
|
||||
|
||||
/// A store that can be remember information about the event cache.
|
||||
///
|
||||
/// It really acts as a cache, in the sense that clearing the backing data
|
||||
/// should not have any irremediable effect, other than providing a lesser user
|
||||
/// experience.
|
||||
#[async_trait]
|
||||
pub trait EventCacheStore: Send + Sync {
|
||||
/// Returns all the known events for the given room.
|
||||
async fn room_events(&self, room: &RoomId) -> Result<Vec<SyncTimelineEvent>>;
|
||||
|
||||
/// Adds all the entries to the given room's timeline.
|
||||
async fn append_room_entries(&self, room: &RoomId, entries: Vec<TimelineEntry>) -> Result<()>;
|
||||
|
||||
/// Returns whether the store knows about the given pagination token.
|
||||
async fn contains_gap(&self, room: &RoomId, pagination_token: &PaginationToken)
|
||||
-> Result<bool>;
|
||||
|
||||
/// Replaces a given gap (identified by its pagination token) with the given
|
||||
/// entries.
|
||||
///
|
||||
/// Note: if the gap hasn't been found, then nothing happens, and the events
|
||||
/// are lost.
|
||||
///
|
||||
/// Returns whether the gap was found.
|
||||
async fn replace_gap(
|
||||
&self,
|
||||
room: &RoomId,
|
||||
gap_id: Option<&PaginationToken>,
|
||||
entries: Vec<TimelineEntry>,
|
||||
) -> Result<bool>;
|
||||
|
||||
/// Retrieve the oldest backpagination token for the given room.
|
||||
async fn oldest_backpagination_token(&self, room: &RoomId) -> Result<Option<PaginationToken>>;
|
||||
|
||||
/// Clear all the information tied to a given room.
|
||||
///
|
||||
/// This forgets the following:
|
||||
/// - events in the room
|
||||
/// - pagination tokens
|
||||
async fn clear_room(&self, room: &RoomId) -> Result<()>;
|
||||
}
|
||||
|
||||
/// A newtype wrapper for a pagination token returned by a /messages response.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct PaginationToken(pub String);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum TimelineEntry {
|
||||
Event(SyncTimelineEvent),
|
||||
|
||||
Gap {
|
||||
/// The token to use in the query, extracted from a previous "from" /
|
||||
/// "end" field of a `/messages` response.
|
||||
prev_token: PaginationToken,
|
||||
},
|
||||
}
|
||||
|
||||
/// All the information related to a room and stored in the event cache.
|
||||
#[derive(Default)]
|
||||
struct RoomInfo {
|
||||
/// All the timeline entries per room, in sync order.
|
||||
entries: Vec<TimelineEntry>,
|
||||
}
|
||||
|
||||
impl RoomInfo {
|
||||
fn clear(&mut self) {
|
||||
self.entries.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/// An [`EventCacheStore`] implementation that keeps all the information in
|
||||
/// memory.
|
||||
#[derive(Default)]
|
||||
pub(crate) struct MemoryStore {
|
||||
by_room: RwLock<BTreeMap<OwnedRoomId, RoomInfo>>,
|
||||
}
|
||||
|
||||
impl MemoryStore {
|
||||
/// Create a new empty [`MemoryStore`].
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl EventCacheStore for MemoryStore {
|
||||
async fn room_events(&self, room: &RoomId) -> Result<Vec<SyncTimelineEvent>> {
|
||||
Ok(self
|
||||
.by_room
|
||||
.read()
|
||||
.await
|
||||
.get(room)
|
||||
.map(|room_info| {
|
||||
room_info
|
||||
.entries
|
||||
.iter()
|
||||
.filter_map(
|
||||
|entry| if let TimelineEntry::Event(ev) = entry { Some(ev) } else { None },
|
||||
)
|
||||
.cloned()
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or_default())
|
||||
}
|
||||
|
||||
async fn append_room_entries(&self, room: &RoomId, entries: Vec<TimelineEntry>) -> Result<()> {
|
||||
self.by_room.write().await.entry(room.to_owned()).or_default().entries.extend(entries);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn clear_room(&self, room: &RoomId) -> Result<()> {
|
||||
// Clear the room, so as to avoid reallocations if the room is being reused.
|
||||
// XXX: do we also want an actual way to *remove* a room? (for left rooms)
|
||||
if let Some(room) = self.by_room.write().await.get_mut(room) {
|
||||
room.clear();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn oldest_backpagination_token(&self, room: &RoomId) -> Result<Option<PaginationToken>> {
|
||||
Ok(self.by_room.read().await.get(room).and_then(|room| {
|
||||
room.entries.iter().find_map(|entry| {
|
||||
if let TimelineEntry::Gap { prev_token: backpagination_token } = entry {
|
||||
Some(backpagination_token.clone())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
}))
|
||||
}
|
||||
|
||||
async fn contains_gap(&self, room: &RoomId, needle: &PaginationToken) -> Result<bool> {
|
||||
let mut by_room_guard = self.by_room.write().await;
|
||||
let room = by_room_guard.entry(room.to_owned()).or_default();
|
||||
|
||||
Ok(room.entries.iter().any(|entry| {
|
||||
if let TimelineEntry::Gap { prev_token: existing } = entry {
|
||||
existing == needle
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
async fn replace_gap(
|
||||
&self,
|
||||
room: &RoomId,
|
||||
token: Option<&PaginationToken>,
|
||||
entries: Vec<TimelineEntry>,
|
||||
) -> Result<bool> {
|
||||
let mut by_room_guard = self.by_room.write().await;
|
||||
let room = by_room_guard.entry(room.to_owned()).or_default();
|
||||
|
||||
if let Some(token) = token {
|
||||
let gap_pos = room.entries.iter().enumerate().find_map(|(i, t)| {
|
||||
if let TimelineEntry::Gap { prev_token: existing } = t {
|
||||
if existing == token {
|
||||
return Some(i);
|
||||
}
|
||||
}
|
||||
None
|
||||
});
|
||||
|
||||
if let Some(pos) = gap_pos {
|
||||
room.entries.splice(pos..pos + 1, entries);
|
||||
Ok(true)
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
} else {
|
||||
// We had no previous token: assume we can prepend the events.
|
||||
room.entries.splice(0..0, entries);
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Gap {
|
||||
/// The token to use in the query, extracted from a previous "from" /
|
||||
@@ -266,7 +86,7 @@ impl RoomEvents {
|
||||
&mut self,
|
||||
events: I,
|
||||
position: Position,
|
||||
) -> StdResult<(), LinkedChunkError>
|
||||
) -> Result<(), LinkedChunkError>
|
||||
where
|
||||
I: IntoIterator<Item = SyncTimelineEvent>,
|
||||
I::IntoIter: ExactSizeIterator,
|
||||
@@ -275,11 +95,7 @@ impl RoomEvents {
|
||||
}
|
||||
|
||||
/// Insert a gap at a specified position.
|
||||
pub fn insert_gap_at(
|
||||
&mut self,
|
||||
gap: Gap,
|
||||
position: Position,
|
||||
) -> StdResult<(), LinkedChunkError> {
|
||||
pub fn insert_gap_at(&mut self, gap: Gap, position: Position) -> Result<(), LinkedChunkError> {
|
||||
self.chunks.insert_gap_at(gap, position)
|
||||
}
|
||||
|
||||
@@ -291,7 +107,7 @@ impl RoomEvents {
|
||||
&mut self,
|
||||
items: I,
|
||||
gap_identifier: ChunkIdentifier,
|
||||
) -> StdResult<(), LinkedChunkError>
|
||||
) -> Result<(), LinkedChunkError>
|
||||
where
|
||||
I: IntoIterator<Item = SyncTimelineEvent>,
|
||||
I::IntoIter: ExactSizeIterator,
|
||||
@@ -335,7 +151,7 @@ impl RoomEvents {
|
||||
pub fn rchunks_from(
|
||||
&self,
|
||||
identifier: ChunkIdentifier,
|
||||
) -> StdResult<
|
||||
) -> Result<
|
||||
LinkedChunkIterBackward<'_, SyncTimelineEvent, Gap, DEFAULT_CHUNK_CAPACITY>,
|
||||
LinkedChunkError,
|
||||
> {
|
||||
@@ -347,10 +163,8 @@ impl RoomEvents {
|
||||
pub fn chunks_from(
|
||||
&self,
|
||||
identifier: ChunkIdentifier,
|
||||
) -> StdResult<
|
||||
LinkedChunkIter<'_, SyncTimelineEvent, Gap, DEFAULT_CHUNK_CAPACITY>,
|
||||
LinkedChunkError,
|
||||
> {
|
||||
) -> Result<LinkedChunkIter<'_, SyncTimelineEvent, Gap, DEFAULT_CHUNK_CAPACITY>, LinkedChunkError>
|
||||
{
|
||||
self.chunks.chunks_from(identifier)
|
||||
}
|
||||
|
||||
@@ -364,7 +178,7 @@ impl RoomEvents {
|
||||
/// Iterate over the events, forward.
|
||||
///
|
||||
/// The oldest event comes first.
|
||||
pub fn events(&self) -> impl Iterator<Item = (ItemPosition, &SyncTimelineEvent)> {
|
||||
pub fn events(&self) -> impl Iterator<Item = (Position, &SyncTimelineEvent)> {
|
||||
self.chunks.items()
|
||||
}
|
||||
|
||||
@@ -372,7 +186,7 @@ impl RoomEvents {
|
||||
pub fn revents_from(
|
||||
&self,
|
||||
position: Position,
|
||||
) -> StdResult<impl Iterator<Item = (Position, &SyncTimelineEvent)>, LinkedChunkError> {
|
||||
) -> Result<impl Iterator<Item = (Position, &SyncTimelineEvent)>, LinkedChunkError> {
|
||||
self.chunks.ritems_from(position)
|
||||
}
|
||||
|
||||
@@ -381,13 +195,13 @@ impl RoomEvents {
|
||||
pub fn events_from(
|
||||
&self,
|
||||
position: Position,
|
||||
) -> StdResult<impl Iterator<Item = (Position, &SyncTimelineEvent)>, LinkedChunkError> {
|
||||
) -> Result<impl Iterator<Item = (Position, &SyncTimelineEvent)>, LinkedChunkError> {
|
||||
self.chunks.items_from(position)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for RoomEvents {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> StdResult<(), fmt::Error> {
|
||||
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
|
||||
formatter.debug_struct("RoomEvents").field("chunk", &self.chunks).finish()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user