base_client: Make the base client a bit more threadsafe.
This moves the bulk of the sync logic into the base client, to avoid deadlocks while someone tires to send messages from a event callback the base client needed to get a bunch of locks. Ideally the AsyncClient would not need a lock for the base client at all but we're not there yet.master
parent
39e59792d2
commit
967544bab9
|
@ -17,7 +17,6 @@
|
|||
use std::collections::BTreeMap;
|
||||
use std::collections::HashMap;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::ops::Deref;
|
||||
use std::result::Result as StdResult;
|
||||
use std::sync::Arc;
|
||||
use std::time::{Duration, Instant};
|
||||
|
@ -339,7 +338,7 @@ impl AsyncClient {
|
|||
/// Returns the rooms this client knows about.
|
||||
///
|
||||
/// A `HashMap` of room id to `matrix::models::Room`
|
||||
pub async fn get_rooms(&self) -> HashMap<RoomId, Arc<tokio::sync::RwLock<Room>>> {
|
||||
pub async fn get_rooms(&self) -> Arc<RwLock<HashMap<RoomId, Arc<tokio::sync::RwLock<Room>>>>> {
|
||||
self.base_client.read().await.joined_rooms.clone()
|
||||
}
|
||||
|
||||
|
@ -645,109 +644,8 @@ impl AsyncClient {
|
|||
|
||||
let mut response = self.send(request).await?;
|
||||
|
||||
let mut updated = false;
|
||||
for (room_id, room) in &mut response.rooms.join {
|
||||
let matrix_room = {
|
||||
let mut client = self.base_client.write().await;
|
||||
for event in &room.state.events {
|
||||
if let Ok(e) = event.deserialize() {
|
||||
if client.receive_joined_state_event(&room_id, &e).await {
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
client.get_or_create_room(&room_id).clone()
|
||||
};
|
||||
|
||||
// RoomSummary contains information for calculating room name
|
||||
matrix_room.write().await.set_room_summary(&room.summary);
|
||||
|
||||
// re looping is not ideal here
|
||||
for event in &mut room.state.events {
|
||||
if let Ok(e) = event.deserialize() {
|
||||
let client = self.base_client.read().await;
|
||||
client.emit_state_event(&room_id, &e).await;
|
||||
}
|
||||
}
|
||||
|
||||
for mut event in &mut 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
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
// look at AccountData to further cut down users by collecting ignored users
|
||||
if let Some(account_data) = &room.account_data {
|
||||
for account_data in &account_data.events {
|
||||
{
|
||||
if let Ok(e) = account_data.deserialize() {
|
||||
let mut client = self.base_client.write().await;
|
||||
if client.receive_account_data_event(&room_id, &e).await {
|
||||
updated = true;
|
||||
}
|
||||
client.emit_account_data_event(room_id, &e).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// After the room has been created and state/timeline events accounted for we use the room_id of the newly created
|
||||
// room to add any presence events that relate to a user in the current room. This is not super
|
||||
// efficient but we need a room_id so we would loop through now or later.
|
||||
for presence in &mut response.presence.events {
|
||||
{
|
||||
if let Ok(e) = presence.deserialize() {
|
||||
let mut client = self.base_client.write().await;
|
||||
if client.receive_presence_event(&room_id, &e).await {
|
||||
updated = true;
|
||||
}
|
||||
|
||||
client.emit_presence_event(&room_id, &e).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for ephemeral in &mut room.ephemeral.events {
|
||||
{
|
||||
if let Ok(e) = ephemeral.deserialize() {
|
||||
let mut client = self.base_client.write().await;
|
||||
if client.receive_ephemeral_event(&room_id, &e).await {
|
||||
updated = true;
|
||||
}
|
||||
|
||||
client.emit_ephemeral_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?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut client = self.base_client.write().await;
|
||||
client.receive_sync_response(&mut response, updated).await?;
|
||||
client.receive_sync_response(&mut response).await?;
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
|
@ -994,7 +892,7 @@ impl AsyncClient {
|
|||
{
|
||||
let encrypted = {
|
||||
let client = self.base_client.read().await;
|
||||
let room = client.joined_rooms.get(room_id);
|
||||
let room = client.get_room(room_id).await;
|
||||
|
||||
match room {
|
||||
Some(r) => r.read().await.is_encrypted(),
|
||||
|
@ -1005,7 +903,7 @@ impl AsyncClient {
|
|||
if encrypted {
|
||||
let missing_sessions = {
|
||||
let client = self.base_client.read().await;
|
||||
let room = client.joined_rooms.get(room_id);
|
||||
let room = client.get_room(room_id).await;
|
||||
let room = room.as_ref().unwrap().read().await;
|
||||
let users = room.members.keys();
|
||||
self.base_client
|
||||
|
@ -1158,7 +1056,7 @@ impl AsyncClient {
|
|||
/// Get the current, if any, sync token of the client.
|
||||
/// This will be None if the client didn't sync at least once.
|
||||
pub async fn sync_token(&self) -> Option<String> {
|
||||
self.base_client.read().await.sync_token.clone()
|
||||
self.base_client.read().await.sync_token().await
|
||||
}
|
||||
|
||||
/// Query the server for users device keys.
|
||||
|
|
|
@ -17,6 +17,7 @@ use std::collections::HashMap;
|
|||
#[cfg(feature = "encryption")]
|
||||
use std::collections::{BTreeMap, HashSet};
|
||||
use std::fmt;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[cfg(feature = "encryption")]
|
||||
|
@ -37,6 +38,7 @@ use crate::session::Session;
|
|||
use crate::state::{ClientState, StateStore};
|
||||
use crate::EventEmitter;
|
||||
|
||||
use std::ops::Deref;
|
||||
#[cfg(feature = "encryption")]
|
||||
use tokio::sync::Mutex;
|
||||
use tokio::sync::RwLock;
|
||||
|
@ -66,13 +68,13 @@ pub struct Client {
|
|||
/// token.
|
||||
pub session: Option<Session>,
|
||||
/// The current sync token that should be used for the next sync call.
|
||||
pub sync_token: Option<Token>,
|
||||
pub sync_token: Arc<RwLock<Option<Token>>>,
|
||||
/// A map of the rooms our user is joined in.
|
||||
pub joined_rooms: HashMap<RoomId, Arc<RwLock<Room>>>,
|
||||
pub joined_rooms: Arc<RwLock<HashMap<RoomId, Arc<RwLock<Room>>>>>,
|
||||
/// A list of ignored users.
|
||||
pub ignored_users: Vec<UserId>,
|
||||
pub ignored_users: Arc<RwLock<Vec<UserId>>>,
|
||||
/// The push ruleset for the logged in user.
|
||||
pub push_ruleset: Option<Ruleset>,
|
||||
pub push_ruleset: Arc<RwLock<Option<Ruleset>>>,
|
||||
/// Any implementor of EventEmitter will act as the callbacks for various
|
||||
/// events.
|
||||
pub event_emitter: Option<Box<dyn EventEmitter>>,
|
||||
|
@ -82,7 +84,7 @@ pub struct Client {
|
|||
/// There is a default implementation `JsonStore` that saves JSON to disk.
|
||||
pub state_store: Option<Box<dyn StateStore>>,
|
||||
/// Does the `Client` need to sync with the state store.
|
||||
needs_state_store_sync: bool,
|
||||
needs_state_store_sync: Arc<AtomicBool>,
|
||||
|
||||
#[cfg(feature = "encryption")]
|
||||
olm: Arc<Mutex<Option<OlmMachine>>>,
|
||||
|
@ -117,13 +119,13 @@ impl Client {
|
|||
|
||||
Ok(Client {
|
||||
session,
|
||||
sync_token: None,
|
||||
joined_rooms: HashMap::new(),
|
||||
ignored_users: Vec::new(),
|
||||
push_ruleset: None,
|
||||
sync_token: Arc::new(RwLock::new(None)),
|
||||
joined_rooms: Arc::new(RwLock::new(HashMap::new())),
|
||||
ignored_users: Arc::new(RwLock::new(Vec::new())),
|
||||
push_ruleset: Arc::new(RwLock::new(None)),
|
||||
event_emitter: None,
|
||||
state_store: None,
|
||||
needs_state_store_sync: true,
|
||||
needs_state_store_sync: Arc::new(AtomicBool::from(true)),
|
||||
#[cfg(feature = "encryption")]
|
||||
olm: Arc::new(Mutex::new(olm)),
|
||||
})
|
||||
|
@ -143,7 +145,7 @@ impl Client {
|
|||
|
||||
/// Returns true if the state store has been loaded into the client.
|
||||
pub fn is_state_store_synced(&self) -> bool {
|
||||
!self.needs_state_store_sync
|
||||
!self.needs_state_store_sync.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
/// When a client is provided the state store will load state from the `StateStore`.
|
||||
|
@ -158,9 +160,9 @@ impl Client {
|
|||
ignored_users,
|
||||
push_ruleset,
|
||||
} = client_state;
|
||||
self.sync_token = sync_token;
|
||||
self.ignored_users = ignored_users;
|
||||
self.push_ruleset = push_ruleset;
|
||||
*self.sync_token.write().await = sync_token;
|
||||
*self.ignored_users.write().await = ignored_users;
|
||||
*self.push_ruleset.write().await = push_ruleset;
|
||||
} else {
|
||||
// return false and continues with a sync request then save the state and create
|
||||
// and populate the files during the sync
|
||||
|
@ -168,15 +170,17 @@ impl Client {
|
|||
}
|
||||
|
||||
let mut rooms = store.load_all_rooms().await?;
|
||||
self.joined_rooms = rooms
|
||||
self.joined_rooms = Arc::new(RwLock::new(
|
||||
rooms
|
||||
.drain()
|
||||
.map(|(k, room)| (k, Arc::new(RwLock::new(room))))
|
||||
.collect();
|
||||
.collect(),
|
||||
));
|
||||
|
||||
self.needs_state_store_sync = false;
|
||||
self.needs_state_store_sync.store(false, Ordering::Relaxed);
|
||||
}
|
||||
}
|
||||
Ok(!self.needs_state_store_sync)
|
||||
Ok(!self.needs_state_store_sync.load(Ordering::Relaxed))
|
||||
}
|
||||
|
||||
/// Receive a login response and update the session of the client.
|
||||
|
@ -206,7 +210,7 @@ impl Client {
|
|||
}
|
||||
|
||||
pub(crate) async fn calculate_room_name(&self, room_id: &RoomId) -> Option<String> {
|
||||
if let Some(room) = self.joined_rooms.get(room_id) {
|
||||
if let Some(room) = self.joined_rooms.read().await.get(room_id) {
|
||||
let room = room.read().await;
|
||||
Some(room.room_name.calculate_name(&room.members))
|
||||
} else {
|
||||
|
@ -216,16 +220,17 @@ impl Client {
|
|||
|
||||
pub(crate) async fn calculate_room_names(&self) -> Vec<String> {
|
||||
let mut res = Vec::new();
|
||||
for room in self.joined_rooms.values() {
|
||||
for room in self.joined_rooms.read().await.values() {
|
||||
let room = room.read().await;
|
||||
res.push(room.room_name.calculate_name(&room.members))
|
||||
}
|
||||
res
|
||||
}
|
||||
|
||||
pub(crate) fn get_or_create_room(&mut self, room_id: &RoomId) -> &mut Arc<RwLock<Room>> {
|
||||
pub(crate) async fn get_or_create_room(&self, room_id: &RoomId) -> Arc<RwLock<Room>> {
|
||||
#[allow(clippy::or_fun_call)]
|
||||
self.joined_rooms
|
||||
let mut rooms = self.joined_rooms.write().await;
|
||||
rooms
|
||||
.entry(room_id.clone())
|
||||
.or_insert(Arc::new(RwLock::new(Room::new(
|
||||
room_id,
|
||||
|
@ -235,23 +240,24 @@ impl Client {
|
|||
.expect("Receiving events while not being logged in")
|
||||
.user_id,
|
||||
))))
|
||||
.clone()
|
||||
}
|
||||
|
||||
pub(crate) fn get_room(&self, room_id: &RoomId) -> Option<&Arc<RwLock<Room>>> {
|
||||
self.joined_rooms.get(room_id)
|
||||
pub(crate) async fn get_room(&self, room_id: &RoomId) -> Option<Arc<RwLock<Room>>> {
|
||||
self.joined_rooms.read().await.get(room_id).cloned()
|
||||
}
|
||||
|
||||
/// Handle a m.ignored_user_list event, updating the room state if necessary.
|
||||
///
|
||||
/// Returns true if the room name changed, false otherwise.
|
||||
pub(crate) fn handle_ignored_users(&mut self, event: &IgnoredUserListEvent) -> bool {
|
||||
pub(crate) async fn handle_ignored_users(&self, event: &IgnoredUserListEvent) -> bool {
|
||||
// this avoids cloning every UserId for the eq check
|
||||
if self.ignored_users.iter().collect::<Vec<_>>()
|
||||
if self.ignored_users.read().await.iter().collect::<Vec<_>>()
|
||||
== event.content.ignored_users.iter().collect::<Vec<_>>()
|
||||
{
|
||||
false
|
||||
} else {
|
||||
self.ignored_users = event.content.ignored_users.to_vec();
|
||||
*self.ignored_users.write().await = event.content.ignored_users.to_vec();
|
||||
true
|
||||
}
|
||||
}
|
||||
|
@ -259,7 +265,7 @@ impl Client {
|
|||
/// Handle a m.ignored_user_list event, updating the room state if necessary.
|
||||
///
|
||||
/// Returns true if the room name changed, false otherwise.
|
||||
pub(crate) fn handle_push_rules(&mut self, event: &PushRulesEvent) -> bool {
|
||||
pub(crate) async fn handle_push_rules(&self, event: &PushRulesEvent) -> bool {
|
||||
// TODO this is basically a stub
|
||||
// TODO ruma removed PartialEq for evens, so this doesn't work anymore.
|
||||
// Returning always true for now should be ok here since those don't
|
||||
|
@ -267,7 +273,7 @@ impl Client {
|
|||
// if self.push_ruleset.as_ref() == Some(&event.content.global) {
|
||||
// false
|
||||
// } else {
|
||||
self.push_ruleset = Some(event.content.global.clone());
|
||||
*self.push_ruleset.write().await = Some(event.content.global.clone());
|
||||
true
|
||||
// }
|
||||
}
|
||||
|
@ -283,7 +289,7 @@ impl Client {
|
|||
///
|
||||
/// * `event` - The event that should be handled by the client.
|
||||
pub async fn receive_joined_timeline_event(
|
||||
&mut self,
|
||||
&self,
|
||||
room_id: &RoomId,
|
||||
event: &mut EventJson<RoomEvent>,
|
||||
) -> (Option<EventJson<RoomEvent>>, bool) {
|
||||
|
@ -307,7 +313,8 @@ impl Client {
|
|||
}
|
||||
}
|
||||
|
||||
let mut room = self.get_or_create_room(&room_id).write().await;
|
||||
let room_lock = self.get_or_create_room(&room_id).await;
|
||||
let mut room = room_lock.write().await;
|
||||
(decrypted_event, room.receive_timeline_event(&e))
|
||||
}
|
||||
_ => (None, false),
|
||||
|
@ -324,12 +331,9 @@ impl Client {
|
|||
/// * `room_id` - The unique id of the room the event belongs to.
|
||||
///
|
||||
/// * `event` - The event that should be handled by the client.
|
||||
pub async fn receive_joined_state_event(
|
||||
&mut self,
|
||||
room_id: &RoomId,
|
||||
event: &StateEvent,
|
||||
) -> bool {
|
||||
let mut room = self.get_or_create_room(room_id).write().await;
|
||||
pub async fn receive_joined_state_event(&self, room_id: &RoomId, event: &StateEvent) -> bool {
|
||||
let room_lock = self.get_or_create_room(room_id).await;
|
||||
let mut room = room_lock.write().await;
|
||||
room.receive_state_event(event)
|
||||
}
|
||||
|
||||
|
@ -343,13 +347,9 @@ impl Client {
|
|||
/// * `room_id` - The unique id of the room the event belongs to.
|
||||
///
|
||||
/// * `event` - The event that should be handled by the client.
|
||||
pub async fn receive_presence_event(
|
||||
&mut self,
|
||||
room_id: &RoomId,
|
||||
event: &PresenceEvent,
|
||||
) -> bool {
|
||||
pub async fn receive_presence_event(&self, room_id: &RoomId, event: &PresenceEvent) -> bool {
|
||||
// this should be the room that was just created in the `Client::sync` loop.
|
||||
if let Some(room) = self.get_room(room_id) {
|
||||
if let Some(room) = self.get_room(room_id).await {
|
||||
let mut room = room.write().await;
|
||||
room.receive_presence_event(event)
|
||||
} else {
|
||||
|
@ -366,15 +366,11 @@ impl Client {
|
|||
/// * `room_id` - The unique id of the room the event belongs to.
|
||||
///
|
||||
/// * `event` - The presence event for a specified room member.
|
||||
pub async fn receive_account_data_event(
|
||||
&mut self,
|
||||
room_id: &RoomId,
|
||||
event: &NonRoomEvent,
|
||||
) -> bool {
|
||||
pub async fn receive_account_data_event(&self, room_id: &RoomId, event: &NonRoomEvent) -> bool {
|
||||
match event {
|
||||
NonRoomEvent::IgnoredUserList(iu) => self.handle_ignored_users(iu),
|
||||
NonRoomEvent::IgnoredUserList(iu) => self.handle_ignored_users(iu).await,
|
||||
NonRoomEvent::Presence(p) => self.receive_presence_event(room_id, p).await,
|
||||
NonRoomEvent::PushRules(pr) => self.handle_push_rules(pr),
|
||||
NonRoomEvent::PushRules(pr) => self.handle_push_rules(pr).await,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -388,19 +384,21 @@ impl Client {
|
|||
/// * `room_id` - The unique id of the room the event belongs to.
|
||||
///
|
||||
/// * `event` - The presence event for a specified room member.
|
||||
pub async fn receive_ephemeral_event(
|
||||
&mut self,
|
||||
room_id: &RoomId,
|
||||
event: &NonRoomEvent,
|
||||
) -> bool {
|
||||
pub async fn receive_ephemeral_event(&self, room_id: &RoomId, event: &NonRoomEvent) -> bool {
|
||||
match event {
|
||||
NonRoomEvent::IgnoredUserList(iu) => self.handle_ignored_users(iu),
|
||||
NonRoomEvent::IgnoredUserList(iu) => self.handle_ignored_users(iu).await,
|
||||
NonRoomEvent::Presence(p) => self.receive_presence_event(room_id, p).await,
|
||||
NonRoomEvent::PushRules(pr) => self.handle_push_rules(pr),
|
||||
NonRoomEvent::PushRules(pr) => self.handle_push_rules(pr).await,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the current, if any, sync token of the client.
|
||||
/// This will be None if the client didn't sync at least once.
|
||||
pub async fn sync_token(&self) -> Option<String> {
|
||||
self.sync_token.read().await.clone()
|
||||
}
|
||||
|
||||
/// Receive a response from a sync call.
|
||||
///
|
||||
/// # Arguments
|
||||
|
@ -409,11 +407,10 @@ impl Client {
|
|||
///
|
||||
/// * `did_update` - Signals to the `StateStore` if the client state needs updating.
|
||||
pub async fn receive_sync_response(
|
||||
&mut self,
|
||||
&self,
|
||||
response: &mut api::sync::sync_events::Response,
|
||||
did_update: bool,
|
||||
) -> Result<()> {
|
||||
self.sync_token = Some(response.next_batch.clone());
|
||||
*self.sync_token.write().await = Some(response.next_batch.clone());
|
||||
|
||||
#[cfg(feature = "encryption")]
|
||||
{
|
||||
|
@ -425,8 +422,8 @@ impl Client {
|
|||
// TODO once the base client deals with callbacks move this into the
|
||||
// part where we already iterate through the rooms to avoid yet
|
||||
// another room loop.
|
||||
for room in self.joined_rooms.values() {
|
||||
let room = room.write().await;
|
||||
for room in self.joined_rooms.read().await.values() {
|
||||
let room = room.read().await;
|
||||
if !room.is_encrypted() {
|
||||
continue;
|
||||
}
|
||||
|
@ -436,9 +433,103 @@ impl Client {
|
|||
}
|
||||
}
|
||||
|
||||
if did_update {
|
||||
let mut updated = false;
|
||||
for (room_id, room) in &mut response.rooms.join {
|
||||
let matrix_room = {
|
||||
for event in &room.state.events {
|
||||
if let Ok(e) = event.deserialize() {
|
||||
if self.receive_joined_state_event(&room_id, &e).await {
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.get_or_create_room(&room_id).await.clone()
|
||||
};
|
||||
|
||||
// RoomSummary contains information for calculating room name
|
||||
matrix_room.write().await.set_room_summary(&room.summary);
|
||||
|
||||
// re looping is not ideal here
|
||||
for event in &mut room.state.events {
|
||||
if let Ok(e) = event.deserialize() {
|
||||
self.emit_state_event(&room_id, &e).await;
|
||||
}
|
||||
}
|
||||
|
||||
for mut event in &mut room.timeline.events {
|
||||
let decrypted_event = {
|
||||
let (decrypt_ev, timeline_update) = self
|
||||
.receive_joined_timeline_event(room_id, &mut event)
|
||||
.await;
|
||||
if timeline_update {
|
||||
updated = true;
|
||||
};
|
||||
decrypt_ev
|
||||
};
|
||||
|
||||
if let Some(e) = decrypted_event {
|
||||
*event = e;
|
||||
}
|
||||
|
||||
if let Ok(e) = event.deserialize() {
|
||||
self.emit_timeline_event(&room_id, &e).await;
|
||||
}
|
||||
}
|
||||
|
||||
// look at AccountData to further cut down users by collecting ignored users
|
||||
if let Some(account_data) = &room.account_data {
|
||||
for account_data in &account_data.events {
|
||||
{
|
||||
if let Ok(e) = account_data.deserialize() {
|
||||
if self.receive_account_data_event(&room_id, &e).await {
|
||||
updated = true;
|
||||
}
|
||||
self.emit_account_data_event(room_id, &e).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// After the room has been created and state/timeline events accounted for we use the room_id of the newly created
|
||||
// room to add any presence events that relate to a user in the current room. This is not super
|
||||
// efficient but we need a room_id so we would loop through now or later.
|
||||
for presence in &mut response.presence.events {
|
||||
{
|
||||
if let Ok(e) = presence.deserialize() {
|
||||
if self.receive_presence_event(&room_id, &e).await {
|
||||
updated = true;
|
||||
}
|
||||
|
||||
self.emit_presence_event(&room_id, &e).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for ephemeral in &mut room.ephemeral.events {
|
||||
{
|
||||
if let Ok(e) = ephemeral.deserialize() {
|
||||
if self.receive_ephemeral_event(&room_id, &e).await {
|
||||
updated = true;
|
||||
}
|
||||
|
||||
self.emit_ephemeral_event(&room_id, &e).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if updated {
|
||||
if let Some(store) = self.state_store.as_ref() {
|
||||
let state = ClientState::from_base_client(&self);
|
||||
store
|
||||
.store_room_state(matrix_room.read().await.deref())
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if updated {
|
||||
if let Some(store) = self.state_store.as_ref() {
|
||||
let state = ClientState::from_base_client(&self).await;
|
||||
store.store_client_state(state).await?;
|
||||
}
|
||||
}
|
||||
|
@ -512,7 +603,7 @@ impl Client {
|
|||
&self,
|
||||
room_id: &RoomId,
|
||||
) -> Result<Vec<send_event_to_device::Request>> {
|
||||
let room = self.get_room(room_id).expect("No room found");
|
||||
let room = self.get_room(room_id).await.expect("No room found");
|
||||
let mut olm = self.olm.lock().await;
|
||||
|
||||
match &mut *olm {
|
||||
|
@ -633,21 +724,21 @@ impl Client {
|
|||
match event {
|
||||
RoomEvent::RoomMember(mem) => {
|
||||
if let Some(ee) = &self.event_emitter {
|
||||
if let Some(room) = self.get_room(&room_id) {
|
||||
if let Some(room) = self.get_room(&room_id).await {
|
||||
ee.on_room_member(Arc::clone(&room), &mem).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
RoomEvent::RoomName(name) => {
|
||||
if let Some(ee) = &self.event_emitter {
|
||||
if let Some(room) = self.get_room(&room_id) {
|
||||
if let Some(room) = self.get_room(&room_id).await {
|
||||
ee.on_room_name(Arc::clone(&room), &name).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
RoomEvent::RoomCanonicalAlias(canonical) => {
|
||||
if let Some(ee) = &self.event_emitter {
|
||||
if let Some(room) = self.get_room(&room_id) {
|
||||
if let Some(room) = self.get_room(&room_id).await {
|
||||
ee.on_room_canonical_alias(Arc::clone(&room), &canonical)
|
||||
.await;
|
||||
}
|
||||
|
@ -655,28 +746,28 @@ impl Client {
|
|||
}
|
||||
RoomEvent::RoomAliases(aliases) => {
|
||||
if let Some(ee) = &self.event_emitter {
|
||||
if let Some(room) = self.get_room(&room_id) {
|
||||
if let Some(room) = self.get_room(&room_id).await {
|
||||
ee.on_room_aliases(Arc::clone(&room), &aliases).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
RoomEvent::RoomAvatar(avatar) => {
|
||||
if let Some(ee) = &self.event_emitter {
|
||||
if let Some(room) = self.get_room(&room_id) {
|
||||
if let Some(room) = self.get_room(&room_id).await {
|
||||
ee.on_room_avatar(Arc::clone(&room), &avatar).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
RoomEvent::RoomMessage(msg) => {
|
||||
if let Some(ee) = &self.event_emitter {
|
||||
if let Some(room) = self.get_room(&room_id) {
|
||||
if let Some(room) = self.get_room(&room_id).await {
|
||||
ee.on_room_message(Arc::clone(&room), &msg).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
RoomEvent::RoomMessageFeedback(msg_feedback) => {
|
||||
if let Some(ee) = &self.event_emitter {
|
||||
if let Some(room) = self.get_room(&room_id) {
|
||||
if let Some(room) = self.get_room(&room_id).await {
|
||||
ee.on_room_message_feedback(Arc::clone(&room), &msg_feedback)
|
||||
.await;
|
||||
}
|
||||
|
@ -684,21 +775,21 @@ impl Client {
|
|||
}
|
||||
RoomEvent::RoomRedaction(redaction) => {
|
||||
if let Some(ee) = &self.event_emitter {
|
||||
if let Some(room) = self.get_room(&room_id) {
|
||||
if let Some(room) = self.get_room(&room_id).await {
|
||||
ee.on_room_redaction(Arc::clone(&room), &redaction).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
RoomEvent::RoomPowerLevels(power) => {
|
||||
if let Some(ee) = &self.event_emitter {
|
||||
if let Some(room) = self.get_room(&room_id) {
|
||||
if let Some(room) = self.get_room(&room_id).await {
|
||||
ee.on_room_power_levels(Arc::clone(&room), &power).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
RoomEvent::RoomTombstone(tomb) => {
|
||||
if let Some(ee) = &self.event_emitter {
|
||||
if let Some(room) = self.get_room(&room_id) {
|
||||
if let Some(room) = self.get_room(&room_id).await {
|
||||
ee.on_room_tombstone(Arc::clone(&room), &tomb).await;
|
||||
}
|
||||
}
|
||||
|
@ -711,21 +802,21 @@ impl Client {
|
|||
match event {
|
||||
StateEvent::RoomMember(member) => {
|
||||
if let Some(ee) = &self.event_emitter {
|
||||
if let Some(room) = self.get_room(&room_id) {
|
||||
if let Some(room) = self.get_room(&room_id).await {
|
||||
ee.on_state_member(Arc::clone(&room), &member).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
StateEvent::RoomName(name) => {
|
||||
if let Some(ee) = &self.event_emitter {
|
||||
if let Some(room) = self.get_room(&room_id) {
|
||||
if let Some(room) = self.get_room(&room_id).await {
|
||||
ee.on_state_name(Arc::clone(&room), &name).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
StateEvent::RoomCanonicalAlias(canonical) => {
|
||||
if let Some(ee) = &self.event_emitter {
|
||||
if let Some(room) = self.get_room(&room_id) {
|
||||
if let Some(room) = self.get_room(&room_id).await {
|
||||
ee.on_state_canonical_alias(Arc::clone(&room), &canonical)
|
||||
.await;
|
||||
}
|
||||
|
@ -733,35 +824,35 @@ impl Client {
|
|||
}
|
||||
StateEvent::RoomAliases(aliases) => {
|
||||
if let Some(ee) = &self.event_emitter {
|
||||
if let Some(room) = self.get_room(&room_id) {
|
||||
if let Some(room) = self.get_room(&room_id).await {
|
||||
ee.on_state_aliases(Arc::clone(&room), &aliases).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
StateEvent::RoomAvatar(avatar) => {
|
||||
if let Some(ee) = &self.event_emitter {
|
||||
if let Some(room) = self.get_room(&room_id) {
|
||||
if let Some(room) = self.get_room(&room_id).await {
|
||||
ee.on_state_avatar(Arc::clone(&room), &avatar).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
StateEvent::RoomPowerLevels(power) => {
|
||||
if let Some(ee) = &self.event_emitter {
|
||||
if let Some(room) = self.get_room(&room_id) {
|
||||
if let Some(room) = self.get_room(&room_id).await {
|
||||
ee.on_state_power_levels(Arc::clone(&room), &power).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
StateEvent::RoomJoinRules(rules) => {
|
||||
if let Some(ee) = &self.event_emitter {
|
||||
if let Some(room) = self.get_room(&room_id) {
|
||||
if let Some(room) = self.get_room(&room_id).await {
|
||||
ee.on_state_join_rules(Arc::clone(&room), &rules).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
StateEvent::RoomTombstone(tomb) => {
|
||||
if let Some(ee) = &self.event_emitter {
|
||||
if let Some(room) = self.get_room(&room_id) {
|
||||
if let Some(room) = self.get_room(&room_id).await {
|
||||
ee.on_room_tombstone(Arc::clone(&room), &tomb).await;
|
||||
}
|
||||
}
|
||||
|
@ -774,14 +865,14 @@ impl Client {
|
|||
match event {
|
||||
NonRoomEvent::Presence(presence) => {
|
||||
if let Some(ee) = &self.event_emitter {
|
||||
if let Some(room) = self.get_room(&room_id) {
|
||||
if let Some(room) = self.get_room(&room_id).await {
|
||||
ee.on_account_presence(Arc::clone(&room), &presence).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
NonRoomEvent::IgnoredUserList(ignored) => {
|
||||
if let Some(ee) = &self.event_emitter {
|
||||
if let Some(room) = self.get_room(&room_id) {
|
||||
if let Some(room) = self.get_room(&room_id).await {
|
||||
ee.on_account_ignored_users(Arc::clone(&room), &ignored)
|
||||
.await;
|
||||
}
|
||||
|
@ -789,14 +880,14 @@ impl Client {
|
|||
}
|
||||
NonRoomEvent::PushRules(rules) => {
|
||||
if let Some(ee) = &self.event_emitter {
|
||||
if let Some(room) = self.get_room(&room_id) {
|
||||
if let Some(room) = self.get_room(&room_id).await {
|
||||
ee.on_account_push_rules(Arc::clone(&room), &rules).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
NonRoomEvent::FullyRead(full_read) => {
|
||||
if let Some(ee) = &self.event_emitter {
|
||||
if let Some(room) = self.get_room(&room_id) {
|
||||
if let Some(room) = self.get_room(&room_id).await {
|
||||
ee.on_account_data_fully_read(Arc::clone(&room), &full_read)
|
||||
.await;
|
||||
}
|
||||
|
@ -810,14 +901,14 @@ impl Client {
|
|||
match event {
|
||||
NonRoomEvent::Presence(presence) => {
|
||||
if let Some(ee) = &self.event_emitter {
|
||||
if let Some(room) = self.get_room(&room_id) {
|
||||
if let Some(room) = self.get_room(&room_id).await {
|
||||
ee.on_account_presence(Arc::clone(&room), &presence).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
NonRoomEvent::IgnoredUserList(ignored) => {
|
||||
if let Some(ee) = &self.event_emitter {
|
||||
if let Some(room) = self.get_room(&room_id) {
|
||||
if let Some(room) = self.get_room(&room_id).await {
|
||||
ee.on_account_ignored_users(Arc::clone(&room), &ignored)
|
||||
.await;
|
||||
}
|
||||
|
@ -825,14 +916,14 @@ impl Client {
|
|||
}
|
||||
NonRoomEvent::PushRules(rules) => {
|
||||
if let Some(ee) = &self.event_emitter {
|
||||
if let Some(room) = self.get_room(&room_id) {
|
||||
if let Some(room) = self.get_room(&room_id).await {
|
||||
ee.on_account_push_rules(Arc::clone(&room), &rules).await;
|
||||
}
|
||||
}
|
||||
}
|
||||
NonRoomEvent::FullyRead(full_read) => {
|
||||
if let Some(ee) = &self.event_emitter {
|
||||
if let Some(room) = self.get_room(&room_id) {
|
||||
if let Some(room) = self.get_room(&room_id).await {
|
||||
ee.on_account_data_fully_read(Arc::clone(&room), &full_read)
|
||||
.await;
|
||||
}
|
||||
|
@ -844,7 +935,7 @@ impl Client {
|
|||
|
||||
pub(crate) async fn emit_presence_event(&self, room_id: &RoomId, event: &PresenceEvent) {
|
||||
if let Some(ee) = &self.event_emitter {
|
||||
if let Some(room) = self.get_room(&room_id) {
|
||||
if let Some(room) = self.get_room(&room_id).await {
|
||||
ee.on_presence_event(Arc::clone(&room), &event).await;
|
||||
}
|
||||
}
|
||||
|
@ -889,6 +980,7 @@ mod test {
|
|||
let _response = client.sync(sync_settings).await.unwrap();
|
||||
|
||||
let bc = &client.base_client.read().await;
|
||||
assert_eq!(1, bc.ignored_users.len())
|
||||
let ignored_users = bc.ignored_users.read().await;
|
||||
assert_eq!(1, ignored_users.len())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -493,7 +493,8 @@ mod test {
|
|||
|
||||
let _response = client.sync(sync_settings).await.unwrap();
|
||||
|
||||
let rooms = &client.base_client.read().await.joined_rooms;
|
||||
let rooms_lock = &client.base_client.read().await.joined_rooms;
|
||||
let rooms = rooms_lock.read().await;
|
||||
let room = &rooms
|
||||
.get(&RoomId::try_from("!SVkFJHzfwvuaIEawgC:localhost").unwrap())
|
||||
.unwrap()
|
||||
|
|
|
@ -13,13 +13,12 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub mod state_store;
|
||||
pub use state_store::JsonStore;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::base_client::{Client as BaseClient, Token};
|
||||
use crate::events::push_rules::Ruleset;
|
||||
use crate::identifiers::{RoomId, UserId};
|
||||
|
@ -48,7 +47,7 @@ impl PartialEq for ClientState {
|
|||
}
|
||||
|
||||
impl ClientState {
|
||||
pub fn from_base_client(client: &BaseClient) -> ClientState {
|
||||
pub async fn from_base_client(client: &BaseClient) -> ClientState {
|
||||
let BaseClient {
|
||||
sync_token,
|
||||
ignored_users,
|
||||
|
@ -56,9 +55,9 @@ impl ClientState {
|
|||
..
|
||||
} = client;
|
||||
Self {
|
||||
sync_token: sync_token.clone(),
|
||||
ignored_users: ignored_users.clone(),
|
||||
push_ruleset: push_ruleset.clone(),
|
||||
sync_token: sync_token.read().await.clone(),
|
||||
ignored_users: ignored_users.read().await.clone(),
|
||||
push_ruleset: push_ruleset.read().await.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -292,11 +292,11 @@ mod test {
|
|||
// assert the synced client and the logged in client are equal
|
||||
assert_eq!(base_client.session, Some(session));
|
||||
assert_eq!(
|
||||
base_client.sync_token,
|
||||
base_client.sync_token().await,
|
||||
Some("s526_47314_0_7_1_1_1_11444_1".to_string())
|
||||
);
|
||||
assert_eq!(
|
||||
base_client.ignored_users,
|
||||
*base_client.ignored_users.read().await,
|
||||
vec![UserId::try_from("@someone:example.org").unwrap()]
|
||||
);
|
||||
}
|
||||
|
|
|
@ -343,7 +343,7 @@ impl ClientTestRunner {
|
|||
}
|
||||
|
||||
async fn stream_client_events(&mut self) {
|
||||
let mut cli = self
|
||||
let cli = self
|
||||
.client
|
||||
.as_ref()
|
||||
.expect("`AsyncClient` must be set use `ClientTestRunner::set_client`")
|
||||
|
|
Loading…
Reference in New Issue