use std::{collections::HashMap, sync::Arc};
use ruma::{EventId, OwnedEventId};
use tokio::sync::{OwnedRwLockReadGuard, OwnedRwLockWriteGuard, RwLock};
use super::{LatestEvent, LatestEventsError};
use crate::{
event_cache::{EventCache, EventCacheError, RoomEventCache},
room::WeakRoom,
send_queue::RoomSendQueueUpdate,
};
#[derive(Debug)]
pub(super) struct RoomLatestEvents {
state: Arc<RwLock<RoomLatestEventsState>>,
}
impl RoomLatestEvents {
pub async fn new(
weak_room: WeakRoom,
event_cache: &EventCache,
) -> Result<Option<Self>, LatestEventsError> {
let room_id = weak_room.room_id();
let room_event_cache = match event_cache.for_room(room_id).await {
Ok((room_event_cache, _drop_handles)) => room_event_cache,
Err(EventCacheError::RoomNotFound { .. }) => return Ok(None),
Err(err) => return Err(LatestEventsError::EventCache(err)),
};
Ok(Some(Self {
state: Arc::new(RwLock::new(RoomLatestEventsState {
for_the_room: Self::create_latest_event_for_inner(
&weak_room,
None,
&room_event_cache,
)
.await,
per_thread: HashMap::new(),
weak_room,
room_event_cache,
})),
}))
}
async fn create_latest_event_for_inner(
weak_room: &WeakRoom,
thread_id: Option<&EventId>,
room_event_cache: &RoomEventCache,
) -> LatestEvent {
LatestEvent::new(weak_room, thread_id, room_event_cache).await
}
pub async fn read(&self) -> RoomLatestEventsReadGuard {
RoomLatestEventsReadGuard { inner: self.state.clone().read_owned().await }
}
pub async fn write(&self) -> RoomLatestEventsWriteGuard {
RoomLatestEventsWriteGuard { inner: self.state.clone().write_owned().await }
}
}
#[derive(Debug)]
struct RoomLatestEventsState {
for_the_room: LatestEvent,
per_thread: HashMap<OwnedEventId, LatestEvent>,
room_event_cache: RoomEventCache,
weak_room: WeakRoom,
}
pub(super) struct RoomLatestEventsReadGuard {
inner: OwnedRwLockReadGuard<RoomLatestEventsState>,
}
impl RoomLatestEventsReadGuard {
pub fn for_room(&self) -> &LatestEvent {
&self.inner.for_the_room
}
pub fn for_thread(&self, thread_id: &EventId) -> Option<&LatestEvent> {
self.inner.per_thread.get(thread_id)
}
#[cfg(test)]
pub fn per_thread(&self) -> &HashMap<OwnedEventId, LatestEvent> {
&self.inner.per_thread
}
}
pub(super) struct RoomLatestEventsWriteGuard {
inner: OwnedRwLockWriteGuard<RoomLatestEventsState>,
}
impl RoomLatestEventsWriteGuard {
async fn create_latest_event_for(&self, thread_id: Option<&EventId>) -> LatestEvent {
RoomLatestEvents::create_latest_event_for_inner(
&self.inner.weak_room,
thread_id,
&self.inner.room_event_cache,
)
.await
}
pub fn has_thread(&self, thread_id: &EventId) -> bool {
self.inner.per_thread.contains_key(thread_id)
}
pub async fn create_and_insert_latest_event_for_thread(&mut self, thread_id: &EventId) {
let latest_event = self.create_latest_event_for(Some(thread_id)).await;
self.inner.per_thread.insert(thread_id.to_owned(), latest_event);
}
pub fn forget_thread(&mut self, thread_id: &EventId) {
self.inner.per_thread.remove(thread_id);
}
pub async fn update_with_event_cache(&mut self) {
let room = self.inner.weak_room.get();
let (own_user_id, power_levels) = match &room {
Some(room) => {
let power_levels = room.power_levels().await.ok();
(Some(room.own_user_id()), power_levels)
}
None => (None, None),
};
let inner = &mut *self.inner;
let for_the_room = &mut inner.for_the_room;
let per_thread = &mut inner.per_thread;
let room_event_cache = &inner.room_event_cache;
for_the_room
.update_with_event_cache(room_event_cache, own_user_id, power_levels.as_ref())
.await;
for latest_event in per_thread.values_mut() {
latest_event
.update_with_event_cache(room_event_cache, own_user_id, power_levels.as_ref())
.await;
}
}
pub async fn update_with_send_queue(&mut self, send_queue_update: &RoomSendQueueUpdate) {
let room = self.inner.weak_room.get();
let (own_user_id, power_levels) = match &room {
Some(room) => {
let power_levels = room.power_levels().await.ok();
(Some(room.own_user_id()), power_levels)
}
None => (None, None),
};
let inner = &mut *self.inner;
let for_the_room = &mut inner.for_the_room;
let per_thread = &mut inner.per_thread;
let room_event_cache = &inner.room_event_cache;
for_the_room
.update_with_send_queue(
send_queue_update,
room_event_cache,
own_user_id,
power_levels.as_ref(),
)
.await;
for latest_event in per_thread.values_mut() {
latest_event
.update_with_send_queue(
send_queue_update,
room_event_cache,
own_user_id,
power_levels.as_ref(),
)
.await;
}
}
}