mirror of
https://github.com/matrix-org/matrix-rust-sdk.git
synced 2026-05-06 15:04:11 -04:00
feat(base): Properly handle redacted m.room.member events
This commit is contained in:
committed by
Jonas Platte
parent
a2fb420635
commit
0fad7b60a9
@@ -56,16 +56,16 @@ use ruma::{
|
||||
api::client::{self as api, push::get_notifications::v3::Notification},
|
||||
events::{
|
||||
push_rules::PushRulesEvent,
|
||||
room::member::{MembershipState, OriginalSyncRoomMemberEvent, RoomMemberEvent},
|
||||
room::member::{MembershipState, SyncRoomMemberEvent},
|
||||
AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent, AnyStrippedStateEvent,
|
||||
AnySyncEphemeralRoomEvent, AnySyncRoomEvent, AnySyncStateEvent, GlobalAccountDataEventType,
|
||||
StateEventType, SyncStateEvent,
|
||||
StateEventType,
|
||||
},
|
||||
push::{Action, PushConditionRoomCtx, Ruleset},
|
||||
serde::Raw,
|
||||
MilliSecondsSinceUnixEpoch, OwnedUserId, RoomId, UInt, UserId,
|
||||
};
|
||||
use tracing::{info, trace, warn};
|
||||
use tracing::{debug, info, trace, warn};
|
||||
|
||||
#[cfg(feature = "e2e-encryption")]
|
||||
use crate::error::Error;
|
||||
@@ -281,15 +281,15 @@ impl BaseClient {
|
||||
#[allow(clippy::single_match)]
|
||||
match &e {
|
||||
AnySyncRoomEvent::State(s) => match s {
|
||||
AnySyncStateEvent::RoomMember(SyncStateEvent::Original(member)) => {
|
||||
AnySyncStateEvent::RoomMember(member) => {
|
||||
ambiguity_cache.handle_event(changes, room_id, member).await?;
|
||||
|
||||
match member.content.membership {
|
||||
match member.membership() {
|
||||
MembershipState::Join | MembershipState::Invite => {
|
||||
user_ids.insert(member.state_key.clone());
|
||||
user_ids.insert(member.state_key().to_owned());
|
||||
}
|
||||
_ => {
|
||||
user_ids.remove(&member.state_key);
|
||||
user_ids.remove(member.state_key());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -297,19 +297,19 @@ impl BaseClient {
|
||||
// of profiles that the member set themselves to avoid
|
||||
// having confusing profile changes when a member gets
|
||||
// kicked/banned.
|
||||
if member.state_key == member.sender {
|
||||
if member.state_key() == member.sender() {
|
||||
changes
|
||||
.profiles
|
||||
.entry(room_id.to_owned())
|
||||
.or_default()
|
||||
.insert(member.sender.clone(), member.content.clone());
|
||||
.insert(member.sender().to_owned(), member.into());
|
||||
}
|
||||
|
||||
changes
|
||||
.members
|
||||
.entry(room_id.to_owned())
|
||||
.or_default()
|
||||
.insert(member.state_key.clone(), member.to_owned());
|
||||
.insert(member.state_key().to_owned(), member.clone());
|
||||
}
|
||||
_ => {
|
||||
room_info.handle_state_event(s);
|
||||
@@ -470,12 +470,12 @@ impl BaseClient {
|
||||
|
||||
room_info.handle_state_event(&event);
|
||||
|
||||
if let AnySyncStateEvent::RoomMember(SyncStateEvent::Original(member)) = event {
|
||||
if let AnySyncStateEvent::RoomMember(member) = event {
|
||||
ambiguity_cache.handle_event(changes, &room_id, &member).await?;
|
||||
|
||||
match member.content.membership {
|
||||
match member.membership() {
|
||||
MembershipState::Join | MembershipState::Invite => {
|
||||
user_ids.insert(member.state_key.clone());
|
||||
user_ids.insert(member.state_key().to_owned());
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
@@ -484,11 +484,11 @@ impl BaseClient {
|
||||
// of profiles that the member set themselves to avoid
|
||||
// having confusing profile changes when a member gets
|
||||
// kicked/banned.
|
||||
if member.state_key == member.sender {
|
||||
profiles.insert(member.sender.clone(), member.content.clone());
|
||||
if member.state_key() == member.sender() {
|
||||
profiles.insert(member.sender().to_owned(), (&member).into());
|
||||
}
|
||||
|
||||
members.insert(member.state_key.clone(), member);
|
||||
members.insert(member.state_key().to_owned(), member);
|
||||
} else {
|
||||
state_events
|
||||
.entry(event.event_type())
|
||||
@@ -859,12 +859,12 @@ impl BaseClient {
|
||||
let members: Vec<_> = response
|
||||
.chunk
|
||||
.iter()
|
||||
.filter_map(|e| e.deserialize().ok())
|
||||
.filter_map(|ev| match ev {
|
||||
RoomMemberEvent::Original(ev) => Some(ev),
|
||||
// FIXME: don't filter these out
|
||||
// https://github.com/matrix-org/matrix-rust-sdk/issues/607
|
||||
RoomMemberEvent::Redacted(_) => None,
|
||||
.filter_map(|event| match event.deserialize() {
|
||||
Ok(ev) => Some(ev),
|
||||
Err(e) => {
|
||||
debug!(?event, "Failed to deserialize m.room.member event: {}", e);
|
||||
None
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
@@ -880,32 +880,32 @@ impl BaseClient {
|
||||
let mut user_ids = BTreeSet::new();
|
||||
|
||||
for member in &members {
|
||||
let member: OriginalSyncRoomMemberEvent = member.clone().into();
|
||||
let member: SyncRoomMemberEvent = member.clone().into();
|
||||
|
||||
if self.store.get_member_event(room_id, &member.state_key).await?.is_none() {
|
||||
if self.store.get_member_event(room_id, member.state_key()).await?.is_none() {
|
||||
#[cfg(feature = "e2e-encryption")]
|
||||
match member.content.membership {
|
||||
match member.membership() {
|
||||
MembershipState::Join | MembershipState::Invite => {
|
||||
user_ids.insert(member.state_key.clone());
|
||||
user_ids.insert(member.state_key().to_owned());
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
|
||||
ambiguity_cache.handle_event(&changes, room_id, &member).await?;
|
||||
|
||||
if member.state_key == member.sender {
|
||||
if member.state_key() == member.sender() {
|
||||
changes
|
||||
.profiles
|
||||
.entry(room_id.to_owned())
|
||||
.or_default()
|
||||
.insert(member.sender.clone(), member.content.clone());
|
||||
.insert(member.sender().to_owned(), (&member).into());
|
||||
}
|
||||
|
||||
changes
|
||||
.members
|
||||
.entry(room_id.to_owned())
|
||||
.or_default()
|
||||
.insert(member.state_key.clone(), member);
|
||||
.insert(member.state_key().to_owned(), member);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1238,7 +1238,10 @@ impl BaseClient {
|
||||
let user_display_name = if let Some(member) =
|
||||
changes.members.get(room_id).and_then(|members| members.get(user_id))
|
||||
{
|
||||
member.content.displayname.clone().unwrap_or_else(|| user_id.localpart().to_owned())
|
||||
member
|
||||
.as_original()
|
||||
.and_then(|ev| ev.content.displayname.clone())
|
||||
.unwrap_or_else(|| user_id.localpart().to_owned())
|
||||
} else if let Some(member) = room.get_member(user_id).await? {
|
||||
member.name().to_owned()
|
||||
} else {
|
||||
@@ -1291,8 +1294,10 @@ impl BaseClient {
|
||||
if let Some(member) =
|
||||
changes.members.get(&**room_id).and_then(|members| members.get(user_id))
|
||||
{
|
||||
push_rules.user_display_name =
|
||||
member.content.displayname.clone().unwrap_or_else(|| user_id.localpart().to_owned())
|
||||
push_rules.user_display_name = member
|
||||
.as_original()
|
||||
.and_then(|ev| ev.content.displayname.clone())
|
||||
.unwrap_or_else(|| user_id.localpart().to_owned())
|
||||
}
|
||||
|
||||
if let Some(AnySyncStateEvent::RoomPowerLevels(event)) = changes
|
||||
|
||||
@@ -43,5 +43,6 @@ pub use http;
|
||||
pub use matrix_sdk_crypto as crypto;
|
||||
pub use rooms::{DisplayName, Room, RoomInfo, RoomMember, RoomType};
|
||||
pub use store::{StateChanges, StateStore, Store, StoreError};
|
||||
#[allow(unused_imports)]
|
||||
pub(crate) use utils::{MinimalStateEvent, OriginalMinimalStateEvent, RedactedMinimalStateEvent};
|
||||
pub use utils::{
|
||||
MinimalRoomMemberEvent, MinimalStateEvent, OriginalMinimalStateEvent, RedactedMinimalStateEvent,
|
||||
};
|
||||
|
||||
@@ -17,21 +17,21 @@ use std::sync::Arc;
|
||||
use ruma::{
|
||||
events::{
|
||||
presence::PresenceEvent,
|
||||
room::{
|
||||
member::{MembershipState, RoomMemberEventContent},
|
||||
power_levels::SyncRoomPowerLevelsEvent,
|
||||
},
|
||||
room::{member::MembershipState, power_levels::SyncRoomPowerLevelsEvent},
|
||||
},
|
||||
MxcUri, UserId,
|
||||
};
|
||||
|
||||
use crate::deserialized_responses::MemberEvent;
|
||||
use crate::{deserialized_responses::MemberEvent, MinimalRoomMemberEvent};
|
||||
|
||||
/// A member of a room.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct RoomMember {
|
||||
pub(crate) event: Arc<MemberEvent>,
|
||||
pub(crate) profile: Arc<Option<RoomMemberEventContent>>,
|
||||
// The latest member event sent by the member themselves.
|
||||
// Stored in addition to the latest member event overall to get displayname
|
||||
// and avatar from, which should be ignored on events sent by others.
|
||||
pub(crate) profile: Arc<Option<MinimalRoomMemberEvent>>,
|
||||
#[allow(dead_code)]
|
||||
pub(crate) presence: Arc<Option<PresenceEvent>>,
|
||||
pub(crate) power_levels: Arc<Option<SyncRoomPowerLevelsEvent>>,
|
||||
@@ -49,7 +49,7 @@ impl RoomMember {
|
||||
/// Get the display name of the member if there is one.
|
||||
pub fn display_name(&self) -> Option<&str> {
|
||||
if let Some(p) = self.profile.as_ref() {
|
||||
p.displayname.as_deref()
|
||||
p.as_original().and_then(|e| e.content.displayname.as_deref())
|
||||
} else {
|
||||
self.event.original_content()?.displayname.as_deref()
|
||||
}
|
||||
@@ -69,9 +69,10 @@ impl RoomMember {
|
||||
|
||||
/// Get the avatar url of the member, if there is one.
|
||||
pub fn avatar_url(&self) -> Option<&MxcUri> {
|
||||
match self.profile.as_ref() {
|
||||
Some(p) => p.avatar_url.as_deref(),
|
||||
None => self.event.original_content()?.avatar_url.as_deref(),
|
||||
if let Some(p) = self.profile.as_ref() {
|
||||
p.as_original().and_then(|e| e.content.avatar_url.as_deref())
|
||||
} else {
|
||||
self.event.original_content()?.avatar_url.as_deref()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,7 +107,7 @@ impl RoomMember {
|
||||
/// Get the membership state of this member.
|
||||
pub fn membership(&self) -> &MembershipState {
|
||||
if let Some(p) = self.profile.as_ref() {
|
||||
&p.membership
|
||||
p.membership()
|
||||
} else {
|
||||
self.event.membership()
|
||||
}
|
||||
|
||||
@@ -813,7 +813,7 @@ mod test {
|
||||
canonical_alias::RoomCanonicalAliasEventContent,
|
||||
member::{
|
||||
MembershipState, OriginalSyncRoomMemberEvent, RoomMemberEventContent,
|
||||
StrippedRoomMemberEvent,
|
||||
StrippedRoomMemberEvent, SyncRoomMemberEvent,
|
||||
},
|
||||
name::RoomNameEventContent,
|
||||
},
|
||||
@@ -846,8 +846,8 @@ mod test {
|
||||
}
|
||||
}
|
||||
|
||||
fn make_member_event(user_id: &UserId, name: &str) -> OriginalSyncRoomMemberEvent {
|
||||
OriginalSyncRoomMemberEvent {
|
||||
fn make_member_event(user_id: &UserId, name: &str) -> SyncRoomMemberEvent {
|
||||
SyncRoomMemberEvent::Original(OriginalSyncRoomMemberEvent {
|
||||
content: assign!(RoomMemberEventContent::new(MembershipState::Join), {
|
||||
displayname: Some(name.to_owned())
|
||||
}),
|
||||
@@ -856,7 +856,7 @@ mod test {
|
||||
event_id: event_id!("$h29iv0s1:example.com").to_owned(),
|
||||
origin_server_ts: MilliSecondsSinceUnixEpoch(208u32.into()),
|
||||
unsigned: StateUnsigned::default(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
|
||||
@@ -16,7 +16,7 @@ use std::collections::{BTreeMap, BTreeSet};
|
||||
|
||||
use matrix_sdk_common::deserialized_responses::{AmbiguityChange, MemberEvent};
|
||||
use ruma::{
|
||||
events::room::member::{MembershipState, OriginalSyncRoomMemberEvent, SyncRoomMemberEvent},
|
||||
events::room::member::{MembershipState, SyncRoomMemberEvent},
|
||||
OwnedEventId, OwnedRoomId, OwnedUserId, RoomId, UserId,
|
||||
};
|
||||
use tracing::trace;
|
||||
@@ -75,7 +75,7 @@ impl AmbiguityCache {
|
||||
&mut self,
|
||||
changes: &StateChanges,
|
||||
room_id: &RoomId,
|
||||
member_event: &OriginalSyncRoomMemberEvent,
|
||||
member_event: &SyncRoomMemberEvent,
|
||||
) -> Result<()> {
|
||||
// Synapse seems to have a bug where it puts the same event into the
|
||||
// state and the timeline sometimes.
|
||||
@@ -89,7 +89,7 @@ impl AmbiguityCache {
|
||||
if self
|
||||
.changes
|
||||
.get(room_id)
|
||||
.map(|c| c.contains_key(&member_event.event_id))
|
||||
.map(|c| c.contains_key(member_event.event_id()))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
return Ok(());
|
||||
@@ -106,9 +106,10 @@ impl AmbiguityCache {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let disambiguated_member = old_map.as_mut().and_then(|o| o.remove(&member_event.state_key));
|
||||
let disambiguated_member =
|
||||
old_map.as_mut().and_then(|o| o.remove(member_event.state_key()));
|
||||
let ambiguated_member =
|
||||
new_map.as_mut().and_then(|n| n.add(member_event.state_key.clone()));
|
||||
new_map.as_mut().and_then(|n| n.add(member_event.state_key().clone()));
|
||||
let ambiguous = new_map.as_ref().map(|n| n.is_ambiguous()).unwrap_or(false);
|
||||
|
||||
self.update(room_id, old_map, new_map);
|
||||
@@ -119,9 +120,9 @@ impl AmbiguityCache {
|
||||
member_ambiguous: ambiguous,
|
||||
};
|
||||
|
||||
trace!("Handling display name ambiguity for {}: {:#?}", member_event.state_key, change);
|
||||
trace!("Handling display name ambiguity for {}: {:#?}", member_event.state_key(), change);
|
||||
|
||||
self.add_change(room_id, member_event.event_id.clone(), change);
|
||||
self.add_change(room_id, member_event.event_id().to_owned(), change);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -151,16 +152,16 @@ impl AmbiguityCache {
|
||||
&mut self,
|
||||
changes: &StateChanges,
|
||||
room_id: &RoomId,
|
||||
member_event: &OriginalSyncRoomMemberEvent,
|
||||
member_event: &SyncRoomMemberEvent,
|
||||
) -> Result<(Option<AmbiguityMap>, Option<AmbiguityMap>)> {
|
||||
use MembershipState::*;
|
||||
|
||||
let old_event = if let Some(m) =
|
||||
changes.members.get(room_id).and_then(|m| m.get(&member_event.state_key))
|
||||
changes.members.get(room_id).and_then(|m| m.get(member_event.state_key()))
|
||||
{
|
||||
Some(MemberEvent::Sync(SyncRoomMemberEvent::Original(m.clone())))
|
||||
Some(MemberEvent::Sync(m.clone()))
|
||||
} else {
|
||||
self.store.get_member_event(room_id, &member_event.state_key).await?
|
||||
self.store.get_member_event(room_id, member_event.state_key()).await?
|
||||
};
|
||||
|
||||
let old_display_name = if let Some(event) = old_event {
|
||||
@@ -168,15 +169,17 @@ impl AmbiguityCache {
|
||||
let display_name = if let Some(d) = changes
|
||||
.profiles
|
||||
.get(room_id)
|
||||
.and_then(|p| p.get(&member_event.state_key))
|
||||
.and_then(|p| p.displayname.as_deref())
|
||||
.and_then(|p| p.get(member_event.state_key()))
|
||||
.and_then(|p| p.as_original())
|
||||
.and_then(|p| p.content.displayname.as_deref())
|
||||
{
|
||||
Some(d.to_owned())
|
||||
} else if let Some(d) = self
|
||||
.store
|
||||
.get_profile(room_id, &member_event.state_key)
|
||||
.get_profile(room_id, member_event.state_key())
|
||||
.await?
|
||||
.and_then(|c| c.displayname)
|
||||
.and_then(|p| p.into_original())
|
||||
.and_then(|p| p.content.displayname)
|
||||
{
|
||||
Some(d)
|
||||
} else {
|
||||
@@ -204,17 +207,16 @@ impl AmbiguityCache {
|
||||
None
|
||||
};
|
||||
|
||||
let new_map = if matches!(member_event.content.membership, Join | Invite) {
|
||||
let new_map = if matches!(member_event.membership(), Join | Invite) {
|
||||
let new = member_event
|
||||
.content
|
||||
.displayname
|
||||
.as_deref()
|
||||
.unwrap_or_else(|| member_event.state_key.localpart());
|
||||
.as_original()
|
||||
.and_then(|ev| ev.content.displayname.as_deref())
|
||||
.unwrap_or_else(|| member_event.state_key().localpart());
|
||||
|
||||
// We don't allow other users to set the display name, so if we
|
||||
// have a more trusted version of the display
|
||||
// name use that.
|
||||
let new_display_name = if member_event.sender.as_str() == member_event.state_key {
|
||||
let new_display_name = if member_event.sender().as_str() == member_event.state_key() {
|
||||
new
|
||||
} else if let Some(old) = old_display_name.as_deref() {
|
||||
old
|
||||
|
||||
@@ -53,8 +53,8 @@ macro_rules! statestore_integration_tests {
|
||||
presence::PresenceEvent,
|
||||
room::{
|
||||
member::{
|
||||
MembershipState, OriginalSyncRoomMemberEvent, RoomMemberEventContent,
|
||||
StrippedRoomMemberEvent,
|
||||
MembershipState, OriginalSyncRoomMemberEvent, SyncRoomMemberEvent,
|
||||
RoomMemberEventContent, StrippedRoomMemberEvent,
|
||||
},
|
||||
power_levels::RoomPowerLevelsEventContent,
|
||||
MediaSource,
|
||||
@@ -173,14 +173,15 @@ macro_rules! statestore_integration_tests {
|
||||
let mut room_members = BTreeMap::new();
|
||||
|
||||
let member_json: &JsonValue = &test_json::MEMBER;
|
||||
let member_event: OriginalSyncRoomMemberEvent =
|
||||
let member_event: SyncRoomMemberEvent =
|
||||
serde_json::from_value(member_json.clone()).unwrap();
|
||||
let member_event_content = member_event.content.clone();
|
||||
let displayname =
|
||||
member_event.as_original().unwrap().content.displayname.clone().unwrap();
|
||||
room_ambiguity_map.insert(
|
||||
member_event_content.displayname.clone().unwrap(),
|
||||
displayname.clone(),
|
||||
BTreeSet::from([user_id.to_owned()]),
|
||||
);
|
||||
room_profiles.insert(user_id.to_owned(), member_event.content.clone());
|
||||
room_profiles.insert(user_id.to_owned(), (&member_event).into());
|
||||
room_members.insert(user_id.to_owned(), member_event);
|
||||
|
||||
let member_state_raw =
|
||||
@@ -190,13 +191,13 @@ macro_rules! statestore_integration_tests {
|
||||
|
||||
let invited_member_json: &JsonValue = &test_json::MEMBER_INVITE;
|
||||
// FIXME: Should be stripped room member event
|
||||
let invited_member_event: OriginalSyncRoomMemberEvent =
|
||||
let invited_member_event: SyncRoomMemberEvent =
|
||||
serde_json::from_value(invited_member_json.clone()).unwrap();
|
||||
room_ambiguity_map
|
||||
.entry(member_event_content.displayname.clone().unwrap())
|
||||
.entry(displayname)
|
||||
.or_default()
|
||||
.insert(invited_user_id.to_owned());
|
||||
room_profiles.insert(invited_user_id.to_owned(), invited_member_event.content.clone());
|
||||
room_profiles.insert(invited_user_id.to_owned(), (&invited_member_event).into());
|
||||
room_members.insert(invited_user_id.to_owned(), invited_member_event);
|
||||
|
||||
let invited_member_state_raw =
|
||||
@@ -279,22 +280,22 @@ macro_rules! statestore_integration_tests {
|
||||
}
|
||||
}
|
||||
|
||||
fn membership_event() -> OriginalSyncRoomMemberEvent {
|
||||
fn membership_event() -> SyncRoomMemberEvent {
|
||||
custom_membership_event(user_id(), event_id!("$h29iv0s8:example.com").to_owned())
|
||||
}
|
||||
|
||||
fn custom_membership_event(
|
||||
user_id: &UserId,
|
||||
event_id: OwnedEventId,
|
||||
) -> OriginalSyncRoomMemberEvent {
|
||||
OriginalSyncRoomMemberEvent {
|
||||
) -> SyncRoomMemberEvent {
|
||||
SyncRoomMemberEvent::Original(OriginalSyncRoomMemberEvent {
|
||||
event_id,
|
||||
content: RoomMemberEventContent::new(MembershipState::Join),
|
||||
sender: user_id.to_owned(),
|
||||
origin_server_ts: MilliSecondsSinceUnixEpoch(198u32.into()),
|
||||
state_key: user_id.to_owned(),
|
||||
unsigned: StateUnsigned::default(),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#[async_test]
|
||||
|
||||
@@ -30,10 +30,7 @@ use ruma::{
|
||||
events::{
|
||||
presence::PresenceEvent,
|
||||
receipt::Receipt,
|
||||
room::member::{
|
||||
MembershipState, OriginalSyncRoomMemberEvent, RoomMemberEventContent,
|
||||
StrippedRoomMemberEvent, SyncRoomMemberEvent,
|
||||
},
|
||||
room::member::{MembershipState, StrippedRoomMemberEvent, SyncRoomMemberEvent},
|
||||
AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent, AnyStrippedStateEvent,
|
||||
AnySyncStateEvent, GlobalAccountDataEventType, RoomAccountDataEventType, StateEventType,
|
||||
},
|
||||
@@ -54,6 +51,7 @@ use super::{Result, RoomInfo, StateChanges, StateStore};
|
||||
use crate::{
|
||||
deserialized_responses::MemberEvent,
|
||||
media::{MediaRequest, UniqueKey},
|
||||
MinimalRoomMemberEvent,
|
||||
};
|
||||
#[cfg(feature = "experimental-timeline")]
|
||||
use crate::{deserialized_responses::SyncRoomEvent, StoreError};
|
||||
@@ -67,8 +65,8 @@ pub struct MemoryStore {
|
||||
sync_token: Arc<RwLock<Option<String>>>,
|
||||
filters: Arc<DashMap<String, String>>,
|
||||
account_data: Arc<DashMap<GlobalAccountDataEventType, Raw<AnyGlobalAccountDataEvent>>>,
|
||||
members: Arc<DashMap<OwnedRoomId, DashMap<OwnedUserId, OriginalSyncRoomMemberEvent>>>,
|
||||
profiles: Arc<DashMap<OwnedRoomId, DashMap<OwnedUserId, RoomMemberEventContent>>>,
|
||||
members: Arc<DashMap<OwnedRoomId, DashMap<OwnedUserId, SyncRoomMemberEvent>>>,
|
||||
profiles: Arc<DashMap<OwnedRoomId, DashMap<OwnedUserId, MinimalRoomMemberEvent>>>,
|
||||
display_names: Arc<DashMap<OwnedRoomId, DashMap<String, BTreeSet<OwnedUserId>>>>,
|
||||
joined_user_ids: Arc<DashMap<OwnedRoomId, DashSet<OwnedUserId>>>,
|
||||
invited_user_ids: Arc<DashMap<OwnedRoomId, DashSet<OwnedUserId>>>,
|
||||
@@ -156,43 +154,43 @@ impl MemoryStore {
|
||||
|
||||
for (room, events) in &changes.members {
|
||||
for event in events.values() {
|
||||
match event.content.membership {
|
||||
match event.membership() {
|
||||
MembershipState::Join => {
|
||||
self.joined_user_ids
|
||||
.entry(room.clone())
|
||||
.or_default()
|
||||
.insert(event.state_key.clone());
|
||||
.insert(event.state_key().to_owned());
|
||||
self.invited_user_ids
|
||||
.entry(room.clone())
|
||||
.or_default()
|
||||
.remove(&event.state_key);
|
||||
.remove(event.state_key());
|
||||
}
|
||||
MembershipState::Invite => {
|
||||
self.invited_user_ids
|
||||
.entry(room.clone())
|
||||
.or_default()
|
||||
.insert(event.state_key.clone());
|
||||
.insert(event.state_key().to_owned());
|
||||
self.joined_user_ids
|
||||
.entry(room.clone())
|
||||
.or_default()
|
||||
.remove(&event.state_key);
|
||||
.remove(event.state_key());
|
||||
}
|
||||
_ => {
|
||||
self.joined_user_ids
|
||||
.entry(room.clone())
|
||||
.or_default()
|
||||
.remove(&event.state_key);
|
||||
.remove(event.state_key());
|
||||
self.invited_user_ids
|
||||
.entry(room.clone())
|
||||
.or_default()
|
||||
.remove(&event.state_key);
|
||||
.remove(event.state_key());
|
||||
}
|
||||
}
|
||||
|
||||
self.members
|
||||
.entry(room.clone())
|
||||
.or_default()
|
||||
.insert(event.state_key.clone(), event.clone());
|
||||
.insert(event.state_key().to_owned(), event.clone());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -497,7 +495,7 @@ impl MemoryStore {
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
user_id: &UserId,
|
||||
) -> Result<Option<RoomMemberEventContent>> {
|
||||
) -> Result<Option<MinimalRoomMemberEvent>> {
|
||||
Ok(self.profiles.get(room_id).and_then(|p| p.get(user_id).map(|p| p.clone())))
|
||||
}
|
||||
|
||||
@@ -508,7 +506,7 @@ impl MemoryStore {
|
||||
) -> Result<Option<MemberEvent>> {
|
||||
if let Some(e) = self.members.get(room_id).and_then(|m| m.get(state_key).map(|m| m.clone()))
|
||||
{
|
||||
Ok(Some(MemberEvent::Sync(SyncRoomMemberEvent::Original(e))))
|
||||
Ok(Some(MemberEvent::Sync(e)))
|
||||
} else if let Some(e) =
|
||||
self.stripped_members.get(room_id).and_then(|m| m.get(state_key).map(|m| m.clone()))
|
||||
{
|
||||
@@ -743,7 +741,7 @@ impl StateStore for MemoryStore {
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
user_id: &UserId,
|
||||
) -> Result<Option<RoomMemberEventContent>> {
|
||||
) -> Result<Option<MinimalRoomMemberEvent>> {
|
||||
self.get_profile(room_id, user_id).await
|
||||
}
|
||||
|
||||
|
||||
@@ -42,9 +42,7 @@ use ruma::{
|
||||
events::{
|
||||
presence::PresenceEvent,
|
||||
receipt::{Receipt, ReceiptEventContent},
|
||||
room::member::{
|
||||
OriginalSyncRoomMemberEvent, RoomMemberEventContent, StrippedRoomMemberEvent,
|
||||
},
|
||||
room::member::{StrippedRoomMemberEvent, SyncRoomMemberEvent},
|
||||
AnyGlobalAccountDataEvent, AnyRoomAccountDataEvent, AnyStrippedStateEvent,
|
||||
AnySyncStateEvent, GlobalAccountDataEventType, RoomAccountDataEventType, StateEventType,
|
||||
},
|
||||
@@ -62,7 +60,7 @@ use crate::{
|
||||
deserialized_responses::MemberEvent,
|
||||
media::MediaRequest,
|
||||
rooms::{RoomInfo, RoomType},
|
||||
Room, Session,
|
||||
MinimalRoomMemberEvent, Room, Session,
|
||||
};
|
||||
|
||||
pub(crate) mod ambiguity_map;
|
||||
@@ -185,7 +183,7 @@ pub trait StateStore: AsyncTraitDeps {
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
user_id: &UserId,
|
||||
) -> Result<Option<RoomMemberEventContent>>;
|
||||
) -> Result<Option<MinimalRoomMemberEvent>>;
|
||||
|
||||
/// Get the `MemberEvent` for the given state key in the given room id.
|
||||
///
|
||||
@@ -493,12 +491,11 @@ pub struct StateChanges {
|
||||
/// A mapping of `UserId` to `PresenceEvent`.
|
||||
pub presence: BTreeMap<OwnedUserId, Raw<PresenceEvent>>,
|
||||
|
||||
/// A mapping of `RoomId` to a map of users and their `SyncRoomMemberEvent`.
|
||||
pub members: BTreeMap<OwnedRoomId, BTreeMap<OwnedUserId, SyncRoomMemberEvent>>,
|
||||
/// A mapping of `RoomId` to a map of users and their
|
||||
/// `OriginalRoomMemberEvent`.
|
||||
pub members: BTreeMap<OwnedRoomId, BTreeMap<OwnedUserId, OriginalSyncRoomMemberEvent>>,
|
||||
/// A mapping of `RoomId` to a map of users and their
|
||||
/// `RoomMemberEventContent`.
|
||||
pub profiles: BTreeMap<OwnedRoomId, BTreeMap<OwnedUserId, RoomMemberEventContent>>,
|
||||
/// `MinimalRoomMemberEvent`.
|
||||
pub profiles: BTreeMap<OwnedRoomId, BTreeMap<OwnedUserId, MinimalRoomMemberEvent>>,
|
||||
|
||||
/// A mapping of `RoomId` to a map of event type string to a state key and
|
||||
/// `AnySyncStateEvent`.
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use ruma::{
|
||||
events::{
|
||||
room::member::{MembershipState, RoomMemberEventContent},
|
||||
RedactContent, RedactedEventContent, StateEventContent, StrippedStateEvent, SyncStateEvent,
|
||||
},
|
||||
EventId, OwnedEventId, RoomVersionId,
|
||||
@@ -12,30 +13,48 @@ use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
// implemented for C::Redacted.
|
||||
//
|
||||
// It is unclear why a Serialize bound on C::Redacted is not also required.
|
||||
|
||||
/// A minimal state event.
|
||||
///
|
||||
/// This type can holding an possibly-redacted state event with an optional
|
||||
/// event ID. The event ID is optional so this type can also hold events from
|
||||
/// invited rooms, where event IDs are not available.
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub enum MinimalStateEvent<C: StateEventContent + RedactContent>
|
||||
where
|
||||
C::Redacted: StateEventContent + RedactedEventContent + DeserializeOwned,
|
||||
{
|
||||
/// An unredacted event.
|
||||
Original(OriginalMinimalStateEvent<C>),
|
||||
/// A redacted event.
|
||||
Redacted(RedactedMinimalStateEvent<C::Redacted>),
|
||||
}
|
||||
|
||||
/// An unredacted minimal state event.
|
||||
///
|
||||
/// For more details see [`MinimalStateEvent`].
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct OriginalMinimalStateEvent<C>
|
||||
where
|
||||
C: StateEventContent,
|
||||
{
|
||||
/// The event's content.
|
||||
pub content: C,
|
||||
/// The event's ID, if known.
|
||||
pub event_id: Option<OwnedEventId>,
|
||||
}
|
||||
|
||||
/// A redacted minimal state event.
|
||||
///
|
||||
/// For more details see [`MinimalStateEvent`].
|
||||
#[derive(Clone, Debug, Deserialize, Serialize)]
|
||||
pub struct RedactedMinimalStateEvent<C>
|
||||
where
|
||||
C: StateEventContent + RedactedEventContent,
|
||||
{
|
||||
/// The event's content.
|
||||
pub content: C,
|
||||
/// The event's ID, if known.
|
||||
pub event_id: Option<OwnedEventId>,
|
||||
}
|
||||
|
||||
@@ -44,6 +63,7 @@ where
|
||||
C: StateEventContent + RedactContent,
|
||||
C::Redacted: StateEventContent + RedactedEventContent + DeserializeOwned,
|
||||
{
|
||||
/// Get the inner event's ID.
|
||||
pub fn event_id(&self) -> Option<&EventId> {
|
||||
match self {
|
||||
MinimalStateEvent::Original(ev) => ev.event_id.as_deref(),
|
||||
@@ -51,6 +71,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the inner event, if it isn't redacted.
|
||||
pub fn as_original(&self) -> Option<&OriginalMinimalStateEvent<C>> {
|
||||
match self {
|
||||
MinimalStateEvent::Original(ev) => Some(ev),
|
||||
@@ -58,6 +79,18 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts `self` to the inner `OriginalMinimalStateEvent<C>`, if it isn't
|
||||
/// redacted.
|
||||
pub fn into_original(self) -> Option<OriginalMinimalStateEvent<C>> {
|
||||
match self {
|
||||
MinimalStateEvent::Original(ev) => Some(ev),
|
||||
MinimalStateEvent::Redacted(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Redacts this event.
|
||||
///
|
||||
/// Does nothing if it is already redacted.
|
||||
pub fn redact(&mut self, room_version: &RoomVersionId)
|
||||
where
|
||||
C: Clone,
|
||||
@@ -71,6 +104,20 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// A minimal `m.room.member` event.
|
||||
pub type MinimalRoomMemberEvent = MinimalStateEvent<RoomMemberEventContent>;
|
||||
|
||||
impl MinimalRoomMemberEvent {
|
||||
/// Obtain the membership state, regardless of whether this event is
|
||||
/// redacted.
|
||||
pub fn membership(&self) -> &MembershipState {
|
||||
match self {
|
||||
MinimalStateEvent::Original(ev) => &ev.content.membership,
|
||||
MinimalStateEvent::Redacted(ev) => &ev.content.membership,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<C> From<&SyncStateEvent<C>> for MinimalStateEvent<C>
|
||||
where
|
||||
C: Clone + StateEventContent + RedactContent,
|
||||
|
||||
@@ -10,8 +10,8 @@ use ruma::{
|
||||
},
|
||||
events::{
|
||||
room::member::{
|
||||
MembershipState, OriginalRoomMemberEvent, RoomMemberEventContent,
|
||||
StrippedRoomMemberEvent, SyncRoomMemberEvent,
|
||||
MembershipState, RoomMemberEvent, RoomMemberEventContent, StrippedRoomMemberEvent,
|
||||
SyncRoomMemberEvent,
|
||||
},
|
||||
AnyRoomEvent, AnySyncRoomEvent,
|
||||
},
|
||||
@@ -336,7 +336,7 @@ impl MemberEvent {
|
||||
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||
pub struct MembersResponse {
|
||||
/// The list of members events.
|
||||
pub chunk: Vec<OriginalRoomMemberEvent>,
|
||||
pub chunk: Vec<RoomMemberEvent>,
|
||||
/// Collection of ambiguity changes that room member events trigger.
|
||||
pub ambiguity_changes: AmbiguityChanges,
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ use matrix_sdk_base::{
|
||||
deserialized_responses::MemberEvent,
|
||||
media::{MediaRequest, UniqueKey},
|
||||
store::{Result as StoreResult, StateChanges, StateStore, StoreError},
|
||||
RoomInfo,
|
||||
MinimalStateEvent, RoomInfo,
|
||||
};
|
||||
#[cfg(feature = "experimental-timeline")]
|
||||
use matrix_sdk_base::{deserialized_responses::SyncRoomEvent, store::BoxStream};
|
||||
@@ -557,20 +557,20 @@ impl IndexeddbStore {
|
||||
let profile_changes = changes.profiles.get(room);
|
||||
|
||||
for event in events.values() {
|
||||
let key = (room, &event.state_key);
|
||||
let key = (room, event.state_key());
|
||||
|
||||
match event.content.membership {
|
||||
match event.membership() {
|
||||
MembershipState::Join => {
|
||||
joined.put_key_val_owned(
|
||||
&self.encode_key(KEYS::JOINED_USER_IDS, key),
|
||||
&self.serialize_event(&event.state_key)?,
|
||||
&self.serialize_event(event.state_key())?,
|
||||
)?;
|
||||
invited.delete(&self.encode_key(KEYS::INVITED_USER_IDS, key))?;
|
||||
}
|
||||
MembershipState::Invite => {
|
||||
invited.put_key_val_owned(
|
||||
&self.encode_key(KEYS::INVITED_USER_IDS, key),
|
||||
&self.serialize_event(&event.state_key)?,
|
||||
&self.serialize_event(event.state_key())?,
|
||||
)?;
|
||||
joined.delete(&self.encode_key(KEYS::JOINED_USER_IDS, key))?;
|
||||
}
|
||||
@@ -585,7 +585,7 @@ impl IndexeddbStore {
|
||||
&self.serialize_event(&event)?,
|
||||
)?;
|
||||
|
||||
if let Some(profile) = profile_changes.and_then(|p| p.get(&event.state_key)) {
|
||||
if let Some(profile) = profile_changes.and_then(|p| p.get(event.state_key())) {
|
||||
profiles_store.put_key_val_owned(
|
||||
&self.encode_key(KEYS::PROFILES, key),
|
||||
&self.serialize_event(&profile)?,
|
||||
@@ -888,7 +888,7 @@ impl IndexeddbStore {
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
user_id: &UserId,
|
||||
) -> Result<Option<RoomMemberEventContent>> {
|
||||
) -> Result<Option<MinimalStateEvent<RoomMemberEventContent>>> {
|
||||
self.inner
|
||||
.transaction_on_one_with_mode(KEYS::PROFILES, IdbTransactionMode::Readonly)?
|
||||
.object_store(KEYS::PROFILES)?
|
||||
@@ -1335,7 +1335,7 @@ impl StateStore for IndexeddbStore {
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
user_id: &UserId,
|
||||
) -> StoreResult<Option<RoomMemberEventContent>> {
|
||||
) -> StoreResult<Option<MinimalStateEvent<RoomMemberEventContent>>> {
|
||||
self.get_profile(room_id, user_id).await.map_err(|e| e.into())
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ use matrix_sdk_base::{
|
||||
deserialized_responses::MemberEvent,
|
||||
media::{MediaRequest, UniqueKey},
|
||||
store::{Result as StoreResult, StateChanges, StateStore, StoreError},
|
||||
RoomInfo,
|
||||
MinimalStateEvent, RoomInfo,
|
||||
};
|
||||
#[cfg(feature = "experimental-timeline")]
|
||||
use matrix_sdk_base::{deserialized_responses::SyncRoomEvent, store::BoxStream};
|
||||
@@ -459,20 +459,20 @@ impl SledStore {
|
||||
let profile_changes = changes.profiles.get(room);
|
||||
|
||||
for event in events.values() {
|
||||
let key = (room, &event.state_key);
|
||||
let key = (room, event.state_key());
|
||||
|
||||
match event.content.membership {
|
||||
match event.membership() {
|
||||
MembershipState::Join => {
|
||||
joined.insert(
|
||||
self.encode_key(JOINED_USER_ID, &key),
|
||||
event.state_key.as_str(),
|
||||
event.state_key().as_str(),
|
||||
)?;
|
||||
invited.remove(self.encode_key(INVITED_USER_ID, &key))?;
|
||||
}
|
||||
MembershipState::Invite => {
|
||||
invited.insert(
|
||||
self.encode_key(INVITED_USER_ID, &key),
|
||||
event.state_key.as_str(),
|
||||
event.state_key().as_str(),
|
||||
)?;
|
||||
joined.remove(self.encode_key(JOINED_USER_ID, &key))?;
|
||||
}
|
||||
@@ -489,7 +489,7 @@ impl SledStore {
|
||||
)?;
|
||||
|
||||
if let Some(profile) =
|
||||
profile_changes.and_then(|p| p.get(&event.state_key))
|
||||
profile_changes.and_then(|p| p.get(event.state_key()))
|
||||
{
|
||||
profiles.insert(
|
||||
self.encode_key(PROFILE, &key),
|
||||
@@ -730,7 +730,7 @@ impl SledStore {
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
user_id: &UserId,
|
||||
) -> Result<Option<RoomMemberEventContent>> {
|
||||
) -> Result<Option<MinimalStateEvent<RoomMemberEventContent>>> {
|
||||
let db = self.clone();
|
||||
let key = self.encode_key(PROFILE, (room_id, user_id));
|
||||
spawn_blocking(move || db.profiles.get(key)?.map(|p| db.deserialize_event(&p)).transpose())
|
||||
@@ -1433,7 +1433,7 @@ impl StateStore for SledStore {
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
user_id: &UserId,
|
||||
) -> StoreResult<Option<RoomMemberEventContent>> {
|
||||
) -> StoreResult<Option<MinimalStateEvent<RoomMemberEventContent>>> {
|
||||
self.get_profile(room_id, user_id).await.map_err(Into::into)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user