base: Add a method to get all the user ids that use a certain display name
parent
6cb2c8b468
commit
b4a916b797
|
@ -33,6 +33,7 @@ pub struct RoomMember {
|
||||||
pub(crate) power_levles: Arc<Option<SyncStateEvent<PowerLevelsEventContent>>>,
|
pub(crate) power_levles: Arc<Option<SyncStateEvent<PowerLevelsEventContent>>>,
|
||||||
pub(crate) max_power_level: i64,
|
pub(crate) max_power_level: i64,
|
||||||
pub(crate) is_room_creator: bool,
|
pub(crate) is_room_creator: bool,
|
||||||
|
pub(crate) display_name_ambiguous: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RoomMember {
|
impl RoomMember {
|
||||||
|
|
|
@ -312,6 +312,13 @@ impl Room {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_member(&self, user_id: &UserId) -> StoreResult<Option<RoomMember>> {
|
pub async fn get_member(&self, user_id: &UserId) -> StoreResult<Option<RoomMember>> {
|
||||||
|
let member_event =
|
||||||
|
if let Some(m) = self.store.get_member_event(self.room_id(), user_id).await? {
|
||||||
|
m
|
||||||
|
} else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
|
|
||||||
let presence = self.store.get_presence_event(user_id).await?;
|
let presence = self.store.get_presence_event(user_id).await?;
|
||||||
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();
|
||||||
|
@ -338,17 +345,28 @@ impl Room {
|
||||||
})
|
})
|
||||||
.flatten();
|
.flatten();
|
||||||
|
|
||||||
Ok(self
|
let ambiguous = self
|
||||||
.store
|
.store
|
||||||
.get_member_event(&self.room_id, user_id)
|
.get_users_with_display_name(
|
||||||
|
self.room_id(),
|
||||||
|
member_event
|
||||||
|
.content
|
||||||
|
.displayname
|
||||||
|
.as_deref()
|
||||||
|
.unwrap_or_else(|| user_id.localpart()),
|
||||||
|
)
|
||||||
.await?
|
.await?
|
||||||
.map(|e| RoomMember {
|
.len()
|
||||||
event: e.into(),
|
> 1;
|
||||||
|
|
||||||
|
Ok(Some(RoomMember {
|
||||||
|
event: member_event.into(),
|
||||||
profile: profile.into(),
|
profile: profile.into(),
|
||||||
presence: presence.into(),
|
presence: presence.into(),
|
||||||
power_levles: power.into(),
|
power_levles: power.into(),
|
||||||
max_power_level,
|
max_power_level,
|
||||||
is_room_creator,
|
is_room_creator,
|
||||||
|
display_name_ambiguous: ambiguous,
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,10 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use std::sync::{Arc, RwLock};
|
use std::{
|
||||||
|
collections::BTreeSet,
|
||||||
|
sync::{Arc, RwLock},
|
||||||
|
};
|
||||||
|
|
||||||
use dashmap::{DashMap, DashSet};
|
use dashmap::{DashMap, DashSet};
|
||||||
use matrix_sdk_common::{
|
use matrix_sdk_common::{
|
||||||
|
@ -345,4 +348,8 @@ impl StateStore for MemoryStore {
|
||||||
async fn get_stripped_room_infos(&self) -> Result<Vec<StrippedRoomInfo>> {
|
async fn get_stripped_room_infos(&self) -> Result<Vec<StrippedRoomInfo>> {
|
||||||
Ok(self.get_stripped_room_infos())
|
Ok(self.get_stripped_room_infos())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_users_with_display_name(&self, _: &RoomId, _: &str) -> Result<BTreeSet<UserId>> {
|
||||||
|
Ok(BTreeSet::new())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,12 @@
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
use std::{collections::BTreeMap, ops::Deref, path::Path, sync::Arc};
|
use std::{
|
||||||
|
collections::{BTreeMap, BTreeSet},
|
||||||
|
ops::Deref,
|
||||||
|
path::Path,
|
||||||
|
sync::Arc,
|
||||||
|
};
|
||||||
|
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use matrix_sdk_common::{
|
use matrix_sdk_common::{
|
||||||
|
@ -101,6 +106,12 @@ pub trait StateStore: AsyncTraitDeps {
|
||||||
async fn get_room_infos(&self) -> Result<Vec<RoomInfo>>;
|
async fn get_room_infos(&self) -> Result<Vec<RoomInfo>>;
|
||||||
|
|
||||||
async fn get_stripped_room_infos(&self) -> Result<Vec<StrippedRoomInfo>>;
|
async fn get_stripped_room_infos(&self) -> Result<Vec<StrippedRoomInfo>>;
|
||||||
|
|
||||||
|
async fn get_users_with_display_name(
|
||||||
|
&self,
|
||||||
|
room_id: &RoomId,
|
||||||
|
display_name: &str,
|
||||||
|
) -> Result<BTreeSet<UserId>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
|
|
||||||
mod store_key;
|
mod store_key;
|
||||||
|
|
||||||
use std::{convert::TryFrom, path::Path, sync::Arc, time::SystemTime};
|
use std::{collections::BTreeSet, convert::TryFrom, path::Path, sync::Arc, time::SystemTime};
|
||||||
|
|
||||||
use futures::{
|
use futures::{
|
||||||
stream::{self, Stream},
|
stream::{self, Stream},
|
||||||
|
@ -79,6 +79,43 @@ impl From<SerializationError> for StoreError {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
trait EncodeKey {
|
||||||
|
const SEPARATOR: u8 = 0xff;
|
||||||
|
fn encode(&self) -> Vec<u8>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EncodeKey for &str {
|
||||||
|
fn encode(&self) -> Vec<u8> {
|
||||||
|
[self.as_bytes(), &[Self::SEPARATOR]].concat()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EncodeKey for (&str, &str) {
|
||||||
|
fn encode(&self) -> Vec<u8> {
|
||||||
|
[
|
||||||
|
self.0.as_bytes(),
|
||||||
|
&[Self::SEPARATOR],
|
||||||
|
self.1.as_bytes(),
|
||||||
|
&[Self::SEPARATOR],
|
||||||
|
]
|
||||||
|
.concat()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EncodeKey for (&str, &str, &str) {
|
||||||
|
fn encode(&self) -> Vec<u8> {
|
||||||
|
[
|
||||||
|
self.0.as_bytes(),
|
||||||
|
&[Self::SEPARATOR],
|
||||||
|
self.1.as_bytes(),
|
||||||
|
&[Self::SEPARATOR],
|
||||||
|
self.2.as_bytes(),
|
||||||
|
&[Self::SEPARATOR],
|
||||||
|
]
|
||||||
|
.concat()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct SledStore {
|
pub struct SledStore {
|
||||||
pub(crate) inner: Db,
|
pub(crate) inner: Db,
|
||||||
|
@ -87,6 +124,7 @@ pub struct SledStore {
|
||||||
account_data: Tree,
|
account_data: Tree,
|
||||||
members: Tree,
|
members: Tree,
|
||||||
profiles: Tree,
|
profiles: Tree,
|
||||||
|
display_names: Tree,
|
||||||
joined_user_ids: Tree,
|
joined_user_ids: Tree,
|
||||||
invited_user_ids: Tree,
|
invited_user_ids: Tree,
|
||||||
room_info: Tree,
|
room_info: Tree,
|
||||||
|
@ -105,6 +143,7 @@ impl SledStore {
|
||||||
|
|
||||||
let members = db.open_tree("members")?;
|
let members = db.open_tree("members")?;
|
||||||
let profiles = db.open_tree("profiles")?;
|
let profiles = db.open_tree("profiles")?;
|
||||||
|
let display_names = db.open_tree("display_names")?;
|
||||||
let joined_user_ids = db.open_tree("joined_user_ids")?;
|
let joined_user_ids = db.open_tree("joined_user_ids")?;
|
||||||
let invited_user_ids = db.open_tree("invited_user_ids")?;
|
let invited_user_ids = db.open_tree("invited_user_ids")?;
|
||||||
|
|
||||||
|
@ -124,6 +163,7 @@ impl SledStore {
|
||||||
account_data,
|
account_data,
|
||||||
members,
|
members,
|
||||||
profiles,
|
profiles,
|
||||||
|
display_names,
|
||||||
joined_user_ids,
|
joined_user_ids,
|
||||||
invited_user_ids,
|
invited_user_ids,
|
||||||
room_account_data,
|
room_account_data,
|
||||||
|
@ -230,6 +270,7 @@ impl SledStore {
|
||||||
&self.account_data,
|
&self.account_data,
|
||||||
&self.members,
|
&self.members,
|
||||||
&self.profiles,
|
&self.profiles,
|
||||||
|
&self.display_names,
|
||||||
&self.joined_user_ids,
|
&self.joined_user_ids,
|
||||||
&self.invited_user_ids,
|
&self.invited_user_ids,
|
||||||
&self.room_info,
|
&self.room_info,
|
||||||
|
@ -246,6 +287,7 @@ impl SledStore {
|
||||||
account_data,
|
account_data,
|
||||||
members,
|
members,
|
||||||
profiles,
|
profiles,
|
||||||
|
display_names,
|
||||||
joined,
|
joined,
|
||||||
invited,
|
invited,
|
||||||
rooms,
|
rooms,
|
||||||
|
@ -261,41 +303,91 @@ impl SledStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (room, events) in &changes.members {
|
for (room, events) in &changes.members {
|
||||||
|
let profile_changes = changes.profiles.get(room);
|
||||||
|
|
||||||
for event in events.values() {
|
for event in events.values() {
|
||||||
let key = format!("{}{}", room.as_str(), event.state_key.as_str());
|
let key = format!("{}{}", room.as_str(), event.state_key.as_str());
|
||||||
|
|
||||||
|
let old_profile: Option<MemberEventContent> = if let Some(p) = profiles
|
||||||
|
.get(key.as_str())?
|
||||||
|
.map(|p| self.deserialize_event(&p))
|
||||||
|
.transpose()
|
||||||
|
.map_err(ConflictableTransactionError::Abort)?
|
||||||
|
{
|
||||||
|
p
|
||||||
|
} else {
|
||||||
|
members
|
||||||
|
.get(key.as_str())?
|
||||||
|
.map(|m| self.deserialize_event::<MemberEvent>(&m))
|
||||||
|
.transpose()
|
||||||
|
.map_err(ConflictableTransactionError::Abort)?
|
||||||
|
.map(|m| m.content)
|
||||||
|
};
|
||||||
|
|
||||||
|
let old_display_name = old_profile
|
||||||
|
.map(|m| {
|
||||||
|
m.displayname
|
||||||
|
.unwrap_or_else(|| event.state_key.localpart().to_string())
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|| event.state_key.localpart().to_string());
|
||||||
|
|
||||||
|
let old_display_name_key = (
|
||||||
|
room.as_str(),
|
||||||
|
old_display_name.as_str(),
|
||||||
|
event.state_key.as_str(),
|
||||||
|
)
|
||||||
|
.encode();
|
||||||
|
|
||||||
|
let display_name = profile_changes
|
||||||
|
.map(|p| p.get(&event.state_key))
|
||||||
|
.flatten()
|
||||||
|
.as_ref()
|
||||||
|
.map(|m| m.displayname.as_deref())
|
||||||
|
.unwrap_or_else(|| Some(event.state_key.localpart()))
|
||||||
|
.unwrap_or_else(|| event.state_key.localpart());
|
||||||
|
|
||||||
|
let display_name_key =
|
||||||
|
(room.as_str(), display_name, event.state_key.as_str()).encode();
|
||||||
|
|
||||||
match event.content.membership {
|
match event.content.membership {
|
||||||
MembershipState::Join => {
|
MembershipState::Join => {
|
||||||
joined.insert(key.as_str(), event.state_key.as_str())?;
|
joined.insert(key.as_str(), event.state_key.as_str())?;
|
||||||
invited.remove(key.as_str())?;
|
invited.remove(key.as_str())?;
|
||||||
|
display_names.remove(old_display_name_key)?;
|
||||||
|
display_names
|
||||||
|
.insert(display_name_key, event.state_key.as_str())?;
|
||||||
}
|
}
|
||||||
MembershipState::Invite => {
|
MembershipState::Invite => {
|
||||||
invited.insert(key.as_str(), event.state_key.as_str())?;
|
invited.insert(key.as_str(), event.state_key.as_str())?;
|
||||||
joined.remove(key.as_str())?;
|
joined.remove(key.as_str())?;
|
||||||
|
display_names.remove(old_display_name_key)?;
|
||||||
|
display_names
|
||||||
|
.insert(display_name_key, event.state_key.as_str())?;
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
|
display_names.remove(old_display_name_key)?;
|
||||||
joined.remove(key.as_str())?;
|
joined.remove(key.as_str())?;
|
||||||
invited.remove(key.as_str())?;
|
invited.remove(key.as_str())?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
members.insert(
|
members.insert(
|
||||||
format!("{}{}", room.as_str(), &event.state_key).as_str(),
|
key.as_str(),
|
||||||
self.serialize_event(&event)
|
self.serialize_event(&event)
|
||||||
.map_err(ConflictableTransactionError::Abort)?,
|
.map_err(ConflictableTransactionError::Abort)?,
|
||||||
)?;
|
)?;
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (room, users) in &changes.profiles {
|
if let Some(profile) =
|
||||||
for (user_id, profile) in users {
|
profile_changes.map(|p| p.get(&event.state_key)).flatten()
|
||||||
|
{
|
||||||
profiles.insert(
|
profiles.insert(
|
||||||
format!("{}{}", room.as_str(), user_id.as_str()).as_str(),
|
key.as_str(),
|
||||||
self.serialize_event(&profile)
|
self.serialize_event(&profile)
|
||||||
.map_err(ConflictableTransactionError::Abort)?,
|
.map_err(ConflictableTransactionError::Abort)?,
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (event_type, event) in &changes.account_data {
|
for (event_type, event) in &changes.account_data {
|
||||||
account_data.insert(
|
account_data.insert(
|
||||||
|
@ -449,7 +541,7 @@ impl SledStore {
|
||||||
) -> impl Stream<Item = Result<UserId>> {
|
) -> impl Stream<Item = Result<UserId>> {
|
||||||
stream::iter(
|
stream::iter(
|
||||||
self.invited_user_ids
|
self.invited_user_ids
|
||||||
.scan_prefix(room_id.as_bytes())
|
.scan_prefix(room_id.as_str())
|
||||||
.map(|u| {
|
.map(|u| {
|
||||||
UserId::try_from(String::from_utf8_lossy(&u?.1).to_string())
|
UserId::try_from(String::from_utf8_lossy(&u?.1).to_string())
|
||||||
.map_err(StoreError::Identifier)
|
.map_err(StoreError::Identifier)
|
||||||
|
@ -461,14 +553,10 @@ impl SledStore {
|
||||||
&self,
|
&self,
|
||||||
room_id: &RoomId,
|
room_id: &RoomId,
|
||||||
) -> impl Stream<Item = Result<UserId>> {
|
) -> impl Stream<Item = Result<UserId>> {
|
||||||
stream::iter(
|
stream::iter(self.joined_user_ids.scan_prefix(room_id.as_str()).map(|u| {
|
||||||
self.joined_user_ids
|
|
||||||
.scan_prefix(room_id.as_bytes())
|
|
||||||
.map(|u| {
|
|
||||||
UserId::try_from(String::from_utf8_lossy(&u?.1).to_string())
|
UserId::try_from(String::from_utf8_lossy(&u?.1).to_string())
|
||||||
.map_err(StoreError::Identifier)
|
.map_err(StoreError::Identifier)
|
||||||
}),
|
}))
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_room_infos(&self) -> impl Stream<Item = Result<RoomInfo>> {
|
pub async fn get_room_infos(&self) -> impl Stream<Item = Result<RoomInfo>> {
|
||||||
|
@ -488,6 +576,22 @@ impl SledStore {
|
||||||
.map(move |r| db.deserialize_event(&r?.1).map_err(|e| e.into())),
|
.map(move |r| db.deserialize_event(&r?.1).map_err(|e| e.into())),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn get_users_with_display_name(
|
||||||
|
&self,
|
||||||
|
room_id: &RoomId,
|
||||||
|
display_name: &str,
|
||||||
|
) -> Result<BTreeSet<UserId>> {
|
||||||
|
let key = (room_id.as_str(), display_name).encode();
|
||||||
|
|
||||||
|
self.display_names
|
||||||
|
.scan_prefix(key)
|
||||||
|
.map(|u| {
|
||||||
|
UserId::try_from(String::from_utf8_lossy(&u?.1).to_string())
|
||||||
|
.map_err(StoreError::Identifier)
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
|
@ -552,6 +656,15 @@ impl StateStore for SledStore {
|
||||||
async fn get_stripped_room_infos(&self) -> Result<Vec<StrippedRoomInfo>> {
|
async fn get_stripped_room_infos(&self) -> Result<Vec<StrippedRoomInfo>> {
|
||||||
self.get_stripped_room_infos().await.try_collect().await
|
self.get_stripped_room_infos().await.try_collect().await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn get_users_with_display_name(
|
||||||
|
&self,
|
||||||
|
room_id: &RoomId,
|
||||||
|
display_name: &str,
|
||||||
|
) -> Result<BTreeSet<UserId>> {
|
||||||
|
self.get_users_with_display_name(room_id, display_name)
|
||||||
|
.await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
Loading…
Reference in New Issue