base: Refactor out the room state/timeline handling.

master
Damir Jelić 2020-11-30 17:25:29 +01:00
parent 7dd834a214
commit 0e563a9a81
4 changed files with 99 additions and 90 deletions

View File

@ -458,7 +458,7 @@ impl Client {
/// ///
/// `room_id` - The unique id of the room that should be fetched. /// `room_id` - The unique id of the room that should be fetched.
pub fn get_joined_room(&self, room_id: &RoomId) -> Option<Room> { pub fn get_joined_room(&self, room_id: &RoomId) -> Option<Room> {
self.base_client.get_joined_room(room_id) self.base_client.get_room(room_id)
} }
///// Get an invited room with the given room id. ///// Get an invited room with the given room id.
@ -1032,7 +1032,7 @@ impl Client {
let _guard = mutex.lock().await; let _guard = mutex.lock().await;
{ {
let room = self.base_client.get_joined_room(room_id).unwrap(); let room = self.base_client.get_room(room_id).unwrap();
let members = room.joined_user_ids().await; let members = room.joined_user_ids().await;
// TODO don't collect here. // TODO don't collect here.
let members_iter: Vec<UserId> = members.collect().await; let members_iter: Vec<UserId> = members.collect().await;
@ -1134,14 +1134,14 @@ impl Client {
/// Returns true if a room with the given id was found and the room is /// Returns true if a room with the given id was found and the room is
/// encrypted, false if the room wasn't found or isn't encrypted. /// encrypted, false if the room wasn't found or isn't encrypted.
async fn is_room_encrypted(&self, room_id: &RoomId) -> bool { async fn is_room_encrypted(&self, room_id: &RoomId) -> bool {
match self.base_client.get_joined_room(room_id) { match self.base_client.get_room(room_id) {
Some(r) => r.is_encrypted(), Some(r) => r.is_encrypted(),
None => false, None => false,
} }
} }
async fn are_members_synced(&self, room_id: &RoomId) -> bool { async fn are_members_synced(&self, room_id: &RoomId) -> bool {
match self.base_client.get_joined_room(room_id) { match self.base_client.get_room(room_id) {
Some(r) => r.are_members_synced(), Some(r) => r.are_members_synced(),
None => true, None => true,
} }

View File

@ -56,7 +56,7 @@ use crate::{
error::Result, error::Result,
responses::{JoinedRoom, Rooms, State, SyncResponse, Timeline}, responses::{JoinedRoom, Rooms, State, SyncResponse, Timeline},
session::Session, session::Session,
store::{Room, RoomType, StateChanges, Store}, store::{InnerSummary, Room, RoomType, StateChanges, Store},
}; };
pub type Token = String; pub type Token = String;
@ -212,7 +212,7 @@ pub struct BaseClient {
pub(crate) sync_token: Arc<RwLock<Option<Token>>>, pub(crate) sync_token: Arc<RwLock<Option<Token>>>,
/// Database /// Database
store: Store, store: Store,
joined_rooms: Arc<DashMap<RoomId, Room>>, rooms: Arc<DashMap<RoomId, Room>>,
#[cfg(feature = "encryption")] #[cfg(feature = "encryption")]
olm: Arc<Mutex<Option<OlmMachine>>>, olm: Arc<Mutex<Option<OlmMachine>>>,
#[cfg(feature = "encryption")] #[cfg(feature = "encryption")]
@ -326,7 +326,7 @@ impl BaseClient {
session: Arc::new(RwLock::new(None)), session: Arc::new(RwLock::new(None)),
sync_token: Arc::new(RwLock::new(None)), sync_token: Arc::new(RwLock::new(None)),
store, store,
joined_rooms: Arc::new(DashMap::new()), rooms: Arc::new(DashMap::new()),
#[cfg(feature = "encryption")] #[cfg(feature = "encryption")]
olm: Arc::new(Mutex::new(None)), olm: Arc::new(Mutex::new(None)),
#[cfg(feature = "encryption")] #[cfg(feature = "encryption")]
@ -446,14 +446,84 @@ impl BaseClient {
.expect("Creating room while not being logged in") .expect("Creating room while not being logged in")
.user_id; .user_id;
match room_type { self.rooms
RoomType::Joined => self .entry(room_id.clone())
.joined_rooms .or_insert_with(|| Room::new(user_id, self.store.clone(), room_id, room_type))
.entry(room_id.clone()) .clone()
.or_insert_with(|| Room::new(user_id, self.store.clone(), room_id, room_type)) }
.clone(),
_ => todo!(), async fn handle_timeline(
&self,
room_id: &RoomId,
ruma_timeline: &api::sync::sync_events::Timeline,
summary: &mut InnerSummary,
mut changes: &mut StateChanges,
) -> Timeline {
let mut timeline = Timeline::new(ruma_timeline.limited, ruma_timeline.prev_batch.clone());
for event in &ruma_timeline.events {
if let Ok(mut e) = hoist_room_event_prev_content(event) {
match &mut e {
AnySyncRoomEvent::State(s) => match s {
AnySyncStateEvent::RoomMember(member) => {
handle_membership(&mut changes, room_id, member);
}
_ => {
summary.handle_state_event(&s);
changes.add_state_event(room_id, s.clone());
}
},
AnySyncRoomEvent::Message(message) =>
{
#[cfg(feature = "encryption")]
if let AnySyncMessageEvent::RoomEncrypted(encrypted) = message {
if let Some(olm) = self.olm_machine().await {
if let Ok(decrypted) =
olm.decrypt_room_event(encrypted, room_id).await
{
if let Ok(decrypted) = decrypted.deserialize() {
e = decrypted;
}
}
}
}
}
_ => (),
}
timeline.events.push(e);
}
} }
timeline
}
async fn handle_state(
&self,
room_id: &RoomId,
events: &[Raw<AnySyncStateEvent>],
summary: &mut InnerSummary,
mut changes: &mut StateChanges,
) -> State {
let mut state = State::default();
for e in events {
if let Ok(event) = hoist_and_deserialize_state_event(e) {
match &event {
AnySyncStateEvent::RoomMember(member) => {
handle_membership(&mut changes, room_id, member);
}
e => {
summary.handle_state_event(&e);
changes.add_state_event(room_id, e.clone());
}
}
state.events.push(event);
}
}
state
} }
/// Receive a response from a sync call. /// Receive a response from a sync call.
@ -486,7 +556,6 @@ impl BaseClient {
} }
let mut changes = StateChanges::default(); let mut changes = StateChanges::default();
let mut rooms = Rooms::default(); let mut rooms = Rooms::default();
for (room_id, room_info) in &response.rooms.join { for (room_id, room_info) in &response.rooms.join {
@ -496,62 +565,18 @@ impl BaseClient {
summary.update(&room_info.summary); summary.update(&room_info.summary);
summary.set_prev_batch(room_info.timeline.prev_batch.as_deref()); summary.set_prev_batch(room_info.timeline.prev_batch.as_deref());
let mut state = State::default(); let state = self
.handle_state(
&room_id,
&room_info.state.events,
&mut summary,
&mut changes,
)
.await;
for e in &room_info.state.events { let timeline = self
if let Ok(event) = hoist_and_deserialize_state_event(e) { .handle_timeline(&room_id, &room_info.timeline, &mut summary, &mut changes)
match &event { .await;
AnySyncStateEvent::RoomMember(member) => {
handle_membership(&mut changes, room_id, member);
}
e => {
summary.handle_state_event(&e);
changes.add_state_event(room_id, e.clone());
}
}
state.events.push(event);
}
}
let mut timeline = Timeline::new(
room_info.timeline.limited,
room_info.timeline.prev_batch.clone(),
);
for event in &room_info.timeline.events {
if let Ok(mut e) = hoist_room_event_prev_content(event) {
match &mut e {
AnySyncRoomEvent::State(s) => match s {
AnySyncStateEvent::RoomMember(member) => {
handle_membership(&mut changes, room_id, member);
}
_ => {
summary.handle_state_event(&s);
changes.add_state_event(room_id, s.clone());
}
},
AnySyncRoomEvent::Message(message) =>
{
#[cfg(feature = "encryption")]
if let AnySyncMessageEvent::RoomEncrypted(encrypted) = message {
if let Some(olm) = self.olm_machine().await {
if let Ok(decrypted) =
olm.decrypt_room_event(encrypted, room_id).await
{
if let Ok(decrypted) = decrypted.deserialize() {
e = decrypted;
}
}
}
}
}
_ => (),
}
timeline.events.push(e);
}
}
#[cfg(feature = "encryption")] #[cfg(feature = "encryption")]
if summary.is_encrypted() { if summary.is_encrypted() {
@ -595,7 +620,7 @@ impl BaseClient {
async fn apply_changes(&self, changes: &StateChanges) { async fn apply_changes(&self, changes: &StateChanges) {
// TODO emit room changes here // TODO emit room changes here
for (room_id, summary) in &changes.room_summaries { for (room_id, summary) in &changes.room_summaries {
if let Some(room) = self.get_joined_room(&room_id) { if let Some(room) = self.get_room(&room_id) {
room.update_summary(summary.clone()) room.update_summary(summary.clone())
} }
} }
@ -606,7 +631,7 @@ impl BaseClient {
room_id: &RoomId, room_id: &RoomId,
response: &api::membership::get_member_events::Response, response: &api::membership::get_member_events::Response,
) -> Result<()> { ) -> Result<()> {
if let Some(room) = self.get_joined_room(room_id) { if let Some(room) = self.get_room(room_id) {
let mut summary = room.clone_summary(); let mut summary = room.clone_summary();
summary.mark_members_synced(); summary.mark_members_synced();
@ -763,8 +788,8 @@ impl BaseClient {
} }
} }
pub fn get_joined_room(&self, room_id: &RoomId) -> Option<Room> { pub fn get_room(&self, room_id: &RoomId) -> Option<Room> {
self.joined_rooms.get(room_id).map(|r| r.clone()) self.rooms.get(room_id).map(|r| r.clone())
} }
/// Encrypt a message event content. /// Encrypt a message event content.

View File

@ -18,7 +18,6 @@ pub struct SyncResponse {
/// Updates to the presence status of other users. /// Updates to the presence status of other users.
pub presence: Presence, pub presence: Presence,
///// The global private data created by this user. ///// The global private data created by this user.
//#[serde(default, skip_serializing_if = "AccountData::is_empty")]
//pub account_data: AccountData, //pub account_data: AccountData,
/// Messages sent dirrectly between devices. /// Messages sent dirrectly between devices.
pub to_device: ToDevice, pub to_device: ToDevice,
@ -74,41 +73,28 @@ pub struct ToDevice {
#[derive(Clone, Debug, Default, Deserialize, Serialize)] #[derive(Clone, Debug, Default, Deserialize, Serialize)]
pub struct Rooms { pub struct Rooms {
// /// The rooms that the user has left or been banned from. // /// The rooms that the user has left or been banned from.
// #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
// pub leave: BTreeMap<RoomId, LeftRoom>, // pub leave: BTreeMap<RoomId, LeftRoom>,
/// The rooms that the user has joined. /// The rooms that the user has joined.
#[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
pub join: BTreeMap<RoomId, JoinedRoom>, pub join: BTreeMap<RoomId, JoinedRoom>,
// /// The rooms that the user has been invited to. // /// The rooms that the user has been invited to.
// #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
// pub invite: BTreeMap<RoomId, InvitedRoom>, // pub invite: BTreeMap<RoomId, InvitedRoom>,
} }
/// Updates to joined rooms. /// Updates to joined rooms.
#[derive(Clone, Debug, Deserialize, Serialize)] #[derive(Clone, Debug, Deserialize, Serialize)]
pub struct JoinedRoom { pub struct JoinedRoom {
// /// Information about the room which clients may need to correctly render it
// /// to users.
// #[serde(default, skip_serializing_if = "RoomSummary::is_empty")]
// pub summary: RoomSummary,
// /// Counts of unread notifications for this room. // /// Counts of unread notifications for this room.
// #[serde(default, skip_serializing_if = "UnreadNotificationsCount::is_empty")]
// pub unread_notifications: UnreadNotificationsCount, // pub unread_notifications: UnreadNotificationsCount,
/// The timeline of messages and state changes in the room. /// The timeline of messages and state changes in the room.
pub timeline: Timeline, pub timeline: Timeline,
/// Updates to the state, between the time indicated by the `since` parameter, and the start /// Updates to the state, between the time indicated by the `since` parameter, and the start
/// of the `timeline` (or all state up to the start of the `timeline`, if `since` is not /// of the `timeline` (or all state up to the start of the `timeline`, if `since` is not
/// given, or `full_state` is true). /// given, or `full_state` is true).
pub state: State, pub state: State,
// /// The private data that this user has attached to this room. // /// The private data that this user has attached to this room.
// #[serde(default, skip_serializing_if = "AccountData::is_empty")]
// pub account_data: AccountData, // pub account_data: AccountData,
// /// The ephemeral events in the room that aren't recorded in the timeline or state of the // /// The ephemeral events in the room that aren't recorded in the timeline or state of the
// /// room. e.g. typing. // /// room. e.g. typing.
// #[serde(default, skip_serializing_if = "Ephemeral::is_empty")]
// pub ephemeral: Ephemeral, // pub ephemeral: Ephemeral,
} }

View File

@ -139,8 +139,6 @@ pub enum RoomType {
Joined, Joined,
/// Represents a left room, the `left_rooms` HashMap will be used. /// Represents a left room, the `left_rooms` HashMap will be used.
Left, Left,
/// Represents an invited room, the `invited_rooms` HashMap will be used.
Invited,
} }
impl Room { impl Room {