Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
20618e7
calculate room name internal `Room` method
DevinR528 Mar 27, 2020
a29ae2a
add test, AsyncClient room name methods
DevinR528 Mar 27, 2020
82f8af4
cargo fmt/clippy
DevinR528 Mar 27, 2020
3df15b7
use sync.json
DevinR528 Mar 27, 2020
c202218
fix slice match room_aliases
DevinR528 Mar 28, 2020
090600e
restructure folders, add User, fill out RoomMember, handle prescence.
DevinR528 Mar 28, 2020
e8b5534
start handle_power_levels
DevinR528 Mar 28, 2020
011e77c
calculate room name internal `Room` method
DevinR528 Mar 27, 2020
bcdd81d
add test, AsyncClient room name methods
DevinR528 Mar 27, 2020
063d86a
cargo fmt/clippy
DevinR528 Mar 27, 2020
6b5a357
use sync.json
DevinR528 Mar 27, 2020
7062bdb
fix slice match room_aliases
DevinR528 Mar 28, 2020
bb89db3
remove unused import
DevinR528 Mar 28, 2020
b760b32
fix rebase swap
DevinR528 Mar 28, 2020
bd50e61
use tokio::test, cargo fmt/clippy
DevinR528 Mar 28, 2020
b102779
Merge branch 'add-events' into room-name
DevinR528 Mar 28, 2020
9ee8a2d
merged add-events, fix a few type changes and merge fails
DevinR528 Mar 28, 2020
d4c9bb3
cargo fmt
DevinR528 Mar 28, 2020
0147e8c
update_member, update_power methods for room_member
DevinR528 Mar 28, 2020
4c7acd4
clean up presence updating and member state, add_presence_callback me…
DevinR528 Mar 29, 2020
05b6f46
cargo fmt/clippy
DevinR528 Mar 29, 2020
c89ae25
add account data, current room_id calc, unread, push ruleset, ignored…
DevinR528 Mar 29, 2020
14a8d04
account data loop
DevinR528 Mar 29, 2020
705464f
added a few todos, cargo fmt/clippy
DevinR528 Mar 30, 2020
4391fb6
looked over for review
DevinR528 Mar 30, 2020
62159cc
fix review issues
DevinR528 Mar 31, 2020
0d79c35
remove base_client method
DevinR528 Mar 31, 2020
df58c60
add tests in models files, run coverage
DevinR528 Mar 31, 2020
c3f4a94
remove split on UserId, update tests to correct domain
DevinR528 Mar 31, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions examples/login.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,14 @@ async fn async_cb(room: Arc<RwLock<Room>>, event: Arc<EventResult<RoomEvent>>) {
..
}) = event
{
let user = room.members.get(&sender.to_string()).unwrap();
let member = room.members.get(&sender.to_string()).unwrap();
println!(
"{}: {}",
user.display_name.as_ref().unwrap_or(&sender.to_string()),
member
.user
.display_name
.as_ref()
.unwrap_or(&sender.to_string()),
msg_body
);
}
Expand Down
150 changes: 142 additions & 8 deletions src/async_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,15 @@ use url::Url;

use ruma_api::{Endpoint, Outgoing};
use ruma_events::collections::all::RoomEvent;
use ruma_events::presence::PresenceEvent;
use ruma_events::room::message::MessageEventContent;
use ruma_events::EventResult;
pub use ruma_events::EventType;
use ruma_identifiers::RoomId;

use crate::api;
use crate::base_client::Client as BaseClient;
use crate::base_client::Room;
use crate::models::Room;
use crate::session::Session;
use crate::VERSION;
use crate::{Error, Result};
Expand All @@ -46,6 +47,11 @@ type RoomEventCallback = Box<
dyn FnMut(Arc<SyncLock<Room>>, Arc<EventResult<RoomEvent>>) -> BoxFuture<'static, ()> + Send,
>;

type PresenceEventCallback = Box<
dyn FnMut(Arc<SyncLock<Room>>, Arc<EventResult<PresenceEvent>>) -> BoxFuture<'static, ()>
+ Send,
>;

const DEFAULT_SYNC_TIMEOUT: Duration = Duration::from_secs(30);

#[derive(Clone)]
Expand All @@ -56,11 +62,12 @@ pub struct AsyncClient {
/// The underlying HTTP client.
http_client: reqwest::Client,
/// User session data.
base_client: Arc<RwLock<BaseClient>>,
pub(crate) base_client: Arc<RwLock<BaseClient>>,
/// The transaction id.
transaction_id: Arc<AtomicU64>,
/// Event callbacks
event_callbacks: Arc<Mutex<Vec<RoomEventCallback>>>,
presence_callbacks: Arc<Mutex<Vec<PresenceEventCallback>>>,
}

impl std::fmt::Debug for AsyncClient {
Expand Down Expand Up @@ -245,6 +252,7 @@ impl AsyncClient {
base_client: Arc::new(RwLock::new(BaseClient::new(session)?)),
transaction_id: Arc::new(AtomicU64::new(0)),
event_callbacks: Arc::new(Mutex::new(Vec::new())),
presence_callbacks: Arc::new(Mutex::new(Vec::new())),
})
}

Expand All @@ -260,6 +268,21 @@ impl AsyncClient {
&self.homeserver
}

/// Calculate the room name from a `RoomId`, returning a string.
pub async fn get_room_name(&self, room_id: &str) -> Option<String> {
self.base_client.read().await.calculate_room_name(room_id)
}

/// Calculate the room names this client knows about.
pub async fn get_room_names(&self) -> Vec<String> {
self.base_client.read().await.calculate_room_names()
}

/// Calculate the room names this client knows about.
pub async fn current_room_id(&self) -> Option<RoomId> {
self.base_client.read().await.current_room_id()
}

/// Add a callback that will be called every time the client receives a room
/// event
///
Expand Down Expand Up @@ -293,10 +316,10 @@ impl AsyncClient {
/// ..
/// }) = event
/// {
/// let user = room.members.get(&sender.to_string()).unwrap();
/// let member = room.members.get(&sender.to_string()).unwrap();
/// println!(
/// "{}: {}",
/// user.display_name.as_ref().unwrap_or(&sender.to_string()),
/// member.user.display_name.as_ref().unwrap_or(&sender.to_string()),
/// msg_body
/// );
/// }
Expand All @@ -323,6 +346,78 @@ impl AsyncClient {
futures.push(Box::new(future));
}

/// Add a callback that will be called every time the client receives a presence
/// event
///
/// # Arguments
///
/// * `callback` - The callback that should be called once a RoomEvent is
/// received.
///
/// # Examples
/// ```
/// # use matrix_sdk::events::{
/// # collections::all::RoomEvent,
/// # room::message::{MessageEvent, MessageEventContent, TextMessageEventContent},
/// # presence::{PresenceEvent, PresenceEventContent},
/// # EventResult,
/// # };
/// # use matrix_sdk::Room;
/// # use std::sync::{Arc, RwLock};
/// # use matrix_sdk::AsyncClient;
/// # use url::Url;
///
/// async fn async_cb(room: Arc<RwLock<Room>>, event: Arc<EventResult<PresenceEvent>>) {
/// let room = room.read().unwrap();
/// let event = if let EventResult::Ok(event) = &*event {
/// event
/// } else {
/// return;
/// };
/// let PresenceEvent {
/// content: PresenceEventContent {
/// avatar_url,
/// currently_active,
/// displayname,
/// last_active_ago,
/// presence,
/// status_msg,
/// },
/// sender,
/// } = event;
/// {
/// let member = room.members.get(&sender.to_string()).unwrap();
/// println!(
/// "{} is {}",
/// displayname.as_deref().unwrap_or(&sender.to_string()),
/// status_msg.as_deref().unwrap_or("not here")
/// );
/// }
/// }
/// # fn main() -> Result<(), matrix_sdk::Error> {
/// let homeserver = Url::parse("http://localhost:8080")?;
///
/// let mut client = AsyncClient::new(homeserver, None)?;
///
/// client.add_presence_callback(async_cb);
/// # Ok(())
/// # }
/// ```
pub fn add_presence_callback<C: 'static>(
&mut self,
mut callback: impl FnMut(Arc<SyncLock<Room>>, Arc<EventResult<PresenceEvent>>) -> C
+ 'static
+ Send,
) where
C: Future<Output = ()> + Send,
{
let mut futures = self.presence_callbacks.lock().unwrap();

let future = move |room, event| callback(room, event).boxed();

futures.push(Box::new(future));
}

/// Login to the server.
///
/// # Arguments
Expand All @@ -332,9 +427,9 @@ impl AsyncClient {
/// * `password` - The password of the user.
///
/// * `device_id` - A unique id that will be associated with this session. If
/// not given the homeserver will create one. Can be an exising
/// not given the homeserver will create one. Can be an existing
/// device_id from a previous login call. Note that this should be done
/// only if the client also holds the encryption keys for this devcie.
/// only if the client also holds the encryption keys for this device.
#[instrument(skip(password))]
pub async fn login<S: Into<String> + std::fmt::Debug>(
&mut self,
Expand All @@ -361,7 +456,7 @@ impl AsyncClient {
Ok(response)
}

/// Synchronise the client's state with the latest state on the server.
/// Synchronize the client's state with the latest state on the server.
///
/// # Arguments
///
Expand Down Expand Up @@ -420,7 +515,7 @@ impl AsyncClient {
let mut callbacks = Vec::new();

for cb in &mut cb_futures.iter_mut() {
callbacks.push(cb(matrix_room.clone(), event.clone()));
callbacks.push(cb(matrix_room.clone(), Arc::clone(&event)));
}

callbacks
Expand All @@ -430,6 +525,45 @@ impl AsyncClient {
cb.await;
}
}

// look at AccountData to further cut down users by collecting ignored users
// TODO actually use the ignored users
for account_data in &room.account_data.events {
let mut client = self.base_client.write().await;
if let EventResult::Ok(e) = account_data {
client.receive_account_data(&room_id_string, e);
}
}

// TODO `IncomingEphemeral` events for typing events

// 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 &response.presence.events {
let mut client = self.base_client.write().await;
if let EventResult::Ok(e) = presence {
client.receive_presence_event(&room_id_string, e);
}

let callbacks = {
let mut cb_futures = self.presence_callbacks.lock().unwrap();
let event = if !cb_futures.is_empty() {
Arc::new(presence.clone())
} else {
continue;
};
let mut callbacks = Vec::new();
for cb in &mut cb_futures.iter_mut() {
callbacks.push(cb(matrix_room.clone(), Arc::clone(&event)));
}

callbacks
};
for cb in callbacks {
cb.await;
}
}
}

let mut client = self.base_client.write().await;
Expand Down
Loading