event_emitter/async_client: receive and emit events for invited and left rooms
parent
7b6e030823
commit
0e538a7c67
|
@ -645,6 +645,22 @@ impl AsyncClient {
|
||||||
|
|
||||||
let mut response = self.send(request).await?;
|
let mut response = self.send(request).await?;
|
||||||
|
|
||||||
|
// when events change state updated signals to state store to update database
|
||||||
|
let mut updated = self.iter_joined_rooms(&mut response).await?;
|
||||||
|
if self.iter_invited_rooms(&mut response).await? {
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
|
if self.iter_left_rooms(&mut response).await? {
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut client = self.base_client.write().await;
|
||||||
|
client.receive_sync_response(&mut response, updated).await?;
|
||||||
|
|
||||||
|
Ok(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn iter_joined_rooms(&self, response: &mut sync_events::Response) -> Result<bool> {
|
||||||
let mut updated = false;
|
let mut updated = false;
|
||||||
for (room_id, room) in &mut response.rooms.join {
|
for (room_id, room) in &mut response.rooms.join {
|
||||||
let matrix_room = {
|
let matrix_room = {
|
||||||
|
@ -745,11 +761,92 @@ impl AsyncClient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Ok(updated)
|
||||||
|
}
|
||||||
|
|
||||||
let mut client = self.base_client.write().await;
|
async fn iter_left_rooms(&self, response: &mut sync_events::Response) -> Result<bool> {
|
||||||
client.receive_sync_response(&mut response, updated).await?;
|
let mut updated = false;
|
||||||
|
for (room_id, left_room) in &mut response.rooms.leave {
|
||||||
|
let matrix_room = {
|
||||||
|
let mut client = self.base_client.write().await;
|
||||||
|
for mut event in &mut left_room.timeline.events {
|
||||||
|
let decrypted_event = {
|
||||||
|
let mut client = self.base_client.write().await;
|
||||||
|
let (decrypt_ev, timeline_update) = client
|
||||||
|
.receive_joined_timeline_event(room_id, &mut event)
|
||||||
|
.await;
|
||||||
|
if timeline_update {
|
||||||
|
updated = true;
|
||||||
|
};
|
||||||
|
decrypt_ev
|
||||||
|
};
|
||||||
|
|
||||||
Ok(response)
|
if let Some(e) = decrypted_event {
|
||||||
|
*event = e;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok(e) = event.deserialize() {
|
||||||
|
let client = self.base_client.read().await;
|
||||||
|
client.emit_timeline_event(&room_id, &e).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
client.get_or_create_room(&room_id).clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
// re looping is not ideal here
|
||||||
|
for event in &mut left_room.state.events {
|
||||||
|
if let Ok(e) = event.deserialize() {
|
||||||
|
let client = self.base_client.read().await;
|
||||||
|
client.emit_state_event(&room_id, &e).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if updated {
|
||||||
|
if let Some(store) = self.base_client.read().await.state_store.as_ref() {
|
||||||
|
store
|
||||||
|
.store_room_state(matrix_room.read().await.deref())
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(updated)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn iter_invited_rooms(&self, response: &mut sync_events::Response) -> Result<bool> {
|
||||||
|
let mut updated = false;
|
||||||
|
// INVITED ROOMS
|
||||||
|
for (room_id, invited_room) in &mut response.rooms.invite {
|
||||||
|
let matrix_room = {
|
||||||
|
let mut client = self.base_client.write().await;
|
||||||
|
for event in &invited_room.invite_state.events {
|
||||||
|
if let Ok(e) = event.deserialize() {
|
||||||
|
if client.receive_invite_state_event(&room_id, &e).await {
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
client.get_or_create_room(&room_id).clone()
|
||||||
|
};
|
||||||
|
|
||||||
|
// re looping is not ideal here
|
||||||
|
for event in &mut invited_room.invite_state.events {
|
||||||
|
if let Ok(e) = event.deserialize() {
|
||||||
|
let client = self.base_client.read().await;
|
||||||
|
client.emit_stripped_state_event(&room_id, &e).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if updated {
|
||||||
|
if let Some(store) = self.base_client.read().await.state_store.as_ref() {
|
||||||
|
store
|
||||||
|
.store_room_state(matrix_room.read().await.deref())
|
||||||
|
.await?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(updated)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Repeatedly call sync to synchronize the client state with the server.
|
/// Repeatedly call sync to synchronize the client state with the server.
|
||||||
|
|
|
@ -30,6 +30,7 @@ use crate::events::presence::PresenceEvent;
|
||||||
use crate::events::collections::only::Event as NonRoomEvent;
|
use crate::events::collections::only::Event as NonRoomEvent;
|
||||||
use crate::events::ignored_user_list::IgnoredUserListEvent;
|
use crate::events::ignored_user_list::IgnoredUserListEvent;
|
||||||
use crate::events::push_rules::{PushRulesEvent, Ruleset};
|
use crate::events::push_rules::{PushRulesEvent, Ruleset};
|
||||||
|
use crate::events::stripped::AnyStrippedStateEvent;
|
||||||
use crate::events::EventJson;
|
use crate::events::EventJson;
|
||||||
use crate::identifiers::{RoomId, UserId};
|
use crate::identifiers::{RoomId, UserId};
|
||||||
use crate::models::Room;
|
use crate::models::Room;
|
||||||
|
@ -333,6 +334,25 @@ impl Client {
|
||||||
room.receive_state_event(event)
|
room.receive_state_event(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Receive a state event for a room the user has been invited to.
|
||||||
|
///
|
||||||
|
/// Returns true if the state of the room changed, false
|
||||||
|
/// otherwise.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `room_id` - The unique id of the room the event belongs to.
|
||||||
|
///
|
||||||
|
/// * `event` - A `AnyStrippedStateEvent` that should be handled by the client.
|
||||||
|
pub async fn receive_invite_state_event(
|
||||||
|
&mut self,
|
||||||
|
room_id: &RoomId,
|
||||||
|
event: &AnyStrippedStateEvent,
|
||||||
|
) -> bool {
|
||||||
|
let mut room = self.get_or_create_room(room_id).write().await;
|
||||||
|
room.receive_stripped_state_event(event)
|
||||||
|
}
|
||||||
|
|
||||||
/// Receive a presence event from a sync response and updates the client state.
|
/// Receive a presence event from a sync response and updates the client state.
|
||||||
///
|
///
|
||||||
/// Returns true if the membership list of the room changed, false
|
/// Returns true if the membership list of the room changed, false
|
||||||
|
@ -707,6 +727,71 @@ impl Client {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) async fn emit_stripped_state_event(
|
||||||
|
&self,
|
||||||
|
room_id: &RoomId,
|
||||||
|
event: &AnyStrippedStateEvent,
|
||||||
|
) {
|
||||||
|
match event {
|
||||||
|
AnyStrippedStateEvent::RoomMember(member) => {
|
||||||
|
if let Some(ee) = &self.event_emitter {
|
||||||
|
if let Some(room) = self.get_room(&room_id) {
|
||||||
|
ee.on_stripped_state_member(Arc::clone(&room), &member)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AnyStrippedStateEvent::RoomName(name) => {
|
||||||
|
if let Some(ee) = &self.event_emitter {
|
||||||
|
if let Some(room) = self.get_room(&room_id) {
|
||||||
|
ee.on_stripped_state_name(Arc::clone(&room), &name).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AnyStrippedStateEvent::RoomCanonicalAlias(canonical) => {
|
||||||
|
if let Some(ee) = &self.event_emitter {
|
||||||
|
if let Some(room) = self.get_room(&room_id) {
|
||||||
|
ee.on_stripped_state_canonical_alias(Arc::clone(&room), &canonical)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AnyStrippedStateEvent::RoomAliases(aliases) => {
|
||||||
|
if let Some(ee) = &self.event_emitter {
|
||||||
|
if let Some(room) = self.get_room(&room_id) {
|
||||||
|
ee.on_stripped_state_aliases(Arc::clone(&room), &aliases)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AnyStrippedStateEvent::RoomAvatar(avatar) => {
|
||||||
|
if let Some(ee) = &self.event_emitter {
|
||||||
|
if let Some(room) = self.get_room(&room_id) {
|
||||||
|
ee.on_stripped_state_avatar(Arc::clone(&room), &avatar)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AnyStrippedStateEvent::RoomPowerLevels(power) => {
|
||||||
|
if let Some(ee) = &self.event_emitter {
|
||||||
|
if let Some(room) = self.get_room(&room_id) {
|
||||||
|
ee.on_stripped_state_power_levels(Arc::clone(&room), &power)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AnyStrippedStateEvent::RoomJoinRules(rules) => {
|
||||||
|
if let Some(ee) = &self.event_emitter {
|
||||||
|
if let Some(room) = self.get_room(&room_id) {
|
||||||
|
ee.on_stripped_state_join_rules(Arc::clone(&room), &rules)
|
||||||
|
.await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) async fn emit_state_event(&self, room_id: &RoomId, event: &StateEvent) {
|
pub(crate) async fn emit_state_event(&self, room_id: &RoomId, event: &StateEvent) {
|
||||||
match event {
|
match event {
|
||||||
StateEvent::RoomMember(member) => {
|
StateEvent::RoomMember(member) => {
|
||||||
|
|
|
@ -19,6 +19,7 @@ use crate::events::{
|
||||||
ignored_user_list::IgnoredUserListEvent,
|
ignored_user_list::IgnoredUserListEvent,
|
||||||
presence::PresenceEvent,
|
presence::PresenceEvent,
|
||||||
push_rules::PushRulesEvent,
|
push_rules::PushRulesEvent,
|
||||||
|
receipt::ReceiptEvent,
|
||||||
room::{
|
room::{
|
||||||
aliases::AliasesEvent,
|
aliases::AliasesEvent,
|
||||||
avatar::AvatarEvent,
|
avatar::AvatarEvent,
|
||||||
|
@ -31,6 +32,11 @@ use crate::events::{
|
||||||
redaction::RedactionEvent,
|
redaction::RedactionEvent,
|
||||||
tombstone::TombstoneEvent,
|
tombstone::TombstoneEvent,
|
||||||
},
|
},
|
||||||
|
stripped::{
|
||||||
|
StrippedRoomAliases, StrippedRoomAvatar, StrippedRoomCanonicalAlias, StrippedRoomJoinRules,
|
||||||
|
StrippedRoomMember, StrippedRoomName, StrippedRoomPowerLevels,
|
||||||
|
},
|
||||||
|
typing::TypingEvent,
|
||||||
};
|
};
|
||||||
use crate::models::Room;
|
use crate::models::Room;
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
|
@ -101,6 +107,10 @@ pub trait EventEmitter: Send + Sync {
|
||||||
async fn on_room_power_levels(&self, _: Arc<RwLock<Room>>, _: &PowerLevelsEvent) {}
|
async fn on_room_power_levels(&self, _: Arc<RwLock<Room>>, _: &PowerLevelsEvent) {}
|
||||||
/// Fires when `AsyncClient` receives a `RoomEvent::Tombstone` event.
|
/// Fires when `AsyncClient` receives a `RoomEvent::Tombstone` event.
|
||||||
async fn on_room_tombstone(&self, _: Arc<RwLock<Room>>, _: &TombstoneEvent) {}
|
async fn on_room_tombstone(&self, _: Arc<RwLock<Room>>, _: &TombstoneEvent) {}
|
||||||
|
/// Fires when `AsyncClient` receives a `NonRoomEvent::Typing` event.
|
||||||
|
async fn on_account_data_typing(&self, _: Arc<RwLock<Room>>, _: &TypingEvent) {}
|
||||||
|
/// Fires when `AsyncClient` receives a `NonRoomEvent::Typing` event.
|
||||||
|
async fn on_account_data_receipt(&self, _: Arc<RwLock<Room>>, _: &ReceiptEvent) {}
|
||||||
|
|
||||||
// `RoomEvent`s from `IncomingState`
|
// `RoomEvent`s from `IncomingState`
|
||||||
/// Fires when `AsyncClient` receives a `StateEvent::RoomMember` event.
|
/// Fires when `AsyncClient` receives a `StateEvent::RoomMember` event.
|
||||||
|
@ -118,6 +128,32 @@ pub trait EventEmitter: Send + Sync {
|
||||||
/// Fires when `AsyncClient` receives a `StateEvent::RoomJoinRules` event.
|
/// Fires when `AsyncClient` receives a `StateEvent::RoomJoinRules` event.
|
||||||
async fn on_state_join_rules(&self, _: Arc<RwLock<Room>>, _: &JoinRulesEvent) {}
|
async fn on_state_join_rules(&self, _: Arc<RwLock<Room>>, _: &JoinRulesEvent) {}
|
||||||
|
|
||||||
|
// `AnyStrippedStateEvent`s
|
||||||
|
/// Fires when `AsyncClient` receives a `StateEvent::RoomMember` event.
|
||||||
|
async fn on_stripped_state_member(&self, _: Arc<RwLock<Room>>, _: &StrippedRoomMember) {}
|
||||||
|
/// Fires when `AsyncClient` receives a `StateEvent::RoomName` event.
|
||||||
|
async fn on_stripped_state_name(&self, _: Arc<RwLock<Room>>, _: &StrippedRoomName) {}
|
||||||
|
/// Fires when `AsyncClient` receives a `StateEvent::RoomCanonicalAlias` event.
|
||||||
|
async fn on_stripped_state_canonical_alias(
|
||||||
|
&self,
|
||||||
|
_: Arc<RwLock<Room>>,
|
||||||
|
_: &StrippedRoomCanonicalAlias,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
/// Fires when `AsyncClient` receives a `StateEvent::RoomAliases` event.
|
||||||
|
async fn on_stripped_state_aliases(&self, _: Arc<RwLock<Room>>, _: &StrippedRoomAliases) {}
|
||||||
|
/// Fires when `AsyncClient` receives a `StateEvent::RoomAvatar` event.
|
||||||
|
async fn on_stripped_state_avatar(&self, _: Arc<RwLock<Room>>, _: &StrippedRoomAvatar) {}
|
||||||
|
/// Fires when `AsyncClient` receives a `StateEvent::RoomPowerLevels` event.
|
||||||
|
async fn on_stripped_state_power_levels(
|
||||||
|
&self,
|
||||||
|
_: Arc<RwLock<Room>>,
|
||||||
|
_: &StrippedRoomPowerLevels,
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
/// Fires when `AsyncClient` receives a `StateEvent::RoomJoinRules` event.
|
||||||
|
async fn on_stripped_state_join_rules(&self, _: Arc<RwLock<Room>>, _: &StrippedRoomJoinRules) {}
|
||||||
|
|
||||||
// `NonRoomEvent` (this is a type alias from ruma_events) from `IncomingAccountData`
|
// `NonRoomEvent` (this is a type alias from ruma_events) from `IncomingAccountData`
|
||||||
/// Fires when `AsyncClient` receives a `NonRoomEvent::RoomMember` event.
|
/// Fires when `AsyncClient` receives a `NonRoomEvent::RoomMember` event.
|
||||||
async fn on_account_presence(&self, _: Arc<RwLock<Room>>, _: &PresenceEvent) {}
|
async fn on_account_presence(&self, _: Arc<RwLock<Room>>, _: &PresenceEvent) {}
|
||||||
|
|
|
@ -30,6 +30,7 @@ use crate::events::room::{
|
||||||
power_levels::{NotificationPowerLevels, PowerLevelsEvent, PowerLevelsEventContent},
|
power_levels::{NotificationPowerLevels, PowerLevelsEvent, PowerLevelsEventContent},
|
||||||
tombstone::TombstoneEvent,
|
tombstone::TombstoneEvent,
|
||||||
};
|
};
|
||||||
|
use crate::events::stripped::AnyStrippedStateEvent;
|
||||||
use crate::events::EventType;
|
use crate::events::EventType;
|
||||||
use crate::identifiers::{RoomAliasId, RoomId, UserId};
|
use crate::identifiers::{RoomAliasId, RoomId, UserId};
|
||||||
|
|
||||||
|
@ -183,7 +184,7 @@ impl RoomName {
|
||||||
})
|
})
|
||||||
.collect::<Vec<String>>();
|
.collect::<Vec<String>>();
|
||||||
names.sort();
|
names.sort();
|
||||||
// TODO what is the length the spec wants us to use here and in the `else`
|
// TODO what length does the spec want us to use here and in the `else`
|
||||||
format!("{}, and {} others", names.join(", "), (joined + invited))
|
format!("{}, and {} others", names.join(", "), (joined + invited))
|
||||||
} else {
|
} else {
|
||||||
format!("Empty Room (was {} others)", members.len())
|
format!("Empty Room (was {} others)", members.len())
|
||||||
|
@ -396,15 +397,15 @@ impl Room {
|
||||||
pub fn receive_timeline_event(&mut self, event: &RoomEvent) -> bool {
|
pub fn receive_timeline_event(&mut self, event: &RoomEvent) -> bool {
|
||||||
match event {
|
match event {
|
||||||
// update to the current members of the room
|
// update to the current members of the room
|
||||||
RoomEvent::RoomMember(m) => self.handle_membership(m),
|
RoomEvent::RoomMember(member) => self.handle_membership(member),
|
||||||
// finds all events related to the name of the room for later use
|
// finds all events related to the name of the room for later use
|
||||||
RoomEvent::RoomName(n) => self.handle_room_name(n),
|
RoomEvent::RoomName(name) => self.handle_room_name(name),
|
||||||
RoomEvent::RoomCanonicalAlias(ca) => self.handle_canonical(ca),
|
RoomEvent::RoomCanonicalAlias(c_alias) => self.handle_canonical(c_alias),
|
||||||
RoomEvent::RoomAliases(a) => self.handle_room_aliases(a),
|
RoomEvent::RoomAliases(alias) => self.handle_room_aliases(alias),
|
||||||
// power levels of the room members
|
// power levels of the room members
|
||||||
RoomEvent::RoomPowerLevels(p) => self.handle_power_level(p),
|
RoomEvent::RoomPowerLevels(power) => self.handle_power_level(power),
|
||||||
RoomEvent::RoomTombstone(t) => self.handle_tombstone(t),
|
RoomEvent::RoomTombstone(tomb) => self.handle_tombstone(tomb),
|
||||||
RoomEvent::RoomEncryption(e) => self.handle_encryption_event(e),
|
RoomEvent::RoomEncryption(encrypt) => self.handle_encryption_event(encrypt),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -418,17 +419,33 @@ impl Room {
|
||||||
/// * `event` - The event of the room.
|
/// * `event` - The event of the room.
|
||||||
pub fn receive_state_event(&mut self, event: &StateEvent) -> bool {
|
pub fn receive_state_event(&mut self, event: &StateEvent) -> bool {
|
||||||
match event {
|
match event {
|
||||||
StateEvent::RoomMember(m) => self.handle_membership(m),
|
// update to the current members of the room
|
||||||
StateEvent::RoomName(n) => self.handle_room_name(n),
|
StateEvent::RoomMember(member) => self.handle_membership(member),
|
||||||
StateEvent::RoomCanonicalAlias(ca) => self.handle_canonical(ca),
|
// finds all events related to the name of the room for later use
|
||||||
StateEvent::RoomAliases(a) => self.handle_room_aliases(a),
|
StateEvent::RoomName(name) => self.handle_room_name(name),
|
||||||
StateEvent::RoomPowerLevels(p) => self.handle_power_level(p),
|
StateEvent::RoomCanonicalAlias(c_alias) => self.handle_canonical(c_alias),
|
||||||
StateEvent::RoomTombstone(t) => self.handle_tombstone(t),
|
StateEvent::RoomAliases(alias) => self.handle_room_aliases(alias),
|
||||||
StateEvent::RoomEncryption(e) => self.handle_encryption_event(e),
|
// power levels of the room members
|
||||||
|
StateEvent::RoomPowerLevels(power) => self.handle_power_level(power),
|
||||||
|
StateEvent::RoomTombstone(tomb) => self.handle_tombstone(tomb),
|
||||||
|
StateEvent::RoomEncryption(encrypt) => self.handle_encryption_event(encrypt),
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Receive a stripped state event for this room and update the room state.
|
||||||
|
///
|
||||||
|
/// Returns true if the state of the `Room` has changed, false otherwise.
|
||||||
|
///
|
||||||
|
/// # Arguments
|
||||||
|
///
|
||||||
|
/// * `event` - The `AnyStrippedStateEvent` sent by the server for invited but not
|
||||||
|
/// joined rooms.
|
||||||
|
pub fn receive_stripped_state_event(&mut self, _event: &AnyStrippedStateEvent) -> bool {
|
||||||
|
// TODO do we want to do anything with the events from an invited room?
|
||||||
|
true
|
||||||
|
}
|
||||||
|
|
||||||
/// Receive a presence event from an `IncomingResponse` and updates the client state.
|
/// Receive a presence event from an `IncomingResponse` and updates the client state.
|
||||||
///
|
///
|
||||||
/// This will only update the user if found in the current room looped through by `AsyncClient::sync`.
|
/// This will only update the user if found in the current room looped through by `AsyncClient::sync`.
|
||||||
|
|
Loading…
Reference in New Issue