base: Store the raw versions of events in the state store

This patch changes the way we store and load the majority of events that
are in the state store. This is done so custom fields in the event
aren't lost since a deserialize/serialize cycle removes all the unknown
fields from the event.
master
Damir Jelić 2021-04-28 16:46:58 +02:00
parent cff90b1480
commit 4fc21a8860
5 changed files with 174 additions and 107 deletions

View File

@ -473,7 +473,9 @@ impl BaseClient {
} }
_ => { _ => {
room_info.handle_state_event(&s.content()); room_info.handle_state_event(&s.content());
changes.add_state_event(room_id, s.clone()); let raw_event: Raw<AnySyncStateEvent> =
Raw::from_json(event.event.clone().into_json());
changes.add_state_event(room_id, s.clone(), raw_event);
} }
}, },
@ -543,12 +545,12 @@ impl BaseClient {
room_info: &mut RoomInfo, room_info: &mut RoomInfo,
) -> ( ) -> (
BTreeMap<UserId, StrippedMemberEvent>, BTreeMap<UserId, StrippedMemberEvent>,
BTreeMap<String, BTreeMap<String, AnyStrippedStateEvent>>, BTreeMap<String, BTreeMap<String, Raw<AnyStrippedStateEvent>>>,
) { ) {
events.iter().fold( events.iter().fold(
(BTreeMap::new(), BTreeMap::new()), (BTreeMap::new(), BTreeMap::new()),
|(mut members, mut state_events), e| { |(mut members, mut state_events), raw_event| {
match e.deserialize() { match raw_event.deserialize() {
Ok(e) => { Ok(e) => {
if let AnyStrippedStateEvent::RoomMember(member) = e { if let AnyStrippedStateEvent::RoomMember(member) = e {
@ -566,7 +568,7 @@ impl BaseClient {
state_events state_events
.entry(e.content().event_type().to_owned()) .entry(e.content().event_type().to_owned())
.or_insert_with(BTreeMap::new) .or_insert_with(BTreeMap::new)
.insert(e.state_key().to_owned(), e); .insert(e.state_key().to_owned(), raw_event.clone());
} }
} }
Err(err) => { Err(err) => {
@ -595,19 +597,18 @@ impl BaseClient {
let room_id = room_info.room_id.clone(); let room_id = room_info.room_id.clone();
for event in events for raw_event in events {
.iter() let event = match hoist_and_deserialize_state_event(raw_event) {
.filter_map(|e| match hoist_and_deserialize_state_event(&e) { Ok(e) => e,
Ok(e) => Some(e), Err(e) => {
Err(err) => {
warn!( warn!(
"Couldn't deserialize state event for room {}: {:?} {:#?}", "Couldn't deserialize state event for room {}: {:?} {:#?}",
room_id, err, e room_id, e, raw_event
); );
None continue;
} }
}) };
{
room_info.handle_state_event(&event.content()); room_info.handle_state_event(&event.content());
if let AnySyncStateEvent::RoomMember(member) = event { if let AnySyncStateEvent::RoomMember(member) = event {
@ -641,7 +642,7 @@ impl BaseClient {
state_events state_events
.entry(event.content().event_type().to_owned()) .entry(event.content().event_type().to_owned())
.or_insert_with(BTreeMap::new) .or_insert_with(BTreeMap::new)
.insert(event.state_key().to_owned(), event); .insert(event.state_key().to_owned(), raw_event.clone());
} }
} }
@ -658,20 +659,24 @@ impl BaseClient {
events: &[Raw<AnyBasicEvent>], events: &[Raw<AnyBasicEvent>],
changes: &mut StateChanges, changes: &mut StateChanges,
) { ) {
let events: Vec<AnyBasicEvent> = for raw_event in events {
events.iter().filter_map(|e| e.deserialize().ok()).collect(); if let Ok(event) = raw_event.deserialize() {
changes.add_room_account_data(room_id, event, raw_event.clone());
for event in &events { }
changes.add_room_account_data(room_id, event.clone());
} }
} }
async fn handle_account_data(&self, events: &[Raw<AnyBasicEvent>], changes: &mut StateChanges) { async fn handle_account_data(&self, events: &[Raw<AnyBasicEvent>], changes: &mut StateChanges) {
let events: Vec<AnyBasicEvent> = let mut account_data = BTreeMap::new();
events.iter().filter_map(|e| e.deserialize().ok()).collect();
for event in &events { for raw_event in events {
if let AnyBasicEvent::Direct(e) = event { let event = if let Ok(e) = raw_event.deserialize() {
e
} else {
continue;
};
if let AnyBasicEvent::Direct(e) = &event {
for (user_id, rooms) in e.content.iter() { for (user_id, rooms) in e.content.iter() {
for room_id in rooms { for room_id in rooms {
if let Some(room) = changes.room_infos.get_mut(room_id) { if let Some(room) = changes.room_infos.get_mut(room_id) {
@ -684,12 +689,9 @@ impl BaseClient {
} }
} }
} }
}
let account_data: BTreeMap<String, AnyBasicEvent> = events account_data.insert(event.content().event_type().to_owned(), raw_event.clone());
.into_iter() }
.map(|e| (e.content().event_type().to_owned(), e))
.collect();
changes.account_data = account_data; changes.account_data = account_data;
} }
@ -904,7 +906,7 @@ impl BaseClient {
.iter() .iter()
.filter_map(|e| { .filter_map(|e| {
let event = e.deserialize().ok()?; let event = e.deserialize().ok()?;
Some((event.sender.clone(), event)) Some((event.sender, e.clone()))
}) })
.collect(); .collect();
@ -1345,14 +1347,17 @@ impl BaseClient {
/// Gets the push rules from `changes` if they have been updated, otherwise get them from the /// Gets the push rules from `changes` if they have been updated, otherwise get them from the
/// store. As a fallback, uses `Ruleset::server_default` if the user is logged in. /// store. As a fallback, uses `Ruleset::server_default` if the user is logged in.
pub async fn get_push_rules(&self, changes: &StateChanges) -> Result<Ruleset> { pub async fn get_push_rules(&self, changes: &StateChanges) -> Result<Ruleset> {
if let Some(AnyBasicEvent::PushRules(event)) = if let Some(AnyBasicEvent::PushRules(event)) = changes
changes.account_data.get(&EventType::PushRules.to_string()) .account_data
.get(&EventType::PushRules.to_string())
.and_then(|e| e.deserialize().ok())
{ {
Ok(event.content.global.clone()) Ok(event.content.global)
} else if let Some(AnyBasicEvent::PushRules(event)) = self } else if let Some(AnyBasicEvent::PushRules(event)) = self
.store .store
.get_account_data_event(EventType::PushRules) .get_account_data_event(EventType::PushRules)
.await? .await?
.and_then(|e| e.deserialize().ok())
{ {
Ok(event.content.global) Ok(event.content.global)
} else if let Some(session) = self.get_session().await { } else if let Some(session) = self.get_session().await {
@ -1401,12 +1406,14 @@ impl BaseClient {
.get(room_id) .get(room_id)
.and_then(|types| types.get(EventType::RoomPowerLevels.as_str())) .and_then(|types| types.get(EventType::RoomPowerLevels.as_str()))
.and_then(|events| events.get("")) .and_then(|events| events.get(""))
.and_then(|e| e.deserialize().ok())
{ {
event.content.clone() event.content
} else if let Some(AnySyncStateEvent::RoomPowerLevels(event)) = self } else if let Some(AnySyncStateEvent::RoomPowerLevels(event)) = self
.store .store
.get_state_event(room_id, EventType::RoomPowerLevels, "") .get_state_event(room_id, EventType::RoomPowerLevels, "")
.await? .await?
.and_then(|e| e.deserialize().ok())
{ {
event.content event.content
} else { } else {
@ -1454,8 +1461,9 @@ impl BaseClient {
.get(room_id) .get(room_id)
.and_then(|types| types.get(EventType::RoomPowerLevels.as_str())) .and_then(|types| types.get(EventType::RoomPowerLevels.as_str()))
.and_then(|events| events.get("")) .and_then(|events| events.get(""))
.and_then(|e| e.deserialize().ok())
{ {
let room_power_levels = event.content.clone(); let room_power_levels = event.content;
push_rules.users_power_levels = room_power_levels.users; push_rules.users_power_levels = room_power_levels.users;
push_rules.default_power_level = room_power_levels.users_default; push_rules.default_power_level = room_power_levels.users_default;

View File

@ -393,7 +393,11 @@ impl Room {
return Ok(None); return Ok(None);
}; };
let presence = self.store.get_presence_event(user_id).await?; let presence = self
.store
.get_presence_event(user_id)
.await?
.and_then(|e| e.deserialize().ok());
let profile = self.store.get_profile(self.room_id(), user_id).await?; let profile = self.store.get_profile(self.room_id(), user_id).await?;
let max_power_level = self.max_power_level(); let max_power_level = self.max_power_level();
let is_room_creator = self let is_room_creator = self
@ -410,6 +414,7 @@ impl Room {
.store .store
.get_state_event(self.room_id(), EventType::RoomPowerLevels, "") .get_state_event(self.room_id(), EventType::RoomPowerLevels, "")
.await? .await?
.and_then(|e| e.deserialize().ok())
.and_then(|e| { .and_then(|e| {
if let AnySyncStateEvent::RoomPowerLevels(e) = e { if let AnySyncStateEvent::RoomPowerLevels(e) = e {
Some(e) Some(e)

View File

@ -23,10 +23,11 @@ use matrix_sdk_common::{
events::{ events::{
presence::PresenceEvent, presence::PresenceEvent,
room::member::{MemberEventContent, MembershipState}, room::member::{MemberEventContent, MembershipState},
AnyBasicEvent, AnyStrippedStateEvent, AnySyncStateEvent, EventContent, EventType, AnyBasicEvent, AnyStrippedStateEvent, AnySyncStateEvent, EventType,
}, },
identifiers::{RoomId, UserId}, identifiers::{RoomId, UserId},
instant::Instant, instant::Instant,
Raw,
}; };
use tracing::info; use tracing::info;
@ -39,7 +40,7 @@ use super::{Result, RoomInfo, StateChanges, StateStore};
pub struct MemoryStore { pub struct MemoryStore {
sync_token: Arc<RwLock<Option<String>>>, sync_token: Arc<RwLock<Option<String>>>,
filters: Arc<DashMap<String, String>>, filters: Arc<DashMap<String, String>>,
account_data: Arc<DashMap<String, AnyBasicEvent>>, account_data: Arc<DashMap<String, Raw<AnyBasicEvent>>>,
members: Arc<DashMap<RoomId, DashMap<UserId, MemberEvent>>>, members: Arc<DashMap<RoomId, DashMap<UserId, MemberEvent>>>,
profiles: Arc<DashMap<RoomId, DashMap<UserId, MemberEventContent>>>, profiles: Arc<DashMap<RoomId, DashMap<UserId, MemberEventContent>>>,
display_names: Arc<DashMap<RoomId, DashMap<String, BTreeSet<UserId>>>>, display_names: Arc<DashMap<RoomId, DashMap<String, BTreeSet<UserId>>>>,
@ -47,14 +48,14 @@ pub struct MemoryStore {
invited_user_ids: Arc<DashMap<RoomId, DashSet<UserId>>>, invited_user_ids: Arc<DashMap<RoomId, DashSet<UserId>>>,
room_info: Arc<DashMap<RoomId, RoomInfo>>, room_info: Arc<DashMap<RoomId, RoomInfo>>,
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
room_state: Arc<DashMap<RoomId, DashMap<String, DashMap<String, AnySyncStateEvent>>>>, room_state: Arc<DashMap<RoomId, DashMap<String, DashMap<String, Raw<AnySyncStateEvent>>>>>,
room_account_data: Arc<DashMap<RoomId, DashMap<String, AnyBasicEvent>>>, room_account_data: Arc<DashMap<RoomId, DashMap<String, Raw<AnyBasicEvent>>>>,
stripped_room_info: Arc<DashMap<RoomId, RoomInfo>>, stripped_room_info: Arc<DashMap<RoomId, RoomInfo>>,
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
stripped_room_state: stripped_room_state:
Arc<DashMap<RoomId, DashMap<String, DashMap<String, AnyStrippedStateEvent>>>>, Arc<DashMap<RoomId, DashMap<String, DashMap<String, Raw<AnyStrippedStateEvent>>>>>,
stripped_members: Arc<DashMap<RoomId, DashMap<UserId, StrippedMemberEvent>>>, stripped_members: Arc<DashMap<RoomId, DashMap<UserId, StrippedMemberEvent>>>,
presence: Arc<DashMap<UserId, PresenceEvent>>, presence: Arc<DashMap<UserId, Raw<PresenceEvent>>>,
} }
impl MemoryStore { impl MemoryStore {
@ -176,14 +177,14 @@ impl MemoryStore {
} }
for (room, event_types) in &changes.state { for (room, event_types) in &changes.state {
for events in event_types.values() { for (event_type, events) in event_types {
for event in events.values() { for (state_key, event) in events {
self.room_state self.room_state
.entry(room.clone()) .entry(room.clone())
.or_insert_with(DashMap::new) .or_insert_with(DashMap::new)
.entry(event.content().event_type().to_string()) .entry(event_type.to_owned())
.or_insert_with(DashMap::new) .or_insert_with(DashMap::new)
.insert(event.state_key().to_string(), event.clone()); .insert(state_key.to_owned(), event.clone());
} }
} }
} }
@ -211,14 +212,14 @@ impl MemoryStore {
} }
for (room, event_types) in &changes.stripped_state { for (room, event_types) in &changes.stripped_state {
for events in event_types.values() { for (event_type, events) in event_types {
for event in events.values() { for (state_key, event) in events {
self.stripped_room_state self.stripped_room_state
.entry(room.clone()) .entry(room.clone())
.or_insert_with(DashMap::new) .or_insert_with(DashMap::new)
.entry(event.content().event_type().to_string()) .entry(event_type.to_owned())
.or_insert_with(DashMap::new) .or_insert_with(DashMap::new)
.insert(event.state_key().to_string(), event.clone()); .insert(state_key.to_owned(), event.clone());
} }
} }
} }
@ -228,7 +229,7 @@ impl MemoryStore {
Ok(()) Ok(())
} }
async fn get_presence_event(&self, user_id: &UserId) -> Result<Option<PresenceEvent>> { async fn get_presence_event(&self, user_id: &UserId) -> Result<Option<Raw<PresenceEvent>>> {
#[allow(clippy::map_clone)] #[allow(clippy::map_clone)]
Ok(self.presence.get(user_id).map(|p| p.clone())) Ok(self.presence.get(user_id).map(|p| p.clone()))
} }
@ -238,7 +239,7 @@ impl MemoryStore {
room_id: &RoomId, room_id: &RoomId,
event_type: EventType, event_type: EventType,
state_key: &str, state_key: &str,
) -> Result<Option<AnySyncStateEvent>> { ) -> Result<Option<Raw<AnySyncStateEvent>>> {
#[allow(clippy::map_clone)] #[allow(clippy::map_clone)]
Ok(self.room_state.get(room_id).and_then(|e| { Ok(self.room_state.get(room_id).and_then(|e| {
e.get(event_type.as_ref()) e.get(event_type.as_ref())
@ -304,7 +305,10 @@ impl MemoryStore {
self.stripped_room_info.iter().map(|r| r.clone()).collect() self.stripped_room_info.iter().map(|r| r.clone()).collect()
} }
async fn get_account_data_event(&self, event_type: EventType) -> Result<Option<AnyBasicEvent>> { async fn get_account_data_event(
&self,
event_type: EventType,
) -> Result<Option<Raw<AnyBasicEvent>>> {
Ok(self Ok(self
.account_data .account_data
.get(event_type.as_ref()) .get(event_type.as_ref())
@ -331,7 +335,7 @@ impl StateStore for MemoryStore {
self.get_sync_token().await self.get_sync_token().await
} }
async fn get_presence_event(&self, user_id: &UserId) -> Result<Option<PresenceEvent>> { async fn get_presence_event(&self, user_id: &UserId) -> Result<Option<Raw<PresenceEvent>>> {
self.get_presence_event(user_id).await self.get_presence_event(user_id).await
} }
@ -340,7 +344,7 @@ impl StateStore for MemoryStore {
room_id: &RoomId, room_id: &RoomId,
event_type: EventType, event_type: EventType,
state_key: &str, state_key: &str,
) -> Result<Option<AnySyncStateEvent>> { ) -> Result<Option<Raw<AnySyncStateEvent>>> {
self.get_state_event(room_id, event_type, state_key).await self.get_state_event(room_id, event_type, state_key).await
} }
@ -393,7 +397,10 @@ impl StateStore for MemoryStore {
.unwrap_or_default()) .unwrap_or_default())
} }
async fn get_account_data_event(&self, event_type: EventType) -> Result<Option<AnyBasicEvent>> { async fn get_account_data_event(
&self,
event_type: EventType,
) -> Result<Option<Raw<AnyBasicEvent>>> {
self.get_account_data_event(event_type).await self.get_account_data_event(event_type).await
} }
} }

View File

@ -31,7 +31,7 @@ use matrix_sdk_common::{
}, },
identifiers::{RoomId, UserId}, identifiers::{RoomId, UserId},
locks::RwLock, locks::RwLock,
AsyncTraitDeps, AsyncTraitDeps, Raw,
}; };
#[cfg(feature = "sled_state_store")] #[cfg(feature = "sled_state_store")]
use sled::Db; use sled::Db;
@ -114,7 +114,7 @@ pub trait StateStore: AsyncTraitDeps {
/// ///
/// * `user_id` - The id of the user for which we wish to fetch the presence /// * `user_id` - The id of the user for which we wish to fetch the presence
/// event for. /// event for.
async fn get_presence_event(&self, user_id: &UserId) -> Result<Option<PresenceEvent>>; async fn get_presence_event(&self, user_id: &UserId) -> Result<Option<Raw<PresenceEvent>>>;
/// Get a state event out of the state store. /// Get a state event out of the state store.
/// ///
@ -128,7 +128,7 @@ pub trait StateStore: AsyncTraitDeps {
room_id: &RoomId, room_id: &RoomId,
event_type: EventType, event_type: EventType,
state_key: &str, state_key: &str,
) -> Result<Option<AnySyncStateEvent>>; ) -> Result<Option<Raw<AnySyncStateEvent>>>;
/// Get the current profile for the given user in the given room. /// Get the current profile for the given user in the given room.
/// ///
@ -192,7 +192,10 @@ pub trait StateStore: AsyncTraitDeps {
/// # Arguments /// # Arguments
/// ///
/// * `event_type` - The event type of the account data event. /// * `event_type` - The event type of the account data event.
async fn get_account_data_event(&self, event_type: EventType) -> Result<Option<AnyBasicEvent>>; async fn get_account_data_event(
&self,
event_type: EventType,
) -> Result<Option<Raw<AnyBasicEvent>>>;
} }
/// A state store wrapper for the SDK. /// A state store wrapper for the SDK.
@ -345,30 +348,33 @@ pub struct StateChanges {
/// A user session, containing an access token and information about the associated user account. /// A user session, containing an access token and information about the associated user account.
pub session: Option<Session>, pub session: Option<Session>,
/// A mapping of event type string to `AnyBasicEvent`. /// A mapping of event type string to `AnyBasicEvent`.
pub account_data: BTreeMap<String, AnyBasicEvent>, pub account_data: BTreeMap<String, Raw<AnyBasicEvent>>,
/// A mapping of `UserId` to `PresenceEvent`. /// A mapping of `UserId` to `PresenceEvent`.
pub presence: BTreeMap<UserId, PresenceEvent>, pub presence: BTreeMap<UserId, Raw<PresenceEvent>>,
/// A mapping of `RoomId` to a map of users and their `MemberEvent`. /// A mapping of `RoomId` to a map of users and their `MemberEvent`.
pub members: BTreeMap<RoomId, BTreeMap<UserId, MemberEvent>>, pub members: BTreeMap<RoomId, BTreeMap<UserId, MemberEvent>>,
/// A mapping of `RoomId` to a map of users and their `MemberEventContent`. /// A mapping of `RoomId` to a map of users and their `MemberEventContent`.
pub profiles: BTreeMap<RoomId, BTreeMap<UserId, MemberEventContent>>, pub profiles: BTreeMap<RoomId, BTreeMap<UserId, MemberEventContent>>,
pub(crate) ambiguity_maps: BTreeMap<RoomId, BTreeMap<String, BTreeSet<UserId>>>,
/// A mapping of `RoomId` to a map of event type string to a state key and `AnySyncStateEvent`. /// A mapping of `RoomId` to a map of event type string to a state key and `AnySyncStateEvent`.
pub state: BTreeMap<RoomId, BTreeMap<String, BTreeMap<String, AnySyncStateEvent>>>, pub state: BTreeMap<RoomId, BTreeMap<String, BTreeMap<String, Raw<AnySyncStateEvent>>>>,
/// A mapping of `RoomId` to a map of event type string to `AnyBasicEvent`. /// A mapping of `RoomId` to a map of event type string to `AnyBasicEvent`.
pub room_account_data: BTreeMap<RoomId, BTreeMap<String, AnyBasicEvent>>, pub room_account_data: BTreeMap<RoomId, BTreeMap<String, Raw<AnyBasicEvent>>>,
/// A map of `RoomId` to `RoomInfo`. /// A map of `RoomId` to `RoomInfo`.
pub room_infos: BTreeMap<RoomId, RoomInfo>, pub room_infos: BTreeMap<RoomId, RoomInfo>,
/// A mapping of `RoomId` to a map of event type to a map of state key to `AnyStrippedStateEvent`. /// A mapping of `RoomId` to a map of event type to a map of state key to `AnyStrippedStateEvent`.
pub stripped_state: BTreeMap<RoomId, BTreeMap<String, BTreeMap<String, AnyStrippedStateEvent>>>, pub stripped_state:
BTreeMap<RoomId, BTreeMap<String, BTreeMap<String, Raw<AnyStrippedStateEvent>>>>,
/// A mapping of `RoomId` to a map of users and their `StrippedMemberEvent`. /// A mapping of `RoomId` to a map of users and their `StrippedMemberEvent`.
pub stripped_members: BTreeMap<RoomId, BTreeMap<UserId, StrippedMemberEvent>>, pub stripped_members: BTreeMap<RoomId, BTreeMap<UserId, StrippedMemberEvent>>,
/// A map of `RoomId` to `RoomInfo`. /// A map of `RoomId` to `RoomInfo`.
pub invited_room_info: BTreeMap<RoomId, RoomInfo>, pub invited_room_info: BTreeMap<RoomId, RoomInfo>,
/// A map from room id to a map of a display name and a set of user ids that
/// share that display name in the given room.
pub ambiguity_maps: BTreeMap<RoomId, BTreeMap<String, BTreeSet<UserId>>>,
/// A map of `RoomId` to a vector of `Notification`s /// A map of `RoomId` to a vector of `Notification`s
pub notifications: BTreeMap<RoomId, Vec<Notification>>, pub notifications: BTreeMap<RoomId, Vec<Notification>>,
} }
@ -383,8 +389,8 @@ impl StateChanges {
} }
/// Update the `StateChanges` struct with the given `PresenceEvent`. /// Update the `StateChanges` struct with the given `PresenceEvent`.
pub fn add_presence_event(&mut self, event: PresenceEvent) { pub fn add_presence_event(&mut self, event: PresenceEvent, raw_event: Raw<PresenceEvent>) {
self.presence.insert(event.sender.clone(), event); self.presence.insert(event.sender, raw_event);
} }
/// Update the `StateChanges` struct with the given `RoomInfo`. /// Update the `StateChanges` struct with the given `RoomInfo`.
@ -400,27 +406,22 @@ impl StateChanges {
} }
/// Update the `StateChanges` struct with the given `AnyBasicEvent`. /// Update the `StateChanges` struct with the given `AnyBasicEvent`.
pub fn add_account_data(&mut self, event: AnyBasicEvent) { pub fn add_account_data(&mut self, event: AnyBasicEvent, raw_event: Raw<AnyBasicEvent>) {
self.account_data self.account_data
.insert(event.content().event_type().to_owned(), event); .insert(event.content().event_type().to_owned(), raw_event);
} }
/// Update the `StateChanges` struct with the given room with a new `AnyBasicEvent`. /// Update the `StateChanges` struct with the given room with a new `AnyBasicEvent`.
pub fn add_room_account_data(&mut self, room_id: &RoomId, event: AnyBasicEvent) { pub fn add_room_account_data(
&mut self,
room_id: &RoomId,
event: AnyBasicEvent,
raw_event: Raw<AnyBasicEvent>,
) {
self.room_account_data self.room_account_data
.entry(room_id.to_owned()) .entry(room_id.to_owned())
.or_insert_with(BTreeMap::new) .or_insert_with(BTreeMap::new)
.insert(event.content().event_type().to_owned(), event); .insert(event.content().event_type().to_owned(), raw_event);
}
/// Update the `StateChanges` struct with the given room with a new `AnyStrippedStateEvent`.
pub fn add_stripped_state_event(&mut self, room_id: &RoomId, event: AnyStrippedStateEvent) {
self.stripped_state
.entry(room_id.to_owned())
.or_insert_with(BTreeMap::new)
.entry(event.content().event_type().to_string())
.or_insert_with(BTreeMap::new)
.insert(event.state_key().to_string(), event);
} }
/// Update the `StateChanges` struct with the given room with a new `StrippedMemberEvent`. /// Update the `StateChanges` struct with the given room with a new `StrippedMemberEvent`.
@ -434,13 +435,18 @@ impl StateChanges {
} }
/// Update the `StateChanges` struct with the given room with a new `AnySyncStateEvent`. /// Update the `StateChanges` struct with the given room with a new `AnySyncStateEvent`.
pub fn add_state_event(&mut self, room_id: &RoomId, event: AnySyncStateEvent) { pub fn add_state_event(
&mut self,
room_id: &RoomId,
event: AnySyncStateEvent,
raw_event: Raw<AnySyncStateEvent>,
) {
self.state self.state
.entry(room_id.to_owned()) .entry(room_id.to_owned())
.or_insert_with(BTreeMap::new) .or_insert_with(BTreeMap::new)
.entry(event.content().event_type().to_string()) .entry(event.content().event_type().to_string())
.or_insert_with(BTreeMap::new) .or_insert_with(BTreeMap::new)
.insert(event.state_key().to_string(), event); .insert(event.state_key().to_string(), raw_event);
} }
/// Update the `StateChanges` struct with the given room with a new `Notification`. /// Update the `StateChanges` struct with the given room with a new `Notification`.

View File

@ -31,9 +31,10 @@ use matrix_sdk_common::{
events::{ events::{
presence::PresenceEvent, presence::PresenceEvent,
room::member::{MemberEventContent, MembershipState}, room::member::{MemberEventContent, MembershipState},
AnyBasicEvent, AnySyncStateEvent, EventContent, EventType, AnyBasicEvent, AnySyncStateEvent, EventType,
}, },
identifiers::{RoomId, UserId}, identifiers::{RoomId, UserId},
Raw,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -405,14 +406,10 @@ impl SledStore {
} }
for (room, event_types) in &changes.state { for (room, event_types) in &changes.state {
for events in event_types.values() { for (event_type, events) in event_types {
for event in events.values() { for (state_key, event) in events {
state.insert( state.insert(
( (room.as_str(), event_type.as_str(), state_key.as_str())
room.as_str(),
event.content().event_type(),
event.state_key(),
)
.encode(), .encode(),
self.serialize_event(&event) self.serialize_event(&event)
.map_err(ConflictableTransactionError::Abort)?, .map_err(ConflictableTransactionError::Abort)?,
@ -456,14 +453,10 @@ impl SledStore {
} }
for (room, event_types) in &changes.stripped_state { for (room, event_types) in &changes.stripped_state {
for events in event_types.values() { for (event_type, events) in event_types {
for event in events.values() { for (state_key, event) in events {
stripped_state.insert( stripped_state.insert(
( (room.as_str(), event_type.as_str(), state_key.as_str())
room.as_str(),
event.content().event_type(),
event.state_key(),
)
.encode(), .encode(),
self.serialize_event(&event) self.serialize_event(&event)
.map_err(ConflictableTransactionError::Abort)?, .map_err(ConflictableTransactionError::Abort)?,
@ -485,7 +478,7 @@ impl SledStore {
Ok(()) Ok(())
} }
pub async fn get_presence_event(&self, user_id: &UserId) -> Result<Option<PresenceEvent>> { pub async fn get_presence_event(&self, user_id: &UserId) -> Result<Option<Raw<PresenceEvent>>> {
Ok(self Ok(self
.presence .presence
.get(user_id.encode())? .get(user_id.encode())?
@ -498,7 +491,7 @@ impl SledStore {
room_id: &RoomId, room_id: &RoomId,
event_type: EventType, event_type: EventType,
state_key: &str, state_key: &str,
) -> Result<Option<AnySyncStateEvent>> { ) -> Result<Option<Raw<AnySyncStateEvent>>> {
Ok(self Ok(self
.room_state .room_state
.get((room_id.as_str(), event_type.as_str(), state_key).encode())? .get((room_id.as_str(), event_type.as_str(), state_key).encode())?
@ -597,7 +590,7 @@ impl SledStore {
pub async fn get_account_data_event( pub async fn get_account_data_event(
&self, &self,
event_type: EventType, event_type: EventType,
) -> Result<Option<AnyBasicEvent>> { ) -> Result<Option<Raw<AnyBasicEvent>>> {
Ok(self Ok(self
.account_data .account_data
.get(event_type.encode())? .get(event_type.encode())?
@ -624,7 +617,7 @@ impl StateStore for SledStore {
self.get_sync_token().await self.get_sync_token().await
} }
async fn get_presence_event(&self, user_id: &UserId) -> Result<Option<PresenceEvent>> { async fn get_presence_event(&self, user_id: &UserId) -> Result<Option<Raw<PresenceEvent>>> {
self.get_presence_event(user_id).await self.get_presence_event(user_id).await
} }
@ -633,7 +626,7 @@ impl StateStore for SledStore {
room_id: &RoomId, room_id: &RoomId,
event_type: EventType, event_type: EventType,
state_key: &str, state_key: &str,
) -> Result<Option<AnySyncStateEvent>> { ) -> Result<Option<Raw<AnySyncStateEvent>>> {
self.get_state_event(room_id, event_type, state_key).await self.get_state_event(room_id, event_type, state_key).await
} }
@ -682,7 +675,10 @@ impl StateStore for SledStore {
.await .await
} }
async fn get_account_data_event(&self, event_type: EventType) -> Result<Option<AnyBasicEvent>> { async fn get_account_data_event(
&self,
event_type: EventType,
) -> Result<Option<Raw<AnyBasicEvent>>> {
self.get_account_data_event(event_type).await self.get_account_data_event(event_type).await
} }
} }
@ -693,12 +689,17 @@ mod test {
use matrix_sdk_common::{ use matrix_sdk_common::{
events::{ events::{
room::member::{MemberEventContent, MembershipState}, room::{
Unsigned, member::{MemberEventContent, MembershipState},
power_levels::PowerLevelsEventContent,
},
AnySyncStateEvent, EventType, Unsigned,
}, },
identifiers::{room_id, user_id, EventId, UserId}, identifiers::{room_id, user_id, EventId, UserId},
Raw,
}; };
use matrix_sdk_test::async_test; use matrix_sdk_test::async_test;
use serde_json::json;
use super::{SledStore, StateChanges}; use super::{SledStore, StateChanges};
use crate::deserialized_responses::MemberEvent; use crate::deserialized_responses::MemberEvent;
@ -707,6 +708,22 @@ mod test {
user_id!("@example:localhost") user_id!("@example:localhost")
} }
fn power_level_event() -> Raw<AnySyncStateEvent> {
let content = PowerLevelsEventContent::default();
let event = json!({
"event_id": EventId::try_from("$h29iv0s8:example.com").unwrap(),
"content": content,
"sender": user_id(),
"type": "m.room.power_levels",
"origin_server_ts": 0u64,
"state_key": "",
"unsigned": Unsigned::default(),
});
serde_json::from_value(event).unwrap()
}
fn membership_event() -> MemberEvent { fn membership_event() -> MemberEvent {
let content = MemberEventContent { let content = MemberEventContent {
avatar_url: None, avatar_url: None,
@ -752,4 +769,28 @@ mod test {
.unwrap() .unwrap()
.is_some()); .is_some());
} }
#[async_test]
async fn test_power_level_saving() {
let store = SledStore::open().unwrap();
let room_id = room_id!("!test:localhost");
let raw_event = power_level_event();
let event = raw_event.deserialize().unwrap();
assert!(store
.get_state_event(&room_id, EventType::RoomPowerLevels, "")
.await
.unwrap()
.is_none());
let mut changes = StateChanges::default();
changes.add_state_event(&room_id, event, raw_event);
store.save_changes(&changes).await.unwrap();
assert!(store
.get_state_event(&room_id, EventType::RoomPowerLevels, "")
.await
.unwrap()
.is_some());
}
} }