sdk: Allow to get stripped state events from the store
Signed-off-by: Kévin Commaille <zecakeh@tedomum.fr>
This commit is contained in:
committed by
Jonas Platte
parent
645af31c59
commit
83e7afab5d
@@ -19,7 +19,10 @@ use std::{collections::BTreeMap, fmt};
|
||||
pub use matrix_sdk_common::deserialized_responses::*;
|
||||
use ruma::{
|
||||
events::{
|
||||
room::member::{MembershipState, RoomMemberEvent, RoomMemberEventContent},
|
||||
room::{
|
||||
member::{MembershipState, RoomMemberEvent, RoomMemberEventContent},
|
||||
power_levels::{RoomPowerLevels, RoomPowerLevelsEventContent},
|
||||
},
|
||||
AnyStrippedStateEvent, AnySyncStateEvent, EventContentFromType,
|
||||
PossiblyRedactedStateEventContent, RedactContent, RedactedStateEventContent,
|
||||
StateEventContent, StaticStateEventContent, StrippedStateEvent, SyncStateEvent,
|
||||
@@ -265,3 +268,13 @@ impl MemberEvent {
|
||||
self.state_key()
|
||||
}
|
||||
}
|
||||
|
||||
impl SyncOrStrippedState<RoomPowerLevelsEventContent> {
|
||||
/// The power levels of the event.
|
||||
pub fn power_levels(&self) -> RoomPowerLevels {
|
||||
match self {
|
||||
Self::Sync(e) => e.power_levels(),
|
||||
Self::Stripped(e) => e.power_levels(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,14 +19,17 @@ use ruma::{
|
||||
presence::PresenceEvent,
|
||||
room::{
|
||||
member::MembershipState,
|
||||
power_levels::{PowerLevelAction, RoomPowerLevels, SyncRoomPowerLevelsEvent},
|
||||
power_levels::{PowerLevelAction, RoomPowerLevels, RoomPowerLevelsEventContent},
|
||||
},
|
||||
MessageLikeEventType, StateEventType,
|
||||
},
|
||||
MxcUri, UserId,
|
||||
};
|
||||
|
||||
use crate::{deserialized_responses::MemberEvent, MinimalRoomMemberEvent};
|
||||
use crate::{
|
||||
deserialized_responses::{MemberEvent, SyncOrStrippedState},
|
||||
MinimalRoomMemberEvent,
|
||||
};
|
||||
|
||||
/// A member of a room.
|
||||
#[derive(Clone, Debug)]
|
||||
@@ -38,7 +41,7 @@ pub struct RoomMember {
|
||||
pub(crate) profile: Arc<Option<MinimalRoomMemberEvent>>,
|
||||
#[allow(dead_code)]
|
||||
pub(crate) presence: Arc<Option<PresenceEvent>>,
|
||||
pub(crate) power_levels: Arc<Option<SyncRoomPowerLevelsEvent>>,
|
||||
pub(crate) power_levels: Arc<Option<SyncOrStrippedState<RoomPowerLevelsEventContent>>>,
|
||||
pub(crate) max_power_level: i64,
|
||||
pub(crate) is_room_creator: bool,
|
||||
pub(crate) display_name_ambiguous: bool,
|
||||
|
||||
@@ -17,12 +17,12 @@ use ruma::{
|
||||
SyncRoomMemberEvent,
|
||||
},
|
||||
power_levels::RoomPowerLevelsEventContent,
|
||||
topic::{OriginalRoomTopicEvent, RedactedRoomTopicEvent, RoomTopicEventContent},
|
||||
topic::RoomTopicEventContent,
|
||||
MediaSource,
|
||||
},
|
||||
AnyEphemeralRoomEventContent, AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent,
|
||||
AnyStrippedStateEvent, AnySyncEphemeralRoomEvent, AnySyncStateEvent,
|
||||
GlobalAccountDataEventType, RoomAccountDataEventType, StateEventType,
|
||||
GlobalAccountDataEventType, RoomAccountDataEventType, StateEventType, SyncStateEvent,
|
||||
},
|
||||
mxc_uri, room_id,
|
||||
serde::Raw,
|
||||
@@ -266,8 +266,12 @@ impl StateStoreIntegrationTests for DynStateStore {
|
||||
self.get_state_event_static::<RoomTopicEventContent>(room_id)
|
||||
.await?
|
||||
.expect("room topic found before redaction")
|
||||
.deserialize_as::<OriginalRoomTopicEvent>()
|
||||
.deserialize()
|
||||
.expect("can deserialize room topic before redaction")
|
||||
.as_sync()
|
||||
.expect("room topic is a sync state event")
|
||||
.as_original()
|
||||
.expect("room topic is not redacted yet")
|
||||
.content
|
||||
.topic,
|
||||
"😀"
|
||||
@@ -283,23 +287,15 @@ impl StateStoreIntegrationTests for DynStateStore {
|
||||
changes.add_redaction(room_id, &redacted_event_id, redaction_evt);
|
||||
self.save_changes(&changes).await?;
|
||||
|
||||
match self
|
||||
.get_state_event_static::<RoomTopicEventContent>(room_id)
|
||||
.await?
|
||||
.expect("room topic found before redaction")
|
||||
.deserialize_as::<OriginalRoomTopicEvent>()
|
||||
{
|
||||
Err(_) => {} // as expected
|
||||
Ok(_) => panic!("Topic has not been redacted"),
|
||||
}
|
||||
|
||||
let _ = self
|
||||
let redacted_event = self
|
||||
.get_state_event_static::<RoomTopicEventContent>(room_id)
|
||||
.await?
|
||||
.expect("room topic found after redaction")
|
||||
.deserialize_as::<RedactedRoomTopicEvent>()
|
||||
.deserialize()
|
||||
.expect("can deserialize room topic after redaction");
|
||||
|
||||
assert_matches!(redacted_event.as_sync(), Some(SyncStateEvent::Redacted(_)));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -37,8 +37,9 @@ use tracing::{debug, warn};
|
||||
|
||||
use super::{Result, RoomInfo, StateChanges, StateStore, StoreError};
|
||||
use crate::{
|
||||
deserialized_responses::RawMemberEvent, media::MediaRequest, MinimalRoomMemberEvent,
|
||||
RoomMemberships, StateStoreDataKey, StateStoreDataValue,
|
||||
deserialized_responses::{RawAnySyncOrStrippedState, RawMemberEvent},
|
||||
media::MediaRequest,
|
||||
MinimalRoomMemberEvent, RoomMemberships, StateStoreDataKey, StateStoreDataValue,
|
||||
};
|
||||
|
||||
/// In-Memory, non-persistent implementation of the `StateStore`
|
||||
@@ -376,25 +377,48 @@ impl MemoryStore {
|
||||
room_id: &RoomId,
|
||||
event_type: StateEventType,
|
||||
state_key: &str,
|
||||
) -> Result<Option<Raw<AnySyncStateEvent>>> {
|
||||
Ok(self
|
||||
) -> Result<Option<RawAnySyncOrStrippedState>> {
|
||||
if let Some(e) = self
|
||||
.stripped_room_state
|
||||
.get(room_id)
|
||||
.as_ref()
|
||||
.and_then(|events| events.get(&event_type))
|
||||
.and_then(|m| m.get(state_key).map(|m| m.clone()))
|
||||
{
|
||||
Ok(Some(RawAnySyncOrStrippedState::Stripped(e)))
|
||||
} else if let Some(e) = self
|
||||
.room_state
|
||||
.get(room_id)
|
||||
.and_then(|e| e.get(&event_type).and_then(|s| s.get(state_key).map(|e| e.clone()))))
|
||||
.as_ref()
|
||||
.and_then(|events| events.get(&event_type))
|
||||
.and_then(|m| m.get(state_key).map(|m| m.clone()))
|
||||
{
|
||||
Ok(Some(RawAnySyncOrStrippedState::Sync(e)))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_state_events(
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
event_type: StateEventType,
|
||||
) -> Result<Vec<Raw<AnySyncStateEvent>>> {
|
||||
Ok(self
|
||||
.room_state
|
||||
.get(room_id)
|
||||
.and_then(|e| {
|
||||
e.get(&event_type).map(|s| s.iter().map(|e| e.clone()).collect::<Vec<_>>())
|
||||
) -> Result<Vec<RawAnySyncOrStrippedState>> {
|
||||
if let Some(v) = self.stripped_room_state.get(room_id).as_ref().and_then(|events| {
|
||||
events.get(&event_type).map(|s| {
|
||||
s.iter().map(|e| RawAnySyncOrStrippedState::Stripped(e.clone())).collect::<Vec<_>>()
|
||||
})
|
||||
.unwrap_or_default())
|
||||
}) {
|
||||
Ok(v)
|
||||
} else if let Some(v) = self.room_state.get(room_id).as_ref().and_then(|events| {
|
||||
events.get(&event_type).map(|s| {
|
||||
s.iter().map(|e| RawAnySyncOrStrippedState::Sync(e.clone())).collect::<Vec<_>>()
|
||||
})
|
||||
}) {
|
||||
Ok(v)
|
||||
} else {
|
||||
Ok(Vec::new())
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_profile(
|
||||
@@ -410,25 +434,9 @@ impl MemoryStore {
|
||||
room_id: &RoomId,
|
||||
state_key: &UserId,
|
||||
) -> Result<Option<RawMemberEvent>> {
|
||||
if let Some(e) = self
|
||||
.stripped_room_state
|
||||
.get(room_id)
|
||||
.as_ref()
|
||||
.and_then(|events| events.get(&StateEventType::RoomMember))
|
||||
.and_then(|m| m.get(state_key.as_str()).map(|m| m.clone().cast()))
|
||||
{
|
||||
Ok(Some(RawMemberEvent::Stripped(e)))
|
||||
} else if let Some(e) = self
|
||||
.room_state
|
||||
.get(room_id)
|
||||
.as_ref()
|
||||
.and_then(|events| events.get(&StateEventType::RoomMember))
|
||||
.and_then(|m| m.get(state_key.as_str()).map(|m| m.clone().cast()))
|
||||
{
|
||||
Ok(Some(RawMemberEvent::Sync(e)))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
self.get_state_event(room_id, StateEventType::RoomMember, state_key.as_str())
|
||||
.await
|
||||
.map(|opt| opt.map(|raw| raw.cast()))
|
||||
}
|
||||
|
||||
/// Get the user IDs for the given room with the given memberships and
|
||||
@@ -588,7 +596,7 @@ impl StateStore for MemoryStore {
|
||||
room_id: &RoomId,
|
||||
event_type: StateEventType,
|
||||
state_key: &str,
|
||||
) -> Result<Option<Raw<AnySyncStateEvent>>> {
|
||||
) -> Result<Option<RawAnySyncOrStrippedState>> {
|
||||
self.get_state_event(room_id, event_type, state_key).await
|
||||
}
|
||||
|
||||
@@ -596,7 +604,7 @@ impl StateStore for MemoryStore {
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
event_type: StateEventType,
|
||||
) -> Result<Vec<Raw<AnySyncStateEvent>>> {
|
||||
) -> Result<Vec<RawAnySyncOrStrippedState>> {
|
||||
self.get_state_events(room_id, event_type).await
|
||||
}
|
||||
|
||||
|
||||
@@ -20,11 +20,10 @@ use ruma::{
|
||||
events::{
|
||||
presence::PresenceEvent,
|
||||
receipt::{Receipt, ReceiptThread, ReceiptType},
|
||||
AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent, AnySyncStateEvent, EmptyStateKey,
|
||||
GlobalAccountDataEvent, GlobalAccountDataEventContent, GlobalAccountDataEventType,
|
||||
RedactContent, RedactedStateEventContent, RoomAccountDataEvent,
|
||||
RoomAccountDataEventContent, RoomAccountDataEventType, StateEventType, StaticEventContent,
|
||||
StaticStateEventContent, SyncStateEvent,
|
||||
AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent, EmptyStateKey, GlobalAccountDataEvent,
|
||||
GlobalAccountDataEventContent, GlobalAccountDataEventType, RedactContent,
|
||||
RedactedStateEventContent, RoomAccountDataEvent, RoomAccountDataEventContent,
|
||||
RoomAccountDataEventType, StateEventType, StaticEventContent, StaticStateEventContent,
|
||||
},
|
||||
serde::Raw,
|
||||
EventId, MxcUri, OwnedEventId, OwnedUserId, RoomId, UserId,
|
||||
@@ -32,8 +31,9 @@ use ruma::{
|
||||
|
||||
use super::{StateChanges, StoreError};
|
||||
use crate::{
|
||||
deserialized_responses::RawMemberEvent, media::MediaRequest, MinimalRoomMemberEvent, RoomInfo,
|
||||
RoomMemberships,
|
||||
deserialized_responses::{RawAnySyncOrStrippedState, RawMemberEvent, RawSyncOrStrippedState},
|
||||
media::MediaRequest,
|
||||
MinimalRoomMemberEvent, RoomInfo, RoomMemberships,
|
||||
};
|
||||
|
||||
/// An abstract state store trait that can be used to implement different stores
|
||||
@@ -102,7 +102,7 @@ pub trait StateStore: AsyncTraitDeps {
|
||||
room_id: &RoomId,
|
||||
event_type: StateEventType,
|
||||
state_key: &str,
|
||||
) -> Result<Option<Raw<AnySyncStateEvent>>, Self::Error>;
|
||||
) -> Result<Option<RawAnySyncOrStrippedState>, Self::Error>;
|
||||
|
||||
/// Get a list of state events for a given room and `StateEventType`.
|
||||
///
|
||||
@@ -115,7 +115,7 @@ pub trait StateStore: AsyncTraitDeps {
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
event_type: StateEventType,
|
||||
) -> Result<Vec<Raw<AnySyncStateEvent>>, Self::Error>;
|
||||
) -> Result<Vec<RawAnySyncOrStrippedState>, Self::Error>;
|
||||
|
||||
/// Get the current profile for the given user in the given room.
|
||||
///
|
||||
@@ -370,7 +370,7 @@ impl<T: StateStore> StateStore for EraseStateStoreError<T> {
|
||||
room_id: &RoomId,
|
||||
event_type: StateEventType,
|
||||
state_key: &str,
|
||||
) -> Result<Option<Raw<AnySyncStateEvent>>, Self::Error> {
|
||||
) -> Result<Option<RawAnySyncOrStrippedState>, Self::Error> {
|
||||
self.0.get_state_event(room_id, event_type, state_key).await.map_err(Into::into)
|
||||
}
|
||||
|
||||
@@ -378,7 +378,7 @@ impl<T: StateStore> StateStore for EraseStateStoreError<T> {
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
event_type: StateEventType,
|
||||
) -> Result<Vec<Raw<AnySyncStateEvent>>, Self::Error> {
|
||||
) -> Result<Vec<RawAnySyncOrStrippedState>, Self::Error> {
|
||||
self.0.get_state_events(room_id, event_type).await.map_err(Into::into)
|
||||
}
|
||||
|
||||
@@ -530,12 +530,12 @@ pub trait StateStoreExt: StateStore {
|
||||
async fn get_state_event_static<C>(
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
) -> Result<Option<Raw<SyncStateEvent<C>>>, Self::Error>
|
||||
) -> Result<Option<RawSyncOrStrippedState<C>>, Self::Error>
|
||||
where
|
||||
C: StaticEventContent + StaticStateEventContent<StateKey = EmptyStateKey> + RedactContent,
|
||||
C::Redacted: RedactedStateEventContent,
|
||||
{
|
||||
Ok(self.get_state_event(room_id, C::TYPE.into(), "").await?.map(Raw::cast))
|
||||
Ok(self.get_state_event(room_id, C::TYPE.into(), "").await?.map(|raw| raw.cast()))
|
||||
}
|
||||
|
||||
/// Get a specific state event of statically-known type.
|
||||
@@ -547,14 +547,17 @@ pub trait StateStoreExt: StateStore {
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
state_key: &K,
|
||||
) -> Result<Option<Raw<SyncStateEvent<C>>>, Self::Error>
|
||||
) -> Result<Option<RawSyncOrStrippedState<C>>, Self::Error>
|
||||
where
|
||||
C: StaticEventContent + StaticStateEventContent + RedactContent,
|
||||
C::StateKey: Borrow<K>,
|
||||
C::Redacted: RedactedStateEventContent,
|
||||
K: AsRef<str> + ?Sized + Sync,
|
||||
{
|
||||
Ok(self.get_state_event(room_id, C::TYPE.into(), state_key.as_ref()).await?.map(Raw::cast))
|
||||
Ok(self
|
||||
.get_state_event(room_id, C::TYPE.into(), state_key.as_ref())
|
||||
.await?
|
||||
.map(|raw| raw.cast()))
|
||||
}
|
||||
|
||||
/// Get a list of state events of a statically-known type for a given room.
|
||||
@@ -565,7 +568,7 @@ pub trait StateStoreExt: StateStore {
|
||||
async fn get_state_events_static<C>(
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
) -> Result<Vec<Raw<SyncStateEvent<C>>>, Self::Error>
|
||||
) -> Result<Vec<RawSyncOrStrippedState<C>>, Self::Error>
|
||||
where
|
||||
C: StaticEventContent + StaticStateEventContent + RedactContent,
|
||||
C::Redacted: RedactedStateEventContent,
|
||||
@@ -575,7 +578,7 @@ pub trait StateStoreExt: StateStore {
|
||||
.get_state_events(room_id, C::TYPE.into())
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(Raw::cast)
|
||||
.map(|raw| raw.cast())
|
||||
.collect())
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ use async_trait::async_trait;
|
||||
use gloo_utils::format::JsValueSerdeExt;
|
||||
use indexed_db_futures::prelude::*;
|
||||
use matrix_sdk_base::{
|
||||
deserialized_responses::RawMemberEvent,
|
||||
deserialized_responses::{RawAnySyncOrStrippedState, RawMemberEvent},
|
||||
media::{MediaRequest, UniqueKey},
|
||||
store::{StateChanges, StateStore, StoreError},
|
||||
MinimalStateEvent, RoomInfo, RoomMemberships, StateStoreDataKey, StateStoreDataValue,
|
||||
@@ -820,21 +820,52 @@ impl_state_store! {
|
||||
room_id: &RoomId,
|
||||
event_type: StateEventType,
|
||||
state_key: &str,
|
||||
) -> Result<Option<Raw<AnySyncStateEvent>>> {
|
||||
self.inner
|
||||
) -> Result<Option<RawAnySyncOrStrippedState>> {
|
||||
if let Some(e) = self
|
||||
.inner
|
||||
.transaction_on_one_with_mode(keys::STRIPPED_ROOM_STATE, IdbTransactionMode::Readonly)?
|
||||
.object_store(keys::STRIPPED_ROOM_STATE)?
|
||||
.get(&self.encode_key(keys::STRIPPED_ROOM_STATE, (room_id, &event_type, state_key)))?
|
||||
.await?
|
||||
.map(|f| self.deserialize_event(&f))
|
||||
.transpose()?
|
||||
{
|
||||
Ok(Some(RawAnySyncOrStrippedState::Stripped(e)))
|
||||
} else if let Some(e) = self
|
||||
.inner
|
||||
.transaction_on_one_with_mode(keys::ROOM_STATE, IdbTransactionMode::Readonly)?
|
||||
.object_store(keys::ROOM_STATE)?
|
||||
.get(&self.encode_key(keys::ROOM_STATE, (room_id, event_type, state_key)))?
|
||||
.await?
|
||||
.map(|f| self.deserialize_event(&f))
|
||||
.transpose()
|
||||
.transpose()?
|
||||
{
|
||||
Ok(Some(RawAnySyncOrStrippedState::Sync(e)))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_state_events(
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
event_type: StateEventType,
|
||||
) -> Result<Vec<Raw<AnySyncStateEvent>>> {
|
||||
) -> Result<Vec<RawAnySyncOrStrippedState>> {
|
||||
let stripped_range = self.encode_to_range(keys::STRIPPED_ROOM_STATE, (room_id, &event_type))?;
|
||||
let stripped_events = self
|
||||
.inner
|
||||
.transaction_on_one_with_mode(keys::STRIPPED_ROOM_STATE, IdbTransactionMode::Readonly)?
|
||||
.object_store(keys::STRIPPED_ROOM_STATE)?
|
||||
.get_all_with_key(&stripped_range)?
|
||||
.await?
|
||||
.iter()
|
||||
.filter_map(|f| self.deserialize_event(&f).ok().map(RawAnySyncOrStrippedState::Stripped))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
if !stripped_events.is_empty() {
|
||||
return Ok(stripped_events)
|
||||
}
|
||||
|
||||
let range = self.encode_to_range(keys::ROOM_STATE, (room_id, event_type))?;
|
||||
Ok(self
|
||||
.inner
|
||||
@@ -843,7 +874,7 @@ impl_state_store! {
|
||||
.get_all_with_key(&range)?
|
||||
.await?
|
||||
.iter()
|
||||
.filter_map(|f| self.deserialize_event(&f).ok())
|
||||
.filter_map(|f| self.deserialize_event(&f).ok().map(RawAnySyncOrStrippedState::Sync))
|
||||
.collect::<Vec<_>>())
|
||||
}
|
||||
|
||||
|
||||
@@ -402,7 +402,10 @@ mod test {
|
||||
use matrix_sdk_test::{async_test, test_json};
|
||||
use ruma::{
|
||||
events::{
|
||||
room::member::{StrippedRoomMemberEvent, SyncRoomMemberEvent},
|
||||
room::{
|
||||
member::{StrippedRoomMemberEvent, SyncRoomMemberEvent},
|
||||
topic::RoomTopicEventContent,
|
||||
},
|
||||
AnySyncStateEvent, StateEventType,
|
||||
},
|
||||
room_id,
|
||||
@@ -553,7 +556,7 @@ mod test {
|
||||
.unwrap();
|
||||
let event =
|
||||
store.get_state_event(room_id, StateEventType::RoomTopic, "").await.unwrap().unwrap();
|
||||
event.deserialize().unwrap();
|
||||
event.cast::<RoomTopicEventContent>().deserialize().unwrap();
|
||||
}
|
||||
|
||||
#[async_test]
|
||||
|
||||
@@ -23,7 +23,7 @@ use async_trait::async_trait;
|
||||
use futures_core::stream::Stream;
|
||||
use futures_util::stream::{self, TryStreamExt};
|
||||
use matrix_sdk_base::{
|
||||
deserialized_responses::RawMemberEvent,
|
||||
deserialized_responses::{RawAnySyncOrStrippedState, RawMemberEvent},
|
||||
media::{MediaRequest, UniqueKey},
|
||||
store::{Result as StoreResult, StateChanges, StateStore, StoreError},
|
||||
MinimalStateEvent, RoomInfo, RoomMemberships, StateStoreDataKey, StateStoreDataValue,
|
||||
@@ -787,11 +787,26 @@ impl SledStateStore {
|
||||
room_id: &RoomId,
|
||||
event_type: StateEventType,
|
||||
state_key: &str,
|
||||
) -> Result<Option<Raw<AnySyncStateEvent>>> {
|
||||
) -> Result<Option<RawAnySyncOrStrippedState>> {
|
||||
let db = self.clone();
|
||||
let key = self.encode_key(keys::ROOM_STATE, (room_id, event_type.to_string(), state_key));
|
||||
let stripped_key = self
|
||||
.encode_key(keys::STRIPPED_ROOM_STATE, (room_id, event_type.to_string(), state_key));
|
||||
spawn_blocking(move || {
|
||||
db.room_state.get(key)?.map(|e| db.deserialize_value(&e)).transpose()
|
||||
if let Some(e) = db
|
||||
.stripped_room_state
|
||||
.get(stripped_key)?
|
||||
.map(|v| db.deserialize_value(&v))
|
||||
.transpose()?
|
||||
{
|
||||
Ok(Some(RawAnySyncOrStrippedState::Stripped(e)))
|
||||
} else if let Some(e) =
|
||||
db.room_state.get(key)?.map(|v| db.deserialize_value(&v)).transpose()?
|
||||
{
|
||||
Ok(Some(RawAnySyncOrStrippedState::Sync(e)))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
})
|
||||
.await?
|
||||
}
|
||||
@@ -800,13 +815,31 @@ impl SledStateStore {
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
event_type: StateEventType,
|
||||
) -> Result<Vec<Raw<AnySyncStateEvent>>> {
|
||||
) -> Result<Vec<RawAnySyncOrStrippedState>> {
|
||||
let db = self.clone();
|
||||
let key = self.encode_key(keys::ROOM_STATE, (room_id, event_type.to_string()));
|
||||
let stripped_key =
|
||||
self.encode_key(keys::STRIPPED_ROOM_STATE, (room_id, event_type.to_string()));
|
||||
spawn_blocking(move || {
|
||||
let stripped_events = db
|
||||
.stripped_room_state
|
||||
.scan_prefix(stripped_key)
|
||||
.flat_map(|e| {
|
||||
e.map(|(_, e)| {
|
||||
db.deserialize_value(&e).map(RawAnySyncOrStrippedState::Stripped)
|
||||
})
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
if !stripped_events.is_empty() {
|
||||
return Ok(stripped_events);
|
||||
}
|
||||
|
||||
db.room_state
|
||||
.scan_prefix(key)
|
||||
.flat_map(|e| e.map(|(_, e)| db.deserialize_value(&e)))
|
||||
.flat_map(|e| {
|
||||
e.map(|(_, e)| db.deserialize_value(&e).map(RawAnySyncOrStrippedState::Sync))
|
||||
})
|
||||
.collect::<Result<_, _>>()
|
||||
})
|
||||
.await?
|
||||
@@ -828,30 +861,9 @@ impl SledStateStore {
|
||||
room_id: &RoomId,
|
||||
state_key: &UserId,
|
||||
) -> Result<Option<RawMemberEvent>> {
|
||||
let db = self.clone();
|
||||
let key =
|
||||
self.encode_key(keys::ROOM_STATE, (room_id, StateEventType::RoomMember, state_key));
|
||||
let stripped_key = self.encode_key(
|
||||
keys::STRIPPED_ROOM_STATE,
|
||||
(room_id, StateEventType::RoomMember, state_key),
|
||||
);
|
||||
spawn_blocking(move || {
|
||||
if let Some(e) = db
|
||||
.stripped_room_state
|
||||
.get(stripped_key)?
|
||||
.map(|v| db.deserialize_value(&v))
|
||||
.transpose()?
|
||||
{
|
||||
Ok(Some(RawMemberEvent::Stripped(e)))
|
||||
} else if let Some(e) =
|
||||
db.room_state.get(key)?.map(|v| db.deserialize_value(&v)).transpose()?
|
||||
{
|
||||
Ok(Some(RawMemberEvent::Sync(e)))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
})
|
||||
.await?
|
||||
self.get_state_event(room_id, StateEventType::RoomMember, state_key.as_str())
|
||||
.await
|
||||
.map(|opt| opt.map(|raw| raw.cast()))
|
||||
}
|
||||
|
||||
/// Get the user IDs for the given room with the given memberships and
|
||||
@@ -1230,7 +1242,7 @@ impl StateStore for SledStateStore {
|
||||
room_id: &RoomId,
|
||||
event_type: StateEventType,
|
||||
state_key: &str,
|
||||
) -> StoreResult<Option<Raw<AnySyncStateEvent>>> {
|
||||
) -> StoreResult<Option<RawAnySyncOrStrippedState>> {
|
||||
self.get_state_event(room_id, event_type, state_key).await.map_err(Into::into)
|
||||
}
|
||||
|
||||
@@ -1238,7 +1250,7 @@ impl StateStore for SledStateStore {
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
event_type: StateEventType,
|
||||
) -> StoreResult<Vec<Raw<AnySyncStateEvent>>> {
|
||||
) -> StoreResult<Vec<RawAnySyncOrStrippedState>> {
|
||||
self.get_state_events(room_id, event_type).await.map_err(Into::into)
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ use std::{
|
||||
use async_trait::async_trait;
|
||||
use deadpool_sqlite::{Object as SqliteConn, Pool as SqlitePool, Runtime};
|
||||
use matrix_sdk_base::{
|
||||
deserialized_responses::RawMemberEvent,
|
||||
deserialized_responses::{RawAnySyncOrStrippedState, RawMemberEvent},
|
||||
media::{MediaRequest, UniqueKey},
|
||||
RoomInfo, RoomMemberships, RoomState, StateChanges, StateStore, StateStoreDataKey,
|
||||
StateStoreDataValue,
|
||||
@@ -547,24 +547,6 @@ trait SqliteObjectStateStoreExt: SqliteObjectExt {
|
||||
.await?)
|
||||
}
|
||||
|
||||
async fn get_state_event(
|
||||
&self,
|
||||
room_id: Key,
|
||||
event_type: Key,
|
||||
state_key: Key,
|
||||
stripped: bool,
|
||||
) -> Result<Option<Vec<u8>>> {
|
||||
Ok(self
|
||||
.query_row(
|
||||
"SELECT data FROM state_event
|
||||
WHERE room_id = ? AND event_type = ? AND state_key = ? AND stripped = ?",
|
||||
(room_id, event_type, state_key, stripped),
|
||||
|row| row.get(0),
|
||||
)
|
||||
.await
|
||||
.optional()?)
|
||||
}
|
||||
|
||||
async fn get_maybe_stripped_state_event(
|
||||
&self,
|
||||
room_id: Key,
|
||||
@@ -582,12 +564,20 @@ trait SqliteObjectStateStoreExt: SqliteObjectExt {
|
||||
.optional()?)
|
||||
}
|
||||
|
||||
async fn get_state_events(&self, room_id: Key, event_type: Key) -> Result<Vec<Vec<u8>>> {
|
||||
async fn get_maybe_stripped_state_events(
|
||||
&self,
|
||||
room_id: Key,
|
||||
event_type: Key,
|
||||
) -> Result<Vec<(bool, Vec<u8>)>> {
|
||||
Ok(self
|
||||
.prepare(
|
||||
"SELECT data FROM state_event
|
||||
WHERE room_id = ? AND event_type = ? AND stripped = FALSE",
|
||||
|mut stmt| stmt.query((room_id, event_type))?.mapped(|row| row.get(0)).collect(),
|
||||
"SELECT stripped, data FROM state_event
|
||||
WHERE room_id = ? AND event_type = ?",
|
||||
|mut stmt| {
|
||||
stmt.query((room_id, event_type))?
|
||||
.mapped(|row| Ok((row.get(0)?, row.get(1)?)))
|
||||
.collect()
|
||||
},
|
||||
)
|
||||
.await?)
|
||||
}
|
||||
@@ -1080,15 +1070,23 @@ impl StateStore for SqliteStateStore {
|
||||
room_id: &RoomId,
|
||||
event_type: StateEventType,
|
||||
state_key: &str,
|
||||
) -> Result<Option<Raw<AnySyncStateEvent>>> {
|
||||
) -> Result<Option<RawAnySyncOrStrippedState>> {
|
||||
let room_id = self.encode_key(keys::STATE_EVENT, room_id);
|
||||
let event_type = self.encode_key(keys::STATE_EVENT, event_type.to_string());
|
||||
let state_key = self.encode_key(keys::STATE_EVENT, state_key);
|
||||
self.acquire()
|
||||
.await?
|
||||
.get_state_event(room_id, event_type, state_key, false)
|
||||
.get_maybe_stripped_state_event(room_id, event_type, state_key)
|
||||
.await?
|
||||
.map(|data| self.deserialize_json(&data))
|
||||
.map(|(stripped, data)| {
|
||||
let ev = if stripped {
|
||||
RawAnySyncOrStrippedState::Stripped(self.deserialize_json(&data)?)
|
||||
} else {
|
||||
RawAnySyncOrStrippedState::Sync(self.deserialize_json(&data)?)
|
||||
};
|
||||
|
||||
Ok(ev)
|
||||
})
|
||||
.transpose()
|
||||
}
|
||||
|
||||
@@ -1096,15 +1094,23 @@ impl StateStore for SqliteStateStore {
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
event_type: StateEventType,
|
||||
) -> Result<Vec<Raw<AnySyncStateEvent>>> {
|
||||
) -> Result<Vec<RawAnySyncOrStrippedState>> {
|
||||
let room_id = self.encode_key(keys::STATE_EVENT, room_id);
|
||||
let event_type = self.encode_key(keys::STATE_EVENT, event_type.to_string());
|
||||
self.acquire()
|
||||
.await?
|
||||
.get_state_events(room_id, event_type)
|
||||
.get_maybe_stripped_state_events(room_id, event_type)
|
||||
.await?
|
||||
.iter()
|
||||
.map(|data| self.deserialize_json(data))
|
||||
.into_iter()
|
||||
.map(|(stripped, data)| {
|
||||
let ev = if stripped {
|
||||
RawAnySyncOrStrippedState::Stripped(self.deserialize_json(&data)?)
|
||||
} else {
|
||||
RawAnySyncOrStrippedState::Sync(self.deserialize_json(&data)?)
|
||||
};
|
||||
|
||||
Ok(ev)
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,8 @@
|
||||
- `Common::active_members(_no_sync)` and `Common::joined_members(_no_sync)` are deprecated.
|
||||
- `matrix-sdk-sqlite` is the new default store implementation outside of WASM, behind the `sqlite` feature.
|
||||
- The `sled` feature was removed. It is still possible to use `matrix-sdk-sled` as a custom store.
|
||||
- The `Common` methods to retrieve state events can now return a sync or stripped event, so it can be used
|
||||
for invited rooms too.
|
||||
|
||||
# 0.6.2
|
||||
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
use std::{borrow::Borrow, collections::BTreeMap, fmt, ops::Deref, sync::Arc};
|
||||
|
||||
use matrix_sdk_base::{
|
||||
deserialized_responses::{MembersResponse, TimelineEvent},
|
||||
deserialized_responses::{
|
||||
MembersResponse, RawAnySyncOrStrippedState, RawSyncOrStrippedState, SyncOrStrippedState,
|
||||
TimelineEvent,
|
||||
},
|
||||
store::StateStoreExt,
|
||||
RoomMemberships, StateChanges,
|
||||
};
|
||||
@@ -35,10 +38,9 @@ use ruma::{
|
||||
MediaSource,
|
||||
},
|
||||
tag::{TagInfo, TagName},
|
||||
AnyRoomAccountDataEvent, AnyStateEvent, AnySyncStateEvent, EmptyStateKey, RedactContent,
|
||||
AnyRoomAccountDataEvent, AnyStateEvent, EmptyStateKey, RedactContent,
|
||||
RedactedStateEventContent, RoomAccountDataEvent, RoomAccountDataEventContent,
|
||||
RoomAccountDataEventType, StateEventType, StaticEventContent, StaticStateEventContent,
|
||||
SyncStateEvent,
|
||||
},
|
||||
push::{Action, PushConditionRoomCtx},
|
||||
serde::Raw,
|
||||
@@ -539,7 +541,7 @@ impl Common {
|
||||
pub async fn get_state_events(
|
||||
&self,
|
||||
event_type: StateEventType,
|
||||
) -> Result<Vec<Raw<AnySyncStateEvent>>> {
|
||||
) -> Result<Vec<RawAnySyncOrStrippedState>> {
|
||||
self.client.store().get_state_events(self.room_id(), event_type).await.map_err(Into::into)
|
||||
}
|
||||
|
||||
@@ -551,15 +553,15 @@ impl Common {
|
||||
/// # async {
|
||||
/// # let room: matrix_sdk::room::Common = todo!();
|
||||
/// use matrix_sdk::ruma::{
|
||||
/// events::room::member::SyncRoomMemberEvent, serde::Raw,
|
||||
/// events::room::member::RoomMemberEventContent, serde::Raw,
|
||||
/// };
|
||||
///
|
||||
/// let room_members: Vec<Raw<SyncRoomMemberEvent>> =
|
||||
/// room.get_state_events_static().await?;
|
||||
/// let room_members =
|
||||
/// room.get_state_events_static::<RoomMemberEventContent>().await?;
|
||||
/// # anyhow::Ok(())
|
||||
/// # };
|
||||
/// ```
|
||||
pub async fn get_state_events_static<C>(&self) -> Result<Vec<Raw<SyncStateEvent<C>>>>
|
||||
pub async fn get_state_events_static<C>(&self) -> Result<Vec<RawSyncOrStrippedState<C>>>
|
||||
where
|
||||
C: StaticEventContent + StaticStateEventContent + RedactContent,
|
||||
C::Redacted: RedactedStateEventContent,
|
||||
@@ -572,7 +574,7 @@ impl Common {
|
||||
&self,
|
||||
event_type: StateEventType,
|
||||
state_key: &str,
|
||||
) -> Result<Option<Raw<AnySyncStateEvent>>> {
|
||||
) -> Result<Option<RawAnySyncOrStrippedState>> {
|
||||
self.client
|
||||
.store()
|
||||
.get_state_event(self.room_id(), event_type, state_key)
|
||||
@@ -588,17 +590,17 @@ impl Common {
|
||||
/// ```no_run
|
||||
/// # async {
|
||||
/// # let room: matrix_sdk::room::Common = todo!();
|
||||
/// use matrix_sdk::ruma::events::room::power_levels::SyncRoomPowerLevelsEvent;
|
||||
/// use matrix_sdk::ruma::events::room::power_levels::RoomPowerLevelsEventContent;
|
||||
///
|
||||
/// let power_levels: SyncRoomPowerLevelsEvent = room
|
||||
/// .get_state_event_static()
|
||||
/// let power_levels = room
|
||||
/// .get_state_event_static::<RoomPowerLevelsEventContent>()
|
||||
/// .await?
|
||||
/// .expect("every room has a power_levels event")
|
||||
/// .deserialize()?;
|
||||
/// # anyhow::Ok(())
|
||||
/// # };
|
||||
/// ```
|
||||
pub async fn get_state_event_static<C>(&self) -> Result<Option<Raw<SyncStateEvent<C>>>>
|
||||
pub async fn get_state_event_static<C>(&self) -> Result<Option<RawSyncOrStrippedState<C>>>
|
||||
where
|
||||
C: StaticEventContent + StaticStateEventContent<StateKey = EmptyStateKey> + RedactContent,
|
||||
C::Redacted: RedactedStateEventContent,
|
||||
@@ -614,11 +616,13 @@ impl Common {
|
||||
/// # async {
|
||||
/// # let room: matrix_sdk::room::Common = todo!();
|
||||
/// use matrix_sdk::ruma::{
|
||||
/// events::room::member::SyncRoomMemberEvent, serde::Raw, user_id,
|
||||
/// events::room::member::RoomMemberEventContent, serde::Raw, user_id,
|
||||
/// };
|
||||
///
|
||||
/// let member_event: Option<Raw<SyncRoomMemberEvent>> = room
|
||||
/// .get_state_event_static_for_key(user_id!("@alice:example.org"))
|
||||
/// let member_event = room
|
||||
/// .get_state_event_static_for_key::<RoomMemberEventContent, _>(user_id!(
|
||||
/// "@alice:example.org"
|
||||
/// ))
|
||||
/// .await?;
|
||||
/// # anyhow::Ok(())
|
||||
/// # };
|
||||
@@ -626,7 +630,7 @@ impl Common {
|
||||
pub async fn get_state_event_static_for_key<C, K>(
|
||||
&self,
|
||||
state_key: &K,
|
||||
) -> Result<Option<Raw<SyncStateEvent<C>>>>
|
||||
) -> Result<Option<RawSyncOrStrippedState<C>>>
|
||||
where
|
||||
C: StaticEventContent + StaticStateEventContent + RedactContent,
|
||||
C::StateKey: Borrow<K>,
|
||||
@@ -839,7 +843,10 @@ impl Common {
|
||||
.get_state_event_static::<RoomServerAclEventContent>()
|
||||
.await?
|
||||
.and_then(|ev| ev.deserialize().ok());
|
||||
let acl = acl_ev.as_ref().and_then(|ev| ev.as_original()).map(|ev| &ev.content);
|
||||
let acl = acl_ev.as_ref().and_then(|ev| match ev {
|
||||
SyncOrStrippedState::Sync(ev) => ev.as_original().map(|ev| &ev.content),
|
||||
SyncOrStrippedState::Stripped(ev) => Some(&ev.content),
|
||||
});
|
||||
|
||||
// Filter out server names that:
|
||||
// - Are blocked due to server ACLs
|
||||
|
||||
@@ -171,7 +171,10 @@ async fn test_state_event_getting() {
|
||||
.deserialize()
|
||||
.unwrap();
|
||||
|
||||
assert_matches::assert_matches!(encryption_event, AnySyncStateEvent::RoomEncryption(_));
|
||||
assert_matches::assert_matches!(
|
||||
encryption_event.as_sync(),
|
||||
Some(AnySyncStateEvent::RoomEncryption(_))
|
||||
);
|
||||
}
|
||||
|
||||
#[async_test]
|
||||
|
||||
@@ -4,10 +4,7 @@ use matrix_sdk::{
|
||||
config::SyncSettings,
|
||||
ruma::{
|
||||
api::client::room::create_room::v3::Request as CreateRoomRequest,
|
||||
events::{
|
||||
room::name::{RoomNameEventContent, SyncRoomNameEvent},
|
||||
StateEventType,
|
||||
},
|
||||
events::{room::name::RoomNameEventContent, StateEventType},
|
||||
},
|
||||
Client,
|
||||
};
|
||||
@@ -64,13 +61,14 @@ async fn test_redacting_name() -> Result<()> {
|
||||
|
||||
let raw_event =
|
||||
room.get_state_event(StateEventType::RoomName, "").await?.expect("Room Name not found");
|
||||
let room_name_event: SyncRoomNameEvent = raw_event.deserialize_as()?;
|
||||
let room_name_event = raw_event.cast::<RoomNameEventContent>().deserialize()?;
|
||||
let sync_room_name_event = room_name_event.as_sync().expect("event is sync event");
|
||||
assert!(
|
||||
room_name_event.as_original().expect("event exists").content.name.is_some(),
|
||||
sync_room_name_event.as_original().expect("event exists").content.name.is_some(),
|
||||
"Event not found"
|
||||
);
|
||||
|
||||
room.redact(room_name_event.event_id(), None, None).await?;
|
||||
room.redact(sync_room_name_event.event_id(), None, None).await?;
|
||||
// sync up.
|
||||
for _ in 0..=10 {
|
||||
// we call sync up to ten times to give the server time to flush other
|
||||
@@ -84,10 +82,17 @@ async fn test_redacting_name() -> Result<()> {
|
||||
|
||||
let raw_event =
|
||||
room.get_state_event(StateEventType::RoomName, "").await?.expect("Room Name not found");
|
||||
let room_name_event: SyncRoomNameEvent = raw_event.deserialize_as()?;
|
||||
let room_name_event = raw_event.cast::<RoomNameEventContent>().deserialize()?;
|
||||
// Name content has been redacted
|
||||
assert!(
|
||||
room_name_event.as_original().expect("event exists").content.name.is_none(),
|
||||
room_name_event
|
||||
.as_sync()
|
||||
.expect("event is sync event")
|
||||
.as_original()
|
||||
.expect("event exists")
|
||||
.content
|
||||
.name
|
||||
.is_none(),
|
||||
"Event hasn't been redacted"
|
||||
);
|
||||
|
||||
@@ -132,14 +137,18 @@ async fn test_redacting_name_static() -> Result<()> {
|
||||
|
||||
// check state event.
|
||||
|
||||
let room_name_event: SyncRoomNameEvent =
|
||||
room.get_state_event_static().await?.expect("Room Name not found").deserialize()?;
|
||||
let room_name_event = room
|
||||
.get_state_event_static::<RoomNameEventContent>()
|
||||
.await?
|
||||
.expect("Room Name not found")
|
||||
.deserialize()?;
|
||||
let sync_room_name_event = room_name_event.as_sync().expect("event is sync event");
|
||||
assert!(
|
||||
room_name_event.as_original().expect("event exists").content.name.is_some(),
|
||||
sync_room_name_event.as_original().expect("event exists").content.name.is_some(),
|
||||
"Event not found"
|
||||
);
|
||||
|
||||
room.redact(room_name_event.event_id(), None, None).await?;
|
||||
room.redact(sync_room_name_event.event_id(), None, None).await?;
|
||||
// we sync up.
|
||||
for _ in 0..=10 {
|
||||
// we call sync up to ten times to give the server time to flush other
|
||||
@@ -151,11 +160,21 @@ async fn test_redacting_name_static() -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
let room_name_event: SyncRoomNameEvent =
|
||||
room.get_state_event_static().await?.expect("Room Name not found").deserialize()?;
|
||||
let room_name_event = room
|
||||
.get_state_event_static::<RoomNameEventContent>()
|
||||
.await?
|
||||
.expect("Room Name not found")
|
||||
.deserialize()?;
|
||||
// Name content has been redacted
|
||||
assert!(
|
||||
room_name_event.as_original().expect("event exists").content.name.is_none(),
|
||||
room_name_event
|
||||
.as_sync()
|
||||
.expect("event is sync event")
|
||||
.as_original()
|
||||
.expect("event exists")
|
||||
.content
|
||||
.name
|
||||
.is_none(),
|
||||
"Event hasn't been redacted"
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user