base: Initial set of docs
parent
10da61c567
commit
58691986a9
|
@ -955,6 +955,15 @@ impl BaseClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Receive a get member events response and convert it to a deserialized
|
||||||
|
/// `MembersResponse`
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `room_id` - The room id this response belongs to.
|
||||||
|
///
|
||||||
|
/// * `response` - The raw response that was received from the server.
|
||||||
pub async fn receive_members(
|
pub async fn receive_members(
|
||||||
&self,
|
&self,
|
||||||
room_id: &RoomId,
|
room_id: &RoomId,
|
||||||
|
@ -1037,6 +1046,21 @@ impl BaseClient {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Receive a successful filter upload response, the filter id will be
|
||||||
|
/// stored under the given name in the store.
|
||||||
|
///
|
||||||
|
/// The filter id can later be retrieved with the [`get_filter`] method.
|
||||||
|
///
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `filter_name` - The name that should be used to persist the filter id in
|
||||||
|
/// the store.
|
||||||
|
///
|
||||||
|
/// * `response` - The successful filter upload response containing the
|
||||||
|
/// filter id.
|
||||||
|
///
|
||||||
|
/// [`get_filter`]: #method.get_filter
|
||||||
pub async fn receive_filter_upload(
|
pub async fn receive_filter_upload(
|
||||||
&self,
|
&self,
|
||||||
filter_name: &str,
|
filter_name: &str,
|
||||||
|
@ -1048,6 +1072,17 @@ impl BaseClient {
|
||||||
.await?)
|
.await?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the filter id of a previously uploaded filter.
|
||||||
|
///
|
||||||
|
/// *Note*: A filter will first need to be uploaded and persisted using
|
||||||
|
/// [`receive_filter_upload`].
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `filter_name` - The name of the filter that was previously used to
|
||||||
|
/// persist the filter.
|
||||||
|
///
|
||||||
|
/// [`receive_filter_upload`]: #method.receive_filter_upload
|
||||||
pub async fn get_filter(&self, filter_name: &str) -> StoreResult<Option<String>> {
|
pub async fn get_filter(&self, filter_name: &str) -> StoreResult<Option<String>> {
|
||||||
self.store.get_filter(filter_name).await
|
self.store.get_filter(filter_name).await
|
||||||
}
|
}
|
||||||
|
@ -1131,6 +1166,11 @@ impl BaseClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the room with the given room id.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `room_id` - The id of the room that should be fetched.
|
||||||
pub fn get_room(&self, room_id: &RoomId) -> Option<RoomState> {
|
pub fn get_room(&self, room_id: &RoomId) -> Option<RoomState> {
|
||||||
self.store.get_room(room_id)
|
self.store.get_room(room_id)
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,7 +52,7 @@ mod store;
|
||||||
|
|
||||||
pub use event_emitter::EventEmitter;
|
pub use event_emitter::EventEmitter;
|
||||||
pub use rooms::{InvitedRoom, JoinedRoom, LeftRoom, Room, RoomInfo, RoomMember, RoomState};
|
pub use rooms::{InvitedRoom, JoinedRoom, LeftRoom, Room, RoomInfo, RoomMember, RoomState};
|
||||||
pub use store::{Store, StoreError};
|
pub use store::{StateStore, Store, StoreError};
|
||||||
|
|
||||||
pub use client::{BaseClient, BaseClientConfig, RoomStateType};
|
pub use client::{BaseClient, BaseClientConfig, RoomStateType};
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ use matrix_sdk_common::{
|
||||||
|
|
||||||
use crate::deserialized_responses::MemberEvent;
|
use crate::deserialized_responses::MemberEvent;
|
||||||
|
|
||||||
|
/// A member of a room.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct RoomMember {
|
pub struct RoomMember {
|
||||||
pub(crate) event: Arc<MemberEvent>,
|
pub(crate) event: Arc<MemberEvent>,
|
||||||
|
@ -37,10 +38,12 @@ pub struct RoomMember {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RoomMember {
|
impl RoomMember {
|
||||||
|
/// Get the unique user id of this member.
|
||||||
pub fn user_id(&self) -> &UserId {
|
pub fn user_id(&self) -> &UserId {
|
||||||
&self.event.state_key
|
&self.event.state_key
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the display name of the member if ther is one.
|
||||||
pub fn display_name(&self) -> Option<&str> {
|
pub fn display_name(&self) -> Option<&str> {
|
||||||
if let Some(p) = self.profile.as_ref() {
|
if let Some(p) = self.profile.as_ref() {
|
||||||
p.displayname.as_deref()
|
p.displayname.as_deref()
|
||||||
|
@ -49,6 +52,10 @@ impl RoomMember {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the name of the member.
|
||||||
|
///
|
||||||
|
/// This returns either the display name or the local part of the user id if
|
||||||
|
/// the member didn't set a display name.
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
if let Some(d) = self.display_name() {
|
if let Some(d) = self.display_name() {
|
||||||
d
|
d
|
||||||
|
@ -57,6 +64,7 @@ impl RoomMember {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the avatar url of the member, if ther is one.
|
||||||
pub fn avatar_url(&self) -> Option<&str> {
|
pub fn avatar_url(&self) -> Option<&str> {
|
||||||
match self.profile.as_ref() {
|
match self.profile.as_ref() {
|
||||||
Some(p) => p.avatar_url.as_deref(),
|
Some(p) => p.avatar_url.as_deref(),
|
||||||
|
@ -64,6 +72,10 @@ impl RoomMember {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the normalized power level of this member.
|
||||||
|
///
|
||||||
|
/// The normalized power level depends on the maximum power level that can
|
||||||
|
/// be found in a certain room, it's always in the range of 0-100.
|
||||||
pub fn normalized_power_level(&self) -> i64 {
|
pub fn normalized_power_level(&self) -> i64 {
|
||||||
if self.max_power_level > 0 {
|
if self.max_power_level > 0 {
|
||||||
(self.power_level() * 100) / self.max_power_level
|
(self.power_level() * 100) / self.max_power_level
|
||||||
|
@ -72,6 +84,7 @@ impl RoomMember {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the power level of this member.
|
||||||
pub fn power_level(&self) -> i64 {
|
pub fn power_level(&self) -> i64 {
|
||||||
self.power_levles
|
self.power_levles
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
@ -85,4 +98,12 @@ impl RoomMember {
|
||||||
})
|
})
|
||||||
.unwrap_or_else(|| if self.is_room_creator { 100 } else { 0 })
|
.unwrap_or_else(|| if self.is_room_creator { 100 } else { 0 })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Is the name that the member uses ambiguous in the room.
|
||||||
|
///
|
||||||
|
/// A name is considered to be ambiguous if at least one other member shares
|
||||||
|
/// the same name.
|
||||||
|
pub fn name_ambiguous(&self) -> bool {
|
||||||
|
self.display_name_ambiguous
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,8 @@ pub enum RoomState {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RoomState {
|
impl RoomState {
|
||||||
|
/// Destructure the room into a `JoinedRoom` if the room is in the joined
|
||||||
|
/// state.
|
||||||
pub fn joined(self) -> Option<JoinedRoom> {
|
pub fn joined(self) -> Option<JoinedRoom> {
|
||||||
if let RoomState::Joined(r) = self {
|
if let RoomState::Joined(r) = self {
|
||||||
Some(r)
|
Some(r)
|
||||||
|
@ -49,6 +51,8 @@ impl RoomState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Destructure the room into an `InvitedRoom` if the room is in the invited
|
||||||
|
/// state.
|
||||||
pub fn invited(self) -> Option<InvitedRoom> {
|
pub fn invited(self) -> Option<InvitedRoom> {
|
||||||
if let RoomState::Invited(r) = self {
|
if let RoomState::Invited(r) = self {
|
||||||
Some(r)
|
Some(r)
|
||||||
|
@ -57,6 +61,8 @@ impl RoomState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Destructure the room into a `LeftRoom` if the room is in the left
|
||||||
|
/// state.
|
||||||
pub fn left(self) -> Option<LeftRoom> {
|
pub fn left(self) -> Option<LeftRoom> {
|
||||||
if let RoomState::Left(r) = self {
|
if let RoomState::Left(r) = self {
|
||||||
Some(r)
|
Some(r)
|
||||||
|
@ -65,6 +71,7 @@ impl RoomState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Is the room encrypted.
|
||||||
pub fn is_encrypted(&self) -> bool {
|
pub fn is_encrypted(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
RoomState::Joined(r) => r.inner.is_encrypted(),
|
RoomState::Joined(r) => r.inner.is_encrypted(),
|
||||||
|
@ -73,6 +80,7 @@ impl RoomState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Are the members for this room synced.
|
||||||
pub fn are_members_synced(&self) -> bool {
|
pub fn are_members_synced(&self) -> bool {
|
||||||
if let RoomState::Joined(r) = self {
|
if let RoomState::Joined(r) = self {
|
||||||
r.inner.are_members_synced()
|
r.inner.are_members_synced()
|
||||||
|
@ -82,12 +90,12 @@ impl RoomState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A room in a joined state.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct JoinedRoom {
|
pub struct JoinedRoom {
|
||||||
pub(crate) inner: Room,
|
pub(crate) inner: Room,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO do we wan't to deref here or have separate implementations.
|
|
||||||
impl Deref for JoinedRoom {
|
impl Deref for JoinedRoom {
|
||||||
type Target = Room;
|
type Target = Room;
|
||||||
|
|
||||||
|
@ -96,6 +104,7 @@ impl Deref for JoinedRoom {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A room in a left state.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct LeftRoom {
|
pub struct LeftRoom {
|
||||||
pub(crate) inner: Room,
|
pub(crate) inner: Room,
|
||||||
|
@ -109,6 +118,7 @@ impl Deref for LeftRoom {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A room in an invited state.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct InvitedRoom {
|
pub struct InvitedRoom {
|
||||||
pub(crate) inner: StrippedRoom,
|
pub(crate) inner: StrippedRoom,
|
||||||
|
@ -122,23 +132,40 @@ impl Deref for InvitedRoom {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A base room info struct that is the backbone of normal as well as stripped
|
||||||
|
/// rooms. Holds all the state events that are important to present a room to
|
||||||
|
/// users.
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct BaseRoomInfo {
|
pub struct BaseRoomInfo {
|
||||||
|
/// The avatar URL of this room.
|
||||||
pub avatar_url: Option<String>,
|
pub avatar_url: Option<String>,
|
||||||
|
/// The canonical alias of this room.
|
||||||
pub canonical_alias: Option<RoomAliasId>,
|
pub canonical_alias: Option<RoomAliasId>,
|
||||||
|
/// The `m.room.create` event content of this room.
|
||||||
pub create: Option<CreateEventContent>,
|
pub create: Option<CreateEventContent>,
|
||||||
|
/// The user id this room is sharing the direct message with, if the room is
|
||||||
|
/// a direct message.
|
||||||
pub dm_target: Option<UserId>,
|
pub dm_target: Option<UserId>,
|
||||||
|
/// The `m.room.encryption` event content that enabled E2EE in this room.
|
||||||
pub encryption: Option<EncryptionEventContent>,
|
pub encryption: Option<EncryptionEventContent>,
|
||||||
|
/// The guest access policy of this room.
|
||||||
pub guest_access: GuestAccess,
|
pub guest_access: GuestAccess,
|
||||||
|
/// The history visiblity policy of this room.
|
||||||
pub history_visibility: HistoryVisibility,
|
pub history_visibility: HistoryVisibility,
|
||||||
|
/// The join rule policy of this room.
|
||||||
pub join_rule: JoinRule,
|
pub join_rule: JoinRule,
|
||||||
|
/// The maximal power level that can be found in this room.
|
||||||
pub max_power_level: i64,
|
pub max_power_level: i64,
|
||||||
|
/// The `m.room.name` of this room.
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
|
/// The `m.room.tombstone` event content of this room.
|
||||||
pub tombstone: Option<TombstoneEventContent>,
|
pub tombstone: Option<TombstoneEventContent>,
|
||||||
|
/// The topic of this room.
|
||||||
pub topic: Option<String>,
|
pub topic: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BaseRoomInfo {
|
impl BaseRoomInfo {
|
||||||
|
/// Create a new, empty base room info.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self::default()
|
Self::default()
|
||||||
}
|
}
|
||||||
|
@ -181,6 +208,9 @@ impl BaseRoomInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Handle a state event for this room and update our info accordingly.
|
||||||
|
///
|
||||||
|
/// Returns true if the event modified the info, false otherwise.
|
||||||
pub fn handle_state_event(&mut self, content: &AnyStateEventContent) -> bool {
|
pub fn handle_state_event(&mut self, content: &AnyStateEventContent) -> bool {
|
||||||
match content {
|
match content {
|
||||||
AnyStateEventContent::RoomEncryption(encryption) => {
|
AnyStateEventContent::RoomEncryption(encryption) => {
|
||||||
|
|
|
@ -43,6 +43,7 @@ use crate::{
|
||||||
|
|
||||||
use super::{BaseRoomInfo, RoomMember};
|
use super::{BaseRoomInfo, RoomMember};
|
||||||
|
|
||||||
|
/// The underlying room data structure collecting state for joined and left rooms.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Room {
|
pub struct Room {
|
||||||
room_id: Arc<RoomId>,
|
room_id: Arc<RoomId>,
|
||||||
|
@ -51,21 +52,28 @@ pub struct Room {
|
||||||
store: Arc<Box<dyn StateStore>>,
|
store: Arc<Box<dyn StateStore>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The room summary containing member counts and members that should be used to
|
||||||
|
/// calculate the room display name.
|
||||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||||
pub struct RoomSummary {
|
pub struct RoomSummary {
|
||||||
|
/// The heroes of the room, members that should be used for the room display
|
||||||
|
/// name.
|
||||||
heroes: Vec<String>,
|
heroes: Vec<String>,
|
||||||
|
/// The number of members that are considered to be joined to the room.
|
||||||
joined_member_count: u64,
|
joined_member_count: u64,
|
||||||
|
/// The number of members that are considered to be invited to the room.
|
||||||
invited_member_count: u64,
|
invited_member_count: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Signals to the `BaseClient` which `RoomState` to send to `EventEmitter`.
|
/// Enum keeping track in which state the room is, e.g. if our own user is
|
||||||
|
/// joined, invited, or has left the room.
|
||||||
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Copy, Debug, Serialize, Deserialize)]
|
||||||
pub enum RoomType {
|
pub enum RoomType {
|
||||||
/// Represents a joined room, the `joined_rooms` HashMap will be used.
|
/// The room is in a joined state.
|
||||||
Joined,
|
Joined,
|
||||||
/// Represents a left room, the `left_rooms` HashMap will be used.
|
/// The room is in a left state.
|
||||||
Left,
|
Left,
|
||||||
/// Represents an invited room, the `invited_rooms` HashMap will be used.
|
/// The room is in a invited state.
|
||||||
Invited,
|
Invited,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -104,62 +112,92 @@ impl Room {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the unique room id of the room.
|
||||||
pub fn room_id(&self) -> &RoomId {
|
pub fn room_id(&self) -> &RoomId {
|
||||||
&self.room_id
|
&self.room_id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get our own user id.
|
||||||
pub fn own_user_id(&self) -> &UserId {
|
pub fn own_user_id(&self) -> &UserId {
|
||||||
&self.own_user_id
|
&self.own_user_id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the type of the room.
|
||||||
pub fn room_type(&self) -> RoomType {
|
pub fn room_type(&self) -> RoomType {
|
||||||
self.inner.read().unwrap().room_type
|
self.inner.read().unwrap().room_type
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the unread notification counts.
|
||||||
pub fn unread_notification_counts(&self) -> UnreadNotificationsCount {
|
pub fn unread_notification_counts(&self) -> UnreadNotificationsCount {
|
||||||
self.inner.read().unwrap().notification_counts
|
self.inner.read().unwrap().notification_counts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Check if the room has it's members fully synced.
|
||||||
|
///
|
||||||
|
/// Members might be missing if lazy member loading was enabled for the sync.
|
||||||
|
///
|
||||||
|
/// Returns true if no members are missing, false otherwise.
|
||||||
pub fn are_members_synced(&self) -> bool {
|
pub fn are_members_synced(&self) -> bool {
|
||||||
self.inner.read().unwrap().members_synced
|
self.inner.read().unwrap().members_synced
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the `prev_batch` token that was received from the last sync. May be
|
||||||
|
/// `None` if the last sync contained the full room history.
|
||||||
pub fn last_prev_batch(&self) -> Option<String> {
|
pub fn last_prev_batch(&self) -> Option<String> {
|
||||||
self.inner.read().unwrap().last_prev_batch.clone()
|
self.inner.read().unwrap().last_prev_batch.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the avatar url of this room.
|
||||||
pub fn avatar_url(&self) -> Option<String> {
|
pub fn avatar_url(&self) -> Option<String> {
|
||||||
self.inner.read().unwrap().base_info.avatar_url.clone()
|
self.inner.read().unwrap().base_info.avatar_url.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the canonical alias of this room.
|
||||||
pub fn canonical_alias(&self) -> Option<RoomAliasId> {
|
pub fn canonical_alias(&self) -> Option<RoomAliasId> {
|
||||||
self.inner.read().unwrap().base_info.canonical_alias.clone()
|
self.inner.read().unwrap().base_info.canonical_alias.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the `m.room.create` content of this room.
|
||||||
|
///
|
||||||
|
/// This usually isn't optional but some servers might not send an
|
||||||
|
/// `m.room.create` event as the first event for a given room, thus this can
|
||||||
|
/// be optional.
|
||||||
pub fn create_content(&self) -> Option<CreateEventContent> {
|
pub fn create_content(&self) -> Option<CreateEventContent> {
|
||||||
self.inner.read().unwrap().base_info.create.clone()
|
self.inner.read().unwrap().base_info.create.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Is this room considered a direct message.
|
||||||
pub fn is_direct(&self) -> bool {
|
pub fn is_direct(&self) -> bool {
|
||||||
self.inner.read().unwrap().base_info.dm_target.is_some()
|
self.inner.read().unwrap().base_info.dm_target.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If this room is a direct message, get the member that we're sharing the
|
||||||
|
/// room with.
|
||||||
|
///
|
||||||
|
/// *Note*: The member list might have been moddified in the meantime and
|
||||||
|
/// the target might not even be in the room anymore. This setting should
|
||||||
|
/// only be considered as guidance.
|
||||||
pub fn direct_target(&self) -> Option<UserId> {
|
pub fn direct_target(&self) -> Option<UserId> {
|
||||||
self.inner.read().unwrap().base_info.dm_target.clone()
|
self.inner.read().unwrap().base_info.dm_target.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Is the room encrypted.
|
||||||
pub fn is_encrypted(&self) -> bool {
|
pub fn is_encrypted(&self) -> bool {
|
||||||
self.inner.read().unwrap().is_encrypted()
|
self.inner.read().unwrap().is_encrypted()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the `m.room.encryption` content that enabled end to end encryption
|
||||||
|
/// in the room.
|
||||||
pub fn encryption_settings(&self) -> Option<EncryptionEventContent> {
|
pub fn encryption_settings(&self) -> Option<EncryptionEventContent> {
|
||||||
self.inner.read().unwrap().base_info.encryption.clone()
|
self.inner.read().unwrap().base_info.encryption.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the guest access policy of this room.
|
||||||
pub fn guest_access(&self) -> GuestAccess {
|
pub fn guest_access(&self) -> GuestAccess {
|
||||||
self.inner.read().unwrap().base_info.guest_access.clone()
|
self.inner.read().unwrap().base_info.guest_access.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the history visiblity policy of this room.
|
||||||
pub fn history_visibility(&self) -> HistoryVisibility {
|
pub fn history_visibility(&self) -> HistoryVisibility {
|
||||||
self.inner
|
self.inner
|
||||||
.read()
|
.read()
|
||||||
|
@ -169,42 +207,62 @@ impl Room {
|
||||||
.clone()
|
.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Is the room considered to be public.
|
||||||
pub fn is_public(&self) -> bool {
|
pub fn is_public(&self) -> bool {
|
||||||
matches!(self.join_rule(), JoinRule::Public)
|
matches!(self.join_rule(), JoinRule::Public)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the join rule policy of this room.
|
||||||
pub fn join_rule(&self) -> JoinRule {
|
pub fn join_rule(&self) -> JoinRule {
|
||||||
self.inner.read().unwrap().base_info.join_rule.clone()
|
self.inner.read().unwrap().base_info.join_rule.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the maximum power level that this room contains.
|
||||||
|
///
|
||||||
|
/// This is useful if one wishes to normalize the power levels, e.g. from
|
||||||
|
/// 0-100 where 100 would be the max power level.
|
||||||
pub fn max_power_level(&self) -> i64 {
|
pub fn max_power_level(&self) -> i64 {
|
||||||
self.inner.read().unwrap().base_info.max_power_level
|
self.inner.read().unwrap().base_info.max_power_level
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the `m.room.name` of this room.
|
||||||
pub fn name(&self) -> Option<String> {
|
pub fn name(&self) -> Option<String> {
|
||||||
self.inner.read().unwrap().base_info.name.clone()
|
self.inner.read().unwrap().base_info.name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Has the room been tombstoned.
|
||||||
pub fn is_tombstoned(&self) -> bool {
|
pub fn is_tombstoned(&self) -> bool {
|
||||||
self.inner.read().unwrap().base_info.tombstone.is_some()
|
self.inner.read().unwrap().base_info.tombstone.is_some()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the `m.room.tombstone` content of this room if there is one.
|
||||||
pub fn tombstone(&self) -> Option<TombstoneEventContent> {
|
pub fn tombstone(&self) -> Option<TombstoneEventContent> {
|
||||||
self.inner.read().unwrap().base_info.tombstone.clone()
|
self.inner.read().unwrap().base_info.tombstone.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the topic of the room.
|
||||||
pub fn topic(&self) -> Option<String> {
|
pub fn topic(&self) -> Option<String> {
|
||||||
self.inner.read().unwrap().base_info.topic.clone()
|
self.inner.read().unwrap().base_info.topic.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Calculate the canonical display name of the room, taking into account
|
||||||
|
/// its name, aliases and members.
|
||||||
|
///
|
||||||
|
/// The display name is calculated according to [this algorithm][spec].
|
||||||
|
///
|
||||||
|
/// [spec]: <https://matrix.org/docs/spec/client_server/latest#calculating-the-display-name-for-a-room>
|
||||||
pub async fn display_name(&self) -> StoreResult<String> {
|
pub async fn display_name(&self) -> StoreResult<String> {
|
||||||
self.calculate_name().await
|
self.calculate_name().await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the list of users ids that are considered to be joined members of
|
||||||
|
/// this room.
|
||||||
pub async fn joined_user_ids(&self) -> StoreResult<Vec<UserId>> {
|
pub async fn joined_user_ids(&self) -> StoreResult<Vec<UserId>> {
|
||||||
self.store.get_joined_user_ids(self.room_id()).await
|
self.store.get_joined_user_ids(self.room_id()).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the list of `RoomMember`s that are considered to be joined members
|
||||||
|
/// of this room.
|
||||||
pub async fn joined_members(&self) -> StoreResult<Vec<RoomMember>> {
|
pub async fn joined_members(&self) -> StoreResult<Vec<RoomMember>> {
|
||||||
let joined = self.store.get_joined_user_ids(self.room_id()).await?;
|
let joined = self.store.get_joined_user_ids(self.room_id()).await?;
|
||||||
let mut members = Vec::new();
|
let mut members = Vec::new();
|
||||||
|
@ -220,6 +278,8 @@ impl Room {
|
||||||
Ok(members)
|
Ok(members)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the list of `RoomMember`s that are considered to be joined or
|
||||||
|
/// invited members of this room.
|
||||||
pub async fn active_members(&self) -> StoreResult<Vec<RoomMember>> {
|
pub async fn active_members(&self) -> StoreResult<Vec<RoomMember>> {
|
||||||
let joined = self.store.get_joined_user_ids(self.room_id()).await?;
|
let joined = self.store.get_joined_user_ids(self.room_id()).await?;
|
||||||
let invited = self.store.get_invited_user_ids(self.room_id()).await?;
|
let invited = self.store.get_invited_user_ids(self.room_id()).await?;
|
||||||
|
@ -237,13 +297,6 @@ impl Room {
|
||||||
Ok(members)
|
Ok(members)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculate the canonical display name of the room, taking into account
|
|
||||||
/// its name, aliases and members.
|
|
||||||
///
|
|
||||||
/// The display name is calculated according to [this algorithm][spec].
|
|
||||||
///
|
|
||||||
/// [spec]:
|
|
||||||
/// <https://matrix.org/docs/spec/client_server/latest#calculating-the-display-name-for-a-room>
|
|
||||||
async fn calculate_name(&self) -> StoreResult<String> {
|
async fn calculate_name(&self) -> StoreResult<String> {
|
||||||
let summary = {
|
let summary = {
|
||||||
let inner = self.inner.read().unwrap();
|
let inner = self.inner.read().unwrap();
|
||||||
|
@ -306,11 +359,16 @@ impl Room {
|
||||||
(*self.inner.read().unwrap()).clone()
|
(*self.inner.read().unwrap()).clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update_summary(&self, summary: RoomInfo) {
|
pub(crate) fn update_summary(&self, summary: RoomInfo) {
|
||||||
let mut inner = self.inner.write().unwrap();
|
let mut inner = self.inner.write().unwrap();
|
||||||
*inner = summary;
|
*inner = summary;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the `RoomMember` with the given `user_id`.
|
||||||
|
///
|
||||||
|
/// Returns `None` if the member was never part of this room, otherwise
|
||||||
|
/// return a `RoomMember` that can be in a joined, invited, left, banned
|
||||||
|
/// state.
|
||||||
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 =
|
let member_event =
|
||||||
if let Some(m) = self.store.get_member_event(self.room_id(), user_id).await? {
|
if let Some(m) = self.store.get_member_event(self.room_id(), user_id).await? {
|
||||||
|
@ -370,16 +428,25 @@ impl Room {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The underlying pure data structure for joined and left rooms.
|
||||||
|
///
|
||||||
|
/// Holds all the info needed to persist a room into the state store.
|
||||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct RoomInfo {
|
pub struct RoomInfo {
|
||||||
|
/// The unique room id of the room.
|
||||||
pub room_id: Arc<RoomId>,
|
pub room_id: Arc<RoomId>,
|
||||||
|
/// The type of the room.
|
||||||
pub room_type: RoomType,
|
pub room_type: RoomType,
|
||||||
|
/// The unread notifications counts.
|
||||||
pub notification_counts: UnreadNotificationsCount,
|
pub notification_counts: UnreadNotificationsCount,
|
||||||
|
/// The summary of this room.
|
||||||
pub summary: RoomSummary,
|
pub summary: RoomSummary,
|
||||||
|
/// Flag remembering if the room members are synced.
|
||||||
pub members_synced: bool,
|
pub members_synced: bool,
|
||||||
|
/// The prev batch of this room we received durring the last sync.
|
||||||
pub last_prev_batch: Option<String>,
|
pub last_prev_batch: Option<String>,
|
||||||
|
/// Base room info which holds some basic event contents important for the
|
||||||
|
/// room state.
|
||||||
pub base_info: BaseRoomInfo,
|
pub base_info: BaseRoomInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,6 +58,7 @@ pub struct MemoryStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MemoryStore {
|
impl MemoryStore {
|
||||||
|
#[cfg(not(feature = "sled_state_store"))]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
sync_token: Arc::new(RwLock::new(None)),
|
sync_token: Arc::new(RwLock::new(None)),
|
||||||
|
@ -78,22 +79,22 @@ impl MemoryStore {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn save_filter(&self, filter_name: &str, filter_id: &str) -> Result<()> {
|
async fn save_filter(&self, filter_name: &str, filter_id: &str) -> Result<()> {
|
||||||
self.filters
|
self.filters
|
||||||
.insert(filter_name.to_string(), filter_id.to_string());
|
.insert(filter_name.to_string(), filter_id.to_string());
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_filter(&self, filter_name: &str) -> Result<Option<String>> {
|
async fn get_filter(&self, filter_name: &str) -> Result<Option<String>> {
|
||||||
Ok(self.filters.get(filter_name).map(|f| f.to_string()))
|
Ok(self.filters.get(filter_name).map(|f| f.to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_sync_token(&self) -> Result<Option<String>> {
|
async fn get_sync_token(&self) -> Result<Option<String>> {
|
||||||
Ok(self.sync_token.read().unwrap().clone())
|
Ok(self.sync_token.read().unwrap().clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn save_changes(&self, changes: &StateChanges) -> Result<()> {
|
async fn save_changes(&self, changes: &StateChanges) -> Result<()> {
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
|
|
||||||
if let Some(s) = &changes.sync_token {
|
if let Some(s) = &changes.sync_token {
|
||||||
|
@ -227,12 +228,12 @@ impl MemoryStore {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_presence_event(&self, user_id: &UserId) -> Result<Option<PresenceEvent>> {
|
async fn get_presence_event(&self, user_id: &UserId) -> Result<Option<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()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_state_event(
|
async fn get_state_event(
|
||||||
&self,
|
&self,
|
||||||
room_id: &RoomId,
|
room_id: &RoomId,
|
||||||
event_type: EventType,
|
event_type: EventType,
|
||||||
|
@ -245,7 +246,7 @@ impl MemoryStore {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_profile(
|
async fn get_profile(
|
||||||
&self,
|
&self,
|
||||||
room_id: &RoomId,
|
room_id: &RoomId,
|
||||||
user_id: &UserId,
|
user_id: &UserId,
|
||||||
|
@ -257,7 +258,7 @@ impl MemoryStore {
|
||||||
.and_then(|p| p.get(user_id).map(|p| p.clone())))
|
.and_then(|p| p.get(user_id).map(|p| p.clone())))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_member_event(
|
async fn get_member_event(
|
||||||
&self,
|
&self,
|
||||||
room_id: &RoomId,
|
room_id: &RoomId,
|
||||||
state_key: &UserId,
|
state_key: &UserId,
|
||||||
|
|
|
@ -44,23 +44,33 @@ mod memory_store;
|
||||||
#[cfg(feature = "sled_state_store")]
|
#[cfg(feature = "sled_state_store")]
|
||||||
mod sled_store;
|
mod sled_store;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "sled_state_store"))]
|
||||||
use self::memory_store::MemoryStore;
|
use self::memory_store::MemoryStore;
|
||||||
#[cfg(feature = "sled_state_store")]
|
#[cfg(feature = "sled_state_store")]
|
||||||
use self::sled_store::SledStore;
|
use self::sled_store::SledStore;
|
||||||
|
|
||||||
|
/// State store specific error type.
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum StoreError {
|
pub enum StoreError {
|
||||||
|
/// An error happened in the underlying sled database.
|
||||||
#[cfg(feature = "sled_state_store")]
|
#[cfg(feature = "sled_state_store")]
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Sled(#[from] sled::Error),
|
Sled(#[from] sled::Error),
|
||||||
|
/// An error happened while serializing or deserializing some data.
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Json(#[from] serde_json::Error),
|
Json(#[from] serde_json::Error),
|
||||||
|
/// An error happened while deserializing a Matrix identifier, e.g. an user
|
||||||
|
/// id.
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Identifier(#[from] matrix_sdk_common::identifiers::Error),
|
Identifier(#[from] matrix_sdk_common::identifiers::Error),
|
||||||
|
/// The store is locked with a passphrase and an incorrect passphrase was
|
||||||
|
/// given.
|
||||||
#[error("The store failed to be unlocked")]
|
#[error("The store failed to be unlocked")]
|
||||||
StoreLocked,
|
StoreLocked,
|
||||||
|
/// An unencrypted store was tried to be unlocked with a passphrase.
|
||||||
#[error("The store is not encrypted but was tried to be opened with a passphrase")]
|
#[error("The store is not encrypted but was tried to be opened with a passphrase")]
|
||||||
UnencryptedStore,
|
UnencryptedStore,
|
||||||
|
/// The store failed to encrypt or decrypt some data.
|
||||||
#[error("Error encrypting or decrypting data from the store: {0}")]
|
#[error("Error encrypting or decrypting data from the store: {0}")]
|
||||||
Encryption(String),
|
Encryption(String),
|
||||||
}
|
}
|
||||||
|
@ -157,7 +167,8 @@ impl Store {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_memory_store() -> Self {
|
#[cfg(not(feature = "sled_state_store"))]
|
||||||
|
pub(crate) fn open_memory_store() -> Self {
|
||||||
let inner = Box::new(MemoryStore::new());
|
let inner = Box::new(MemoryStore::new());
|
||||||
|
|
||||||
Self::new(inner)
|
Self::new(inner)
|
||||||
|
@ -175,7 +186,7 @@ impl Store {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "sled_state_store")]
|
#[cfg(feature = "sled_state_store")]
|
||||||
pub fn open_temporary() -> Result<(Self, Db)> {
|
pub(crate) fn open_temporary() -> Result<(Self, Db)> {
|
||||||
let inner = SledStore::open()?;
|
let inner = SledStore::open()?;
|
||||||
|
|
||||||
Ok((Self::new(Box::new(inner.clone())), inner.inner))
|
Ok((Self::new(Box::new(inner.clone())), inner.inner))
|
||||||
|
|
|
@ -13,15 +13,24 @@ use super::{
|
||||||
identifiers::{DeviceKeyAlgorithm, EventId, RoomId, UserId},
|
identifiers::{DeviceKeyAlgorithm, EventId, RoomId, UserId},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// A change in ambiguity of room members that an `m.room.member` event
|
||||||
|
/// triggers.
|
||||||
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||||
pub struct AmbiguityChange {
|
pub struct AmbiguityChange {
|
||||||
|
/// Is the member that is contained in the state key of the `m.room.member`
|
||||||
|
/// event itself ambiguous because of the event.
|
||||||
pub member_ambiguous: bool,
|
pub member_ambiguous: bool,
|
||||||
|
/// Has another user been disambiguated because of this event.
|
||||||
pub disambiguated_member: Option<UserId>,
|
pub disambiguated_member: Option<UserId>,
|
||||||
|
/// Has another user become ambiguous because of this event.
|
||||||
pub ambiguated_member: Option<UserId>,
|
pub ambiguated_member: Option<UserId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Collection of ambiguioty changes that room member events trigger.
|
||||||
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||||
pub struct AmbiguityChanges {
|
pub struct AmbiguityChanges {
|
||||||
|
/// A map from room id to a map of an event id to the `AmbiguityChange` that
|
||||||
|
/// the event with the given id caused.
|
||||||
pub changes: BTreeMap<RoomId, BTreeMap<EventId, AmbiguityChange>>,
|
pub changes: BTreeMap<RoomId, BTreeMap<EventId, AmbiguityChange>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -320,8 +329,12 @@ impl Into<StrippedStateEvent<MemberEventContent>> for StrippedMemberEvent {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A deserialized response for the rooms members API call.
|
||||||
|
///
|
||||||
|
/// [GET /_matrix/client/r0/rooms/{roomId}/members](https://matrix.org/docs/spec/client_server/r0.6.0#get-matrix-client-r0-rooms-roomid-members)
|
||||||
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
|
||||||
pub struct MembersResponse {
|
pub struct MembersResponse {
|
||||||
|
/// The list of members events.
|
||||||
pub chunk: Vec<MemberEvent>,
|
pub chunk: Vec<MemberEvent>,
|
||||||
/// Collection of ambiguioty changes that room member events trigger.
|
/// Collection of ambiguioty changes that room member events trigger.
|
||||||
pub ambiguity_changes: AmbiguityChanges,
|
pub ambiguity_changes: AmbiguityChanges,
|
||||||
|
|
Loading…
Reference in New Issue