From c69d54e2d4ac4234d183aeda8515410c3ee17e71 Mon Sep 17 00:00:00 2001 From: Devin R Date: Fri, 10 Apr 2020 16:32:28 -0400 Subject: [PATCH 01/10] async_client: impl kick, join, leave, invite, create for --- src/async_client.rs | 167 ++++++++++++++++++++++++++++++++- src/lib.rs | 2 + src/request_builder.rs | 204 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 372 insertions(+), 1 deletion(-) create mode 100644 src/request_builder.rs diff --git a/src/async_client.rs b/src/async_client.rs index 9ce12c68..282e0c35 100644 --- a/src/async_client.rs +++ b/src/async_client.rs @@ -37,7 +37,7 @@ use ruma_api::{Endpoint, Outgoing}; use ruma_events::room::message::MessageEventContent; use ruma_events::EventResult; pub use ruma_events::EventType; -use ruma_identifiers::RoomId; +use ruma_identifiers::{RoomId, RoomIdOrAliasId, UserId}; #[cfg(feature = "encryption")] use ruma_identifiers::{DeviceId, UserId}; @@ -181,7 +181,16 @@ impl SyncSettings { use api::r0::client_exchange::send_event_to_device; #[cfg(feature = "encryption")] use api::r0::keys::{claim_keys, get_keys, upload_keys, KeyAlgorithm}; +use api::r0::membership::join_room_by_id; +use api::r0::membership::join_room_by_id_or_alias; +use api::r0::membership::kick_user; +use api::r0::membership::leave_room; +use api::r0::membership::{ + invite_user::{self, InvitationRecipient}, + Invite3pid, +}; use api::r0::message::create_message_event; +use api::r0::room::create_room; use api::r0::session::login; use api::r0::sync::sync_events; @@ -333,6 +342,162 @@ impl AsyncClient { Ok(response) } + /// Join a room by `RoomId`. + /// + /// Returns a `join_room_by_id::Response` consisting of the + /// joined rooms `RoomId`. + /// + /// # Arguments + /// + /// * room_id - A valid RoomId otherwise sending will fail. + /// + pub async fn join_room_by_id(&mut self, room_id: &RoomId) -> Result { + let request = join_room_by_id::Request { + room_id: room_id.clone(), + third_party_signed: None, + }; + self.send(request).await + } + + /// Join a room by `RoomId`. + /// + /// Returns a `join_room_by_id_or_alias::Response` consisting of the + /// joined rooms `RoomId`. + /// + /// # Arguments + /// + /// * alias - A valid `RoomIdOrAliasId` otherwise sending will fail. + /// + pub async fn join_room_by_id_or_alias( + &mut self, + alias: &RoomIdOrAliasId, + ) -> Result { + let request = join_room_by_id_or_alias::Request { + room_id_or_alias: alias.clone(), + third_party_signed: None, + }; + self.send(request).await + } + + /// Kick a user out of the specified room. + /// + /// Returns a `kick_user::Response`, an empty response. + /// + /// # Arguments + /// + /// * room_id - A valid `RoomId` otherwise sending will fail. + /// + /// * user_id - A valid `UserId`. + /// + /// * reason - Optional reason why the room member is being kicked out. + /// + pub async fn kick_user( + &mut self, + room_id: &RoomId, + user_id: &UserId, + reason: Option, + ) -> Result { + let request = kick_user::Request { + reason, + room_id: room_id.clone(), + user_id: user_id.clone(), + }; + self.send(request).await + } + + /// Leave the specified room. + /// + /// Returns a `leave_room::Response`, an empty response. + /// + /// # Arguments + /// + /// * room_id - A valid `RoomId`. + /// + pub async fn leave_room(&mut self, room_id: &RoomId) -> Result { + let request = leave_room::Request { + room_id: room_id.clone(), + }; + self.send(request).await + } + + /// Invite the specified user by `UserId` to the given room. + /// + /// Returns a `invite_user::Response`, an empty response. + /// + /// # Arguments + /// + /// * room_id - A valid `RoomId`. + /// + /// * user_id - A valid `UserId`. + /// + pub async fn invite_user_by_id( + &mut self, + room_id: &RoomId, + user_id: &UserId, + ) -> Result { + let request = invite_user::Request { + room_id: room_id.clone(), + recipient: InvitationRecipient::UserId { + user_id: user_id.clone(), + }, + }; + self.send(request).await + } + + /// Invite the specified user by third party id to the given room. + /// + /// Returns a `invite_user::Response`, an empty response. + /// + /// # Arguments + /// + /// * room_id - A valid `RoomId`. + /// + /// * invite_id - A valid `UserId`. + /// + pub async fn invite_user_by_3pid( + &mut self, + room_id: &RoomId, + invite_id: &Invite3pid, + ) -> Result { + let request = invite_user::Request { + room_id: room_id.clone(), + recipient: InvitationRecipient::ThirdPartyId(invite_id.clone()), + }; + self.send(request).await + } + + /// A builder to create a room and send the request. + /// + /// Returns a `create_room::Response`, an empty response. + /// + /// # Arguments + /// + /// * room - the easiest way to create this request is using `RoomBuilder` struct. + /// + /// # Examples + /// ```ignore + /// use matrix_sdk::{AsyncClient, RoomBuilder}; + /// + /// let mut bldr = RoomBuilder::default(); + /// bldr.creation_content(false) + /// .initial_state(vec![]) + /// .visibility(Visibility::Public) + /// .name("name") + /// .room_version("v1.0"); + /// + /// let mut cli = AsyncClient::new(homeserver, Some(session)).unwrap(); + /// + /// assert!(cli.create_room(bldr).await.is_ok()); + /// ``` + /// + pub async fn create_room>( + &mut self, + room: R, + ) -> Result { + let request = room.into(); + self.send(request).await + } + /// Synchronize the client's state with the latest state on the server. /// /// # Arguments diff --git a/src/lib.rs b/src/lib.rs index 28bf9375..3cbf4379 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,6 +38,7 @@ mod base_client; mod error; mod event_emitter; mod models; +mod request_builder; mod session; #[cfg(test)] @@ -50,5 +51,6 @@ pub use async_client::{AsyncClient, AsyncClientConfig, SyncSettings}; pub use base_client::Client; pub use event_emitter::EventEmitter; pub use models::Room; +pub use request_builder::RoomBuilder; pub(crate) const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/src/request_builder.rs b/src/request_builder.rs new file mode 100644 index 00000000..aed4f55e --- /dev/null +++ b/src/request_builder.rs @@ -0,0 +1,204 @@ +use crate::events::room::power_levels::PowerLevelsEventContent; +use crate::identifiers::UserId; +use crate::api; +use api::r0::membership::Invite3pid; +use api::r0::room::{ + create_room::{self, CreationContent, InitialStateEvent, RoomPreset}, + Visibility, +}; + +/// A builder used to create rooms. +/// +/// # Examples +/// ``` +/// +/// ``` +#[derive(Default)] +pub struct RoomBuilder { + /// Extra keys to be added to the content of the `m.room.create`. + creation_content: Option, + /// List of state events to send to the new room. + /// + /// Takes precedence over events set by preset, but gets overriden by + /// name and topic keys. + initial_state: Vec, + /// A list of user IDs to invite to the room. + /// + /// This will tell the server to invite everyone in the list to the newly created room. + invite: Vec, + /// List of third party IDs of users to invite. + invite_3pid: Vec, + /// If set, this sets the `is_direct` flag on room invites. + is_direct: Option, + /// If this is included, an `m.room.name` event will be sent into the room to indicate + /// the name of the room. + name: Option, + /// Power level content to override in the default power level event. + power_level_content_override: Option, + /// Convenience parameter for setting various default state events based on a preset. + preset: Option, + /// The desired room alias local part. + room_alias_name: Option, + /// Room version to set for the room. Defaults to homeserver's default if not specified. + room_version: Option, + /// If this is included, an `m.room.topic` event will be sent into the room to indicate + /// the topic for the room. + topic: Option, + /// A public visibility indicates that the room will be shown in the published room + /// list. A private visibility will hide the room from the published room list. Rooms + /// default to private visibility if this key is not included. + visibility: Option, +} + +impl RoomBuilder { + /// Returns an empty `RoomBuilder` for creating rooms. + pub fn new() -> Self { + Self::default() + } + + /// Set the `CreationContent`. + /// + /// Weather users on other servers can join this room. + pub fn creation_content(&mut self, federate: bool) -> &mut Self { + let federate = Some(federate); + self.creation_content = Some(CreationContent { federate }); + self + } + + /// Set the `InitialStateEvent` vector. + /// + pub fn initial_state(&mut self, state: Vec) -> &mut Self { + self.initial_state = state; + self + } + + /// Set the vec of `UserId`s. + /// + pub fn invite(&mut self, invite: Vec) -> &mut Self { + self.invite = invite; + self + } + + /// Set the vec of `Invite3pid`s. + /// + pub fn invite_3pid(&mut self, invite: Vec) -> &mut Self { + self.invite_3pid = invite; + self + } + + /// Set the vec of `Invite3pid`s. + /// + pub fn is_direct(&mut self, direct: bool) -> &mut Self { + self.is_direct = Some(direct); + self + } + + /// Set the room name. A `m.room.name` event will be sent to the room. + /// + pub fn name>(&mut self, name: S) -> &mut Self { + self.name = Some(name.into()); + self + } + + /// Set the room's power levels. + /// + pub fn power_level_override(&mut self, power: PowerLevelsEventContent) -> &mut Self { + self.power_level_content_override = Some(power); + self + } + + /// Convenience for setting various default state events based on a preset. + /// + pub fn preset(&mut self, preset: RoomPreset) -> &mut Self { + self.preset = Some(preset); + self + } + + /// The local part of a room alias. + /// + pub fn room_alias_name>(&mut self, alias: S) -> &mut Self { + self.room_alias_name = Some(alias.into()); + self + } + + /// Room version, defaults to homeserver's version if left unspecified. + /// + pub fn room_version>(&mut self, version: S) -> &mut Self { + self.room_version = Some(version.into()); + self + } + + /// If included, a `m.room.topic` event will be sent to the room. + /// + pub fn topic>(&mut self, topic: S) -> &mut Self { + self.topic = Some(topic.into()); + self + } + + /// A public visibility indicates that the room will be shown in the published + /// room list. A private visibility will hide the room from the published room list. + /// Rooms default to private visibility if this key is not included. + /// + pub fn visibility(&mut self, vis: Visibility) -> &mut Self { + self.visibility = Some(vis); + self + } +} + +impl Into for RoomBuilder { + fn into(self) -> create_room::Request { + create_room::Request { + creation_content: self.creation_content, + initial_state: self.initial_state, + invite: self.invite, + invite_3pid: self.invite_3pid, + is_direct: self.is_direct, + name: self.name, + power_level_content_override: self.power_level_content_override, + preset: self.preset, + room_alias_name: self.room_alias_name, + room_version: self.room_version, + topic: self.topic, + visibility: self.visibility, + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + use crate::{AsyncClient, Session}; + + use mockito::mock; + use url::Url; + + use std::convert::TryFrom; + + #[tokio::test] + async fn create_room_builder() { + let homeserver = Url::parse(&mockito::server_url()).unwrap(); + + let _m = mock("POST", "/_matrix/client/r0/createRoom") + .with_status(200) + .with_body_from_file("./tests/data/room_id.json") + .create(); + + let session = Session { + access_token: "1234".to_owned(), + user_id: UserId::try_from("@example:localhost").unwrap(), + device_id: "DEVICEID".to_owned(), + }; + + let mut bldr = RoomBuilder::default(); + bldr.creation_content(false) + .initial_state(vec![]) + .visibility(Visibility::Public) + .name("name") + .room_version("v1.0"); + + let mut cli = AsyncClient::new(homeserver, Some(session)).unwrap(); + + assert!(cli.create_room(bldr).await.is_ok()); + } +} From 6358db94c707286517ad6fbbbf569a9e930390d7 Mon Sep 17 00:00:00 2001 From: Devin R Date: Fri, 10 Apr 2020 21:44:16 -0400 Subject: [PATCH 02/10] more docs --- src/async_client.rs | 1 - src/request_builder.rs | 22 ++++++++++++++++------ 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/async_client.rs b/src/async_client.rs index 282e0c35..7557536c 100644 --- a/src/async_client.rs +++ b/src/async_client.rs @@ -486,7 +486,6 @@ impl AsyncClient { /// .room_version("v1.0"); /// /// let mut cli = AsyncClient::new(homeserver, Some(session)).unwrap(); - /// /// assert!(cli.create_room(bldr).await.is_ok()); /// ``` /// diff --git a/src/request_builder.rs b/src/request_builder.rs index aed4f55e..e174f8b7 100644 --- a/src/request_builder.rs +++ b/src/request_builder.rs @@ -11,9 +11,23 @@ use api::r0::room::{ /// /// # Examples /// ``` -/// +/// # use matrix_sdk::{AsyncClient, RoomBuilder}; +/// # use matrix_sdk::api::r0::room::Visibility; +/// # use url::Url; +/// # let homeserver = Url::parse("http://example.com").unwrap(); +/// let mut bldr = RoomBuilder::default(); +/// bldr.creation_content(false) +/// .initial_state(vec![]) +/// .visibility(Visibility::Public) +/// .name("name") +/// .room_version("v1.0"); +/// let mut cli = AsyncClient::new(homeserver, None).unwrap(); +/// # use futures::executor::block_on; +/// # block_on(async { +/// assert!(cli.create_room(bldr).await.is_err()); +/// # }) /// ``` -#[derive(Default)] +#[derive(Clone, Default)] pub struct RoomBuilder { /// Extra keys to be added to the content of the `m.room.create`. creation_content: Option, @@ -169,10 +183,8 @@ mod test { use super::*; use crate::{AsyncClient, Session}; - use mockito::mock; use url::Url; - use std::convert::TryFrom; #[tokio::test] @@ -196,9 +208,7 @@ mod test { .visibility(Visibility::Public) .name("name") .room_version("v1.0"); - let mut cli = AsyncClient::new(homeserver, Some(session)).unwrap(); - assert!(cli.create_room(bldr).await.is_ok()); } } From 7aeeeea4321f1bbc4a4a06542beba40342d9d378 Mon Sep 17 00:00:00 2001 From: Devin R Date: Sat, 11 Apr 2020 08:46:45 -0400 Subject: [PATCH 03/10] request_builder: test GetMessageBuilder --- src/async_client.rs | 33 ++++++- src/lib.rs | 2 +- src/request_builder.rs | 205 ++++++++++++++++++++++++++++++++++++----- 3 files changed, 214 insertions(+), 26 deletions(-) diff --git a/src/async_client.rs b/src/async_client.rs index 7557536c..9d9635e0 100644 --- a/src/async_client.rs +++ b/src/async_client.rs @@ -40,7 +40,7 @@ pub use ruma_events::EventType; use ruma_identifiers::{RoomId, RoomIdOrAliasId, UserId}; #[cfg(feature = "encryption")] -use ruma_identifiers::{DeviceId, UserId}; +use ruma_identifiers::DeviceId; use crate::api; use crate::base_client::Client as BaseClient; @@ -190,6 +190,7 @@ use api::r0::membership::{ Invite3pid, }; use api::r0::message::create_message_event; +use api::r0::message::get_message_events; use api::r0::room::create_room; use api::r0::session::login; use api::r0::sync::sync_events; @@ -472,7 +473,7 @@ impl AsyncClient { /// /// # Arguments /// - /// * room - the easiest way to create this request is using `RoomBuilder` struct. + /// * room - the easiest way to create this request is using the `RoomBuilder`. /// /// # Examples /// ```ignore @@ -497,6 +498,34 @@ impl AsyncClient { self.send(request).await } + /// Invite the specified user by third party id to the given room. + /// + /// Returns a `invite_user::Response`, an empty response. + /// + /// # Arguments + /// + /// * request - The easiest way to create a `Request` is using the `GetMessageBuilder` + pub async fn get_message_events>( + &mut self, + request: R, + ) -> Result { + let req = request.into(); + let room_id = req.room_id.clone(); + let mut res = self.send(req).await?; + let mut client = self.base_client.write().await; + // TODO should we support this event? to keep emitting these msg events this is needed + for mut event in &mut res.chunk { + client + .receive_joined_timeline_event(&room_id, &mut event) + .await; + + if let EventResult::Ok(e) = event { + client.emit_timeline_event(&room_id, e).await; + } + } + Ok(res) + } + /// Synchronize the client's state with the latest state on the server. /// /// # Arguments diff --git a/src/lib.rs b/src/lib.rs index 3cbf4379..1e9412ca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,6 +51,6 @@ pub use async_client::{AsyncClient, AsyncClientConfig, SyncSettings}; pub use base_client::Client; pub use event_emitter::EventEmitter; pub use models::Room; -pub use request_builder::RoomBuilder; +pub use request_builder::{GetMessageBuilder, RoomBuilder}; pub(crate) const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/src/request_builder.rs b/src/request_builder.rs index e174f8b7..1553dee8 100644 --- a/src/request_builder.rs +++ b/src/request_builder.rs @@ -1,20 +1,28 @@ -use crate::events::room::power_levels::PowerLevelsEventContent; -use crate::identifiers::UserId; use crate::api; +use crate::events::room::power_levels::PowerLevelsEventContent; +use crate::identifiers::{RoomId, UserId}; +use api::r0::filter::RoomEventFilter; use api::r0::membership::Invite3pid; +use api::r0::message::get_message_events::{self, Direction}; use api::r0::room::{ create_room::{self, CreationContent, InitialStateEvent, RoomPreset}, Visibility, }; +use js_int::UInt; + /// A builder used to create rooms. /// /// # Examples /// ``` +/// # use std::convert::TryFrom; /// # use matrix_sdk::{AsyncClient, RoomBuilder}; /// # use matrix_sdk::api::r0::room::Visibility; +/// # use matrix_sdk::identifiers::UserId; /// # use url::Url; /// # let homeserver = Url::parse("http://example.com").unwrap(); +/// # let mut rt = tokio::runtime::Runtime::new().unwrap(); +/// # rt.block_on(async { /// let mut bldr = RoomBuilder::default(); /// bldr.creation_content(false) /// .initial_state(vec![]) @@ -22,9 +30,7 @@ use api::r0::room::{ /// .name("name") /// .room_version("v1.0"); /// let mut cli = AsyncClient::new(homeserver, None).unwrap(); -/// # use futures::executor::block_on; -/// # block_on(async { -/// assert!(cli.create_room(bldr).await.is_err()); +/// cli.create_room(bldr).await; /// # }) /// ``` #[derive(Clone, Default)] @@ -80,70 +86,60 @@ impl RoomBuilder { } /// Set the `InitialStateEvent` vector. - /// pub fn initial_state(&mut self, state: Vec) -> &mut Self { self.initial_state = state; self } /// Set the vec of `UserId`s. - /// pub fn invite(&mut self, invite: Vec) -> &mut Self { self.invite = invite; self } /// Set the vec of `Invite3pid`s. - /// pub fn invite_3pid(&mut self, invite: Vec) -> &mut Self { self.invite_3pid = invite; self } /// Set the vec of `Invite3pid`s. - /// pub fn is_direct(&mut self, direct: bool) -> &mut Self { self.is_direct = Some(direct); self } /// Set the room name. A `m.room.name` event will be sent to the room. - /// pub fn name>(&mut self, name: S) -> &mut Self { self.name = Some(name.into()); self } /// Set the room's power levels. - /// pub fn power_level_override(&mut self, power: PowerLevelsEventContent) -> &mut Self { self.power_level_content_override = Some(power); self } /// Convenience for setting various default state events based on a preset. - /// pub fn preset(&mut self, preset: RoomPreset) -> &mut Self { self.preset = Some(preset); self } /// The local part of a room alias. - /// pub fn room_alias_name>(&mut self, alias: S) -> &mut Self { self.room_alias_name = Some(alias.into()); self } /// Room version, defaults to homeserver's version if left unspecified. - /// pub fn room_version>(&mut self, version: S) -> &mut Self { self.room_version = Some(version.into()); self } /// If included, a `m.room.topic` event will be sent to the room. - /// pub fn topic>(&mut self, topic: S) -> &mut Self { self.topic = Some(topic.into()); self @@ -152,7 +148,6 @@ impl RoomBuilder { /// A public visibility indicates that the room will be shown in the published /// room list. A private visibility will hide the room from the published room list. /// Rooms default to private visibility if this key is not included. - /// pub fn visibility(&mut self, vis: Visibility) -> &mut Self { self.visibility = Some(vis); self @@ -178,14 +173,131 @@ impl Into for RoomBuilder { } } +/// Create a builder for making get_message_event requests. +#[derive(Clone, Default)] +pub struct GetMessageBuilder { + /// The room to get events from. + room_id: Option, + /// The token to start returning events from. + /// + /// This token can be obtained from a + /// prev_batch token returned for each room by the sync API, or from a start or end token + /// returned by a previous request to this endpoint. + from: Option, + /// The token to stop returning events at. + /// + /// This token can be obtained from a prev_batch + /// token returned for each room by the sync endpoint, or from a start or end token returned + /// by a previous request to this endpoint. + to: Option, + /// The direction to return events from. + direction: Option, + /// The maximum number of events to return. + /// + /// Default: 10. + limit: Option, + /// A filter of the returned events with. + filter: Option, +} + +impl GetMessageBuilder { + /// Create a `GetMessageBuilder` builder to make a `get_message_events::Request`. + /// + /// The `room_id` and `from`` fields **need to be set** to create the request. + /// + /// # Examples + /// ``` + /// # use matrix_sdk::{AsyncClient, GetMessageBuilder}; + /// # use matrix_sdk::api::r0::message::get_message_events::{self, Direction}; + /// # use matrix_sdk::identifiers::RoomId; + /// # use url::Url; + /// # let homeserver = Url::parse("http://example.com").unwrap(); + /// # let mut rt = tokio::runtime::Runtime::new().unwrap(); + /// # rt.block_on(async { + /// # let room_id = RoomId::new(homeserver.as_str()).unwrap(); + /// # let last_sync_token = "".to_string();; + /// let mut cli = AsyncClient::new(homeserver, None).unwrap(); + /// + /// let mut bldr = GetMessageBuilder::new(); + /// bldr.room_id(room_id) + /// .from(last_sync_token) + /// .direction(Direction::Forward); + /// + /// cli.get_message_events(bldr).await.is_err(); + /// # }) + /// ``` + pub fn new() -> Self { + Self::default() + } + + /// RoomId is required to create a `get_message_events::Request`. + pub fn room_id(&mut self, room_id: RoomId) -> &mut Self { + self.room_id = Some(room_id); + self + } + + /// A `next_batch` token or `start` or `end` from a previous `get_message_events` request. + /// + /// This is required to create a `get_message_events::Request`. + pub fn from(&mut self, from: String) -> &mut Self { + self.from = Some(from); + self + } + + /// A `next_batch` token or `start` or `end` from a previous `get_message_events` request. + /// + /// This token signals when to stop receiving events. + pub fn to(&mut self, to: String) -> &mut Self { + self.to = Some(to); + self + } + + /// The direction to return events from. + /// + /// If not specified `Direction::Backward` is used. + pub fn direction(&mut self, direction: Direction) -> &mut Self { + self.direction = Some(direction); + self + } + + /// The maximum number of events to return. + pub fn limit(&mut self, limit: UInt) -> &mut Self { + self.limit = Some(limit); + self + } + + /// Filter events by the given `RoomEventFilter`. + pub fn filter(&mut self, filter: RoomEventFilter) -> &mut Self { + self.filter = Some(filter); + self + } +} + +impl Into for GetMessageBuilder { + fn into(self) -> get_message_events::Request { + get_message_events::Request { + room_id: self.room_id.expect("`room_id` and `from` need to be set"), + from: self.from.expect("`room_id` and `from` need to be set"), + to: self.to, + dir: self.direction.unwrap_or(Direction::Backward), + limit: self.limit, + filter: self.filter, + } + } +} + #[cfg(test)] mod test { - use super::*; + use std::collections::HashMap; - use crate::{AsyncClient, Session}; - use mockito::mock; - use url::Url; + use super::*; + use crate::{AsyncClient, Session, identifiers::RoomId}; + use crate::events::room::power_levels::NotificationPowerLevels; + + use js_int::Int; + use mockito::{mock, Matcher}; use std::convert::TryFrom; + use url::Url; #[tokio::test] async fn create_room_builder() { @@ -202,13 +314,60 @@ mod test { device_id: "DEVICEID".to_owned(), }; - let mut bldr = RoomBuilder::default(); + let mut bldr = RoomBuilder::new(); bldr.creation_content(false) .initial_state(vec![]) .visibility(Visibility::Public) - .name("name") - .room_version("v1.0"); + .name("room_name") + .room_version("v1.0") + .invite_3pid(vec![]) + .is_direct(true) + .power_level_override(PowerLevelsEventContent { + ban: Int::max_value(), + events: HashMap::default(), + events_default: Int::min_value(), + invite: Int::min_value(), + kick: Int::min_value(), + redact: Int::max_value(), + state_default: Int::min_value(), + users_default: Int::min_value(), + notifications: NotificationPowerLevels { room: Int::min_value() }, + users: HashMap::default(), + }) + .preset(RoomPreset::PrivateChat) + .room_alias_name("room_alias") + .topic("room topic") + .visibility(Visibility::Private); let mut cli = AsyncClient::new(homeserver, Some(session)).unwrap(); assert!(cli.create_room(bldr).await.is_ok()); } + + #[tokio::test] + async fn get_message_events() { + let homeserver = Url::parse(&mockito::server_url()).unwrap(); + + let _m = mock("GET", Matcher::Regex(r"^/_matrix/client/r0/rooms/.*/messages".to_string())) + .with_status(200) + .with_body_from_file("./tests/data/room_messages.json") + .create(); + + let session = Session { + access_token: "1234".to_owned(), + user_id: UserId::try_from("@example:localhost").unwrap(), + device_id: "DEVICEID".to_owned(), + }; + + let mut bldr = GetMessageBuilder::new(); + bldr + .room_id(RoomId::try_from("!roomid:example.com").unwrap()) + .from("t47429-4392820_219380_26003_2265".to_string()) + .to("t4357353_219380_26003_2265".to_string()) + .direction(Direction::Backward) + .limit(UInt::new(10).unwrap()); + // TODO this makes ruma error `Err(IntoHttp(IntoHttpError(Query(Custom("unsupported value")))))`?? + // .filter(RoomEventFilter::default()); + + let mut cli = AsyncClient::new(homeserver, Some(session)).unwrap(); + assert!(cli.get_message_events(bldr).await.is_ok()); + } } From 5180f99a0e3ceb87ceb74cf6f4223e540898b724 Mon Sep 17 00:00:00 2001 From: Devin R Date: Sat, 11 Apr 2020 15:58:34 -0400 Subject: [PATCH 04/10] cargo fmt/update fixed olm --- src/request_builder.rs | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/src/request_builder.rs b/src/request_builder.rs index 1553dee8..7eef70af 100644 --- a/src/request_builder.rs +++ b/src/request_builder.rs @@ -291,8 +291,8 @@ mod test { use std::collections::HashMap; use super::*; - use crate::{AsyncClient, Session, identifiers::RoomId}; use crate::events::room::power_levels::NotificationPowerLevels; + use crate::{identifiers::RoomId, AsyncClient, Session}; use js_int::Int; use mockito::{mock, Matcher}; @@ -331,7 +331,9 @@ mod test { redact: Int::max_value(), state_default: Int::min_value(), users_default: Int::min_value(), - notifications: NotificationPowerLevels { room: Int::min_value() }, + notifications: NotificationPowerLevels { + room: Int::min_value(), + }, users: HashMap::default(), }) .preset(RoomPreset::PrivateChat) @@ -346,10 +348,13 @@ mod test { async fn get_message_events() { let homeserver = Url::parse(&mockito::server_url()).unwrap(); - let _m = mock("GET", Matcher::Regex(r"^/_matrix/client/r0/rooms/.*/messages".to_string())) - .with_status(200) - .with_body_from_file("./tests/data/room_messages.json") - .create(); + let _m = mock( + "GET", + Matcher::Regex(r"^/_matrix/client/r0/rooms/.*/messages".to_string()), + ) + .with_status(200) + .with_body_from_file("./tests/data/room_messages.json") + .create(); let session = Session { access_token: "1234".to_owned(), @@ -358,14 +363,13 @@ mod test { }; let mut bldr = GetMessageBuilder::new(); - bldr - .room_id(RoomId::try_from("!roomid:example.com").unwrap()) + bldr.room_id(RoomId::try_from("!roomid:example.com").unwrap()) .from("t47429-4392820_219380_26003_2265".to_string()) .to("t4357353_219380_26003_2265".to_string()) .direction(Direction::Backward) .limit(UInt::new(10).unwrap()); - // TODO this makes ruma error `Err(IntoHttp(IntoHttpError(Query(Custom("unsupported value")))))`?? - // .filter(RoomEventFilter::default()); + // TODO this makes ruma error `Err(IntoHttp(IntoHttpError(Query(Custom("unsupported value")))))`?? + // .filter(RoomEventFilter::default()); let mut cli = AsyncClient::new(homeserver, Some(session)).unwrap(); assert!(cli.get_message_events(bldr).await.is_ok()); From 0d8702b292a03b4846c51284f632fd9f5ba7c34d Mon Sep 17 00:00:00 2001 From: Devin R Date: Sun, 12 Apr 2020 08:21:23 -0400 Subject: [PATCH 05/10] rename get_message_events to room_messages --- src/async_client.rs | 2 +- src/lib.rs | 2 +- src/request_builder.rs | 18 +++++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/async_client.rs b/src/async_client.rs index 9d9635e0..7ef25b69 100644 --- a/src/async_client.rs +++ b/src/async_client.rs @@ -505,7 +505,7 @@ impl AsyncClient { /// # Arguments /// /// * request - The easiest way to create a `Request` is using the `GetMessageBuilder` - pub async fn get_message_events>( + pub async fn room_messages>( &mut self, request: R, ) -> Result { diff --git a/src/lib.rs b/src/lib.rs index 1e9412ca..0e00b83e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,6 +51,6 @@ pub use async_client::{AsyncClient, AsyncClientConfig, SyncSettings}; pub use base_client::Client; pub use event_emitter::EventEmitter; pub use models::Room; -pub use request_builder::{GetMessageBuilder, RoomBuilder}; +pub use request_builder::{RoomBuilder, RoomMessageBuilder}; pub(crate) const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/src/request_builder.rs b/src/request_builder.rs index 7eef70af..9cdebe88 100644 --- a/src/request_builder.rs +++ b/src/request_builder.rs @@ -175,7 +175,7 @@ impl Into for RoomBuilder { /// Create a builder for making get_message_event requests. #[derive(Clone, Default)] -pub struct GetMessageBuilder { +pub struct RoomMessageBuilder { /// The room to get events from. room_id: Option, /// The token to start returning events from. @@ -200,14 +200,14 @@ pub struct GetMessageBuilder { filter: Option, } -impl GetMessageBuilder { - /// Create a `GetMessageBuilder` builder to make a `get_message_events::Request`. +impl RoomMessageBuilder { + /// Create a `RoomMessageBuilder` builder to make a `get_message_events::Request`. /// /// The `room_id` and `from`` fields **need to be set** to create the request. /// /// # Examples /// ``` - /// # use matrix_sdk::{AsyncClient, GetMessageBuilder}; + /// # use matrix_sdk::{AsyncClient, RoomMessageBuilder}; /// # use matrix_sdk::api::r0::message::get_message_events::{self, Direction}; /// # use matrix_sdk::identifiers::RoomId; /// # use url::Url; @@ -218,12 +218,12 @@ impl GetMessageBuilder { /// # let last_sync_token = "".to_string();; /// let mut cli = AsyncClient::new(homeserver, None).unwrap(); /// - /// let mut bldr = GetMessageBuilder::new(); + /// let mut bldr = RoomMessageBuilder::new(); /// bldr.room_id(room_id) /// .from(last_sync_token) /// .direction(Direction::Forward); /// - /// cli.get_message_events(bldr).await.is_err(); + /// cli.room_messages(bldr).await.is_err(); /// # }) /// ``` pub fn new() -> Self { @@ -273,7 +273,7 @@ impl GetMessageBuilder { } } -impl Into for GetMessageBuilder { +impl Into for RoomMessageBuilder { fn into(self) -> get_message_events::Request { get_message_events::Request { room_id: self.room_id.expect("`room_id` and `from` need to be set"), @@ -362,7 +362,7 @@ mod test { device_id: "DEVICEID".to_owned(), }; - let mut bldr = GetMessageBuilder::new(); + let mut bldr = RoomMessageBuilder::new(); bldr.room_id(RoomId::try_from("!roomid:example.com").unwrap()) .from("t47429-4392820_219380_26003_2265".to_string()) .to("t4357353_219380_26003_2265".to_string()) @@ -372,6 +372,6 @@ mod test { // .filter(RoomEventFilter::default()); let mut cli = AsyncClient::new(homeserver, Some(session)).unwrap(); - assert!(cli.get_message_events(bldr).await.is_ok()); + assert!(cli.room_messages(bldr).await.is_ok()); } } From fb10e9bf8788db4195c8a385ab9b1ce219d7b3de Mon Sep 17 00:00:00 2001 From: Devin R Date: Mon, 13 Apr 2020 14:08:51 -0400 Subject: [PATCH 06/10] add optional txn_id to room_send, add docs to room_messages --- src/async_client.rs | 49 ++++++++++++++++++++++++------------------ src/request_builder.rs | 24 ++++++++++----------- 2 files changed, 40 insertions(+), 33 deletions(-) diff --git a/src/async_client.rs b/src/async_client.rs index 7ef25b69..13037a12 100644 --- a/src/async_client.rs +++ b/src/async_client.rs @@ -479,15 +479,15 @@ impl AsyncClient { /// ```ignore /// use matrix_sdk::{AsyncClient, RoomBuilder}; /// - /// let mut bldr = RoomBuilder::default(); - /// bldr.creation_content(false) + /// let mut builder = RoomBuilder::default(); + /// builder.creation_content(false) /// .initial_state(vec![]) /// .visibility(Visibility::Public) /// .name("name") /// .room_version("v1.0"); /// /// let mut cli = AsyncClient::new(homeserver, Some(session)).unwrap(); - /// assert!(cli.create_room(bldr).await.is_ok()); + /// assert!(cli.create_room(builder).await.is_ok()); /// ``` /// pub async fn create_room>( @@ -505,25 +505,27 @@ impl AsyncClient { /// # Arguments /// /// * request - The easiest way to create a `Request` is using the `GetMessageBuilder` + /// + /// # Examples + /// ```ignore + /// use matrix_sdk::{AsyncClient, RoomBuilder}; + /// + /// let mut builder = RoomMessageBuilder::new(); + /// builder.room_id(RoomId::try_from("!roomid:example.com").unwrap()) + /// .from("t47429-4392820_219380_26003_2265".to_string()) + /// .to("t4357353_219380_26003_2265".to_string()) + /// .direction(Direction::Backward) + /// .limit(UInt::new(10).unwrap()); + /// + /// let mut cli = AsyncClient::new(homeserver, Some(session)).unwrap(); + /// assert!(cli.create_room(builder).await.is_ok()); + /// ``` pub async fn room_messages>( &mut self, request: R, ) -> Result { let req = request.into(); - let room_id = req.room_id.clone(); - let mut res = self.send(req).await?; - let mut client = self.base_client.write().await; - // TODO should we support this event? to keep emitting these msg events this is needed - for mut event in &mut res.chunk { - client - .receive_joined_timeline_event(&room_id, &mut event) - .await; - - if let EventResult::Ok(e) = event { - client.emit_timeline_event(&room_id, e).await; - } - } - Ok(res) + self.send(req).await } /// Synchronize the client's state with the latest state on the server. @@ -827,6 +829,9 @@ impl AsyncClient { /// * `room_id` - The id of the room that should receive the message. /// /// * `content` - The content of the message event. + /// + /// * `txn_id` - A unique `Uuid` that can be attached to a `MessageEvent` held + /// in it's unsigned field as `transaction_id`. /// /// # Example /// ```no_run @@ -842,21 +847,23 @@ impl AsyncClient { /// # let homeserver = Url::parse("http://localhost:8080").unwrap(); /// # let mut client = AsyncClient::new(homeserver, None).unwrap(); /// # let room_id = RoomId::try_from("!test:localhost").unwrap(); - /// + /// use uuid::Uuid; + /// /// let content = MessageEventContent::Text(TextMessageEventContent { /// body: "Hello world".to_owned(), /// format: None, /// formatted_body: None, /// relates_to: None, /// }); - /// - /// client.room_send(&room_id, content).await.unwrap(); + /// let txn_id = Uuid::new_v4(); + /// client.room_send(&room_id, content, Some(uuid)).await.unwrap(); /// }) /// ``` pub async fn room_send( &mut self, room_id: &RoomId, #[allow(unused_mut)] mut content: MessageEventContent, + txn_id: Option, ) -> Result { #[allow(unused_mut)] let mut event_type = EventType::RoomMessage; @@ -915,7 +922,7 @@ impl AsyncClient { let request = create_message_event::Request { room_id: room_id.clone(), event_type, - txn_id: Uuid::new_v4().to_string(), + txn_id: txn_id.unwrap_or(Uuid::new_v4()).to_string(), data: content, }; diff --git a/src/request_builder.rs b/src/request_builder.rs index 9cdebe88..05b61e33 100644 --- a/src/request_builder.rs +++ b/src/request_builder.rs @@ -23,14 +23,14 @@ use js_int::UInt; /// # let homeserver = Url::parse("http://example.com").unwrap(); /// # let mut rt = tokio::runtime::Runtime::new().unwrap(); /// # rt.block_on(async { -/// let mut bldr = RoomBuilder::default(); -/// bldr.creation_content(false) +/// let mut builder = RoomBuilder::default(); +/// builder.creation_content(false) /// .initial_state(vec![]) /// .visibility(Visibility::Public) /// .name("name") /// .room_version("v1.0"); /// let mut cli = AsyncClient::new(homeserver, None).unwrap(); -/// cli.create_room(bldr).await; +/// cli.create_room(builder).await; /// # }) /// ``` #[derive(Clone, Default)] @@ -218,12 +218,12 @@ impl RoomMessageBuilder { /// # let last_sync_token = "".to_string();; /// let mut cli = AsyncClient::new(homeserver, None).unwrap(); /// - /// let mut bldr = RoomMessageBuilder::new(); - /// bldr.room_id(room_id) + /// let mut builder = RoomMessageBuilder::new(); + /// builder.room_id(room_id) /// .from(last_sync_token) /// .direction(Direction::Forward); /// - /// cli.room_messages(bldr).await.is_err(); + /// cli.room_messages(builder).await.is_err(); /// # }) /// ``` pub fn new() -> Self { @@ -314,8 +314,8 @@ mod test { device_id: "DEVICEID".to_owned(), }; - let mut bldr = RoomBuilder::new(); - bldr.creation_content(false) + let mut builder = RoomBuilder::new(); + builder.creation_content(false) .initial_state(vec![]) .visibility(Visibility::Public) .name("room_name") @@ -341,7 +341,7 @@ mod test { .topic("room topic") .visibility(Visibility::Private); let mut cli = AsyncClient::new(homeserver, Some(session)).unwrap(); - assert!(cli.create_room(bldr).await.is_ok()); + assert!(cli.create_room(builder).await.is_ok()); } #[tokio::test] @@ -362,8 +362,8 @@ mod test { device_id: "DEVICEID".to_owned(), }; - let mut bldr = RoomMessageBuilder::new(); - bldr.room_id(RoomId::try_from("!roomid:example.com").unwrap()) + let mut builder = RoomMessageBuilder::new(); + builder.room_id(RoomId::try_from("!roomid:example.com").unwrap()) .from("t47429-4392820_219380_26003_2265".to_string()) .to("t4357353_219380_26003_2265".to_string()) .direction(Direction::Backward) @@ -372,6 +372,6 @@ mod test { // .filter(RoomEventFilter::default()); let mut cli = AsyncClient::new(homeserver, Some(session)).unwrap(); - assert!(cli.room_messages(bldr).await.is_ok()); + assert!(cli.room_messages(builder).await.is_ok()); } } From 1a7856e9fe0b223db7df610234aae504bc330ef3 Mon Sep 17 00:00:00 2001 From: Devin R Date: Mon, 13 Apr 2020 14:46:54 -0400 Subject: [PATCH 07/10] fix room_send example, cargo fmt/clippy --- src/async_client.rs | 15 ++++++++------- src/request_builder.rs | 6 ++++-- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/async_client.rs b/src/async_client.rs index 13037a12..a7203347 100644 --- a/src/async_client.rs +++ b/src/async_client.rs @@ -505,18 +505,18 @@ impl AsyncClient { /// # Arguments /// /// * request - The easiest way to create a `Request` is using the `GetMessageBuilder` - /// + /// /// # Examples /// ```ignore /// use matrix_sdk::{AsyncClient, RoomBuilder}; - /// + /// /// let mut builder = RoomMessageBuilder::new(); /// builder.room_id(RoomId::try_from("!roomid:example.com").unwrap()) /// .from("t47429-4392820_219380_26003_2265".to_string()) /// .to("t4357353_219380_26003_2265".to_string()) /// .direction(Direction::Backward) /// .limit(UInt::new(10).unwrap()); - /// + /// /// let mut cli = AsyncClient::new(homeserver, Some(session)).unwrap(); /// assert!(cli.create_room(builder).await.is_ok()); /// ``` @@ -829,9 +829,10 @@ impl AsyncClient { /// * `room_id` - The id of the room that should receive the message. /// /// * `content` - The content of the message event. - /// + /// /// * `txn_id` - A unique `Uuid` that can be attached to a `MessageEvent` held - /// in it's unsigned field as `transaction_id`. + /// in it's unsigned field as `transaction_id`. If not given one is created for the + /// message. /// /// # Example /// ```no_run @@ -848,7 +849,7 @@ impl AsyncClient { /// # let mut client = AsyncClient::new(homeserver, None).unwrap(); /// # let room_id = RoomId::try_from("!test:localhost").unwrap(); /// use uuid::Uuid; - /// + /// /// let content = MessageEventContent::Text(TextMessageEventContent { /// body: "Hello world".to_owned(), /// format: None, @@ -856,7 +857,7 @@ impl AsyncClient { /// relates_to: None, /// }); /// let txn_id = Uuid::new_v4(); - /// client.room_send(&room_id, content, Some(uuid)).await.unwrap(); + /// client.room_send(&room_id, content, Some(txn_id)).await.unwrap(); /// }) /// ``` pub async fn room_send( diff --git a/src/request_builder.rs b/src/request_builder.rs index 05b61e33..edf32721 100644 --- a/src/request_builder.rs +++ b/src/request_builder.rs @@ -315,7 +315,8 @@ mod test { }; let mut builder = RoomBuilder::new(); - builder.creation_content(false) + builder + .creation_content(false) .initial_state(vec![]) .visibility(Visibility::Public) .name("room_name") @@ -363,7 +364,8 @@ mod test { }; let mut builder = RoomMessageBuilder::new(); - builder.room_id(RoomId::try_from("!roomid:example.com").unwrap()) + builder + .room_id(RoomId::try_from("!roomid:example.com").unwrap()) .from("t47429-4392820_219380_26003_2265".to_string()) .to("t4357353_219380_26003_2265".to_string()) .direction(Direction::Backward) From e64d07340275e238ba099fd9f9701909f4d4f196 Mon Sep 17 00:00:00 2001 From: Devin R Date: Tue, 14 Apr 2020 06:36:03 -0400 Subject: [PATCH 08/10] rename RoomMessageBuilder, make examp build, expand on docs --- src/async_client.rs | 76 +++++++++++++++++++++++++----------------- src/lib.rs | 2 +- src/request_builder.rs | 54 +++++++++++++++--------------- 3 files changed, 74 insertions(+), 58 deletions(-) diff --git a/src/async_client.rs b/src/async_client.rs index a7203347..547009ae 100644 --- a/src/async_client.rs +++ b/src/async_client.rs @@ -350,8 +350,7 @@ impl AsyncClient { /// /// # Arguments /// - /// * room_id - A valid RoomId otherwise sending will fail. - /// + /// * room_id - The `RoomId` of the room to be joined. pub async fn join_room_by_id(&mut self, room_id: &RoomId) -> Result { let request = join_room_by_id::Request { room_id: room_id.clone(), @@ -367,8 +366,8 @@ impl AsyncClient { /// /// # Arguments /// - /// * alias - A valid `RoomIdOrAliasId` otherwise sending will fail. - /// + /// * alias - The `RoomId` or `RoomAliasId` of the room to be joined. + /// An alias looks like this `#name:example.com` pub async fn join_room_by_id_or_alias( &mut self, alias: &RoomIdOrAliasId, @@ -386,12 +385,11 @@ impl AsyncClient { /// /// # Arguments /// - /// * room_id - A valid `RoomId` otherwise sending will fail. + /// * room_id - The `RoomId` of the room the user should be kicked out of. /// - /// * user_id - A valid `UserId`. + /// * user_id - The `UserId` of the user that should be kicked out of the room. /// /// * reason - Optional reason why the room member is being kicked out. - /// pub async fn kick_user( &mut self, room_id: &RoomId, @@ -412,7 +410,7 @@ impl AsyncClient { /// /// # Arguments /// - /// * room_id - A valid `RoomId`. + /// * room_id - The `RoomId` of the room to leave. /// pub async fn leave_room(&mut self, room_id: &RoomId) -> Result { let request = leave_room::Request { @@ -427,10 +425,9 @@ impl AsyncClient { /// /// # Arguments /// - /// * room_id - A valid `RoomId`. - /// - /// * user_id - A valid `UserId`. + /// * room_id - The `RoomId` of the room to invite the specified user to. /// + /// * user_id - The `UserId` of the user to invite to the room. pub async fn invite_user_by_id( &mut self, room_id: &RoomId, @@ -451,10 +448,9 @@ impl AsyncClient { /// /// # Arguments /// - /// * room_id - A valid `RoomId`. - /// - /// * invite_id - A valid `UserId`. + /// * room_id - The `RoomId` of the room to invite the specified user to. /// + /// * invite_id - A third party id of a user to invite to the room. pub async fn invite_user_by_3pid( &mut self, room_id: &RoomId, @@ -467,18 +463,22 @@ impl AsyncClient { self.send(request).await } - /// A builder to create a room and send the request. + /// Create a room using the `RoomBuilder` and send the request. /// - /// Returns a `create_room::Response`, an empty response. + /// Sends a request to `/_matrix/client/r0/createRoom`, returns a `create_room::Response`, + /// this is an empty response. /// /// # Arguments /// - /// * room - the easiest way to create this request is using the `RoomBuilder`. + /// * room - The easiest way to create this request is using the `RoomBuilder`. /// /// # Examples - /// ```ignore + /// ```no_run /// use matrix_sdk::{AsyncClient, RoomBuilder}; - /// + /// # use matrix_sdk::api::r0::room::Visibility; + /// # use url::Url; + /// + /// # let homeserver = Url::parse("http://example.com").unwrap(); /// let mut builder = RoomBuilder::default(); /// builder.creation_content(false) /// .initial_state(vec![]) @@ -486,10 +486,12 @@ impl AsyncClient { /// .name("name") /// .room_version("v1.0"); /// - /// let mut cli = AsyncClient::new(homeserver, Some(session)).unwrap(); + /// let mut cli = AsyncClient::new(homeserver, None).unwrap(); + /// # use futures::executor::block_on; + /// # block_on(async { /// assert!(cli.create_room(builder).await.is_ok()); + /// # }); /// ``` - /// pub async fn create_room>( &mut self, room: R, @@ -498,27 +500,41 @@ impl AsyncClient { self.send(request).await } - /// Invite the specified user by third party id to the given room. + /// Get messages starting at a specific sync point using the + /// `MessagesRequestBuilder`s `from` field as a starting point. /// - /// Returns a `invite_user::Response`, an empty response. + /// Sends a request to `/_matrix/client/r0/rooms/{room_id}/messages` and + /// returns a `get_message_events::IncomingResponse` that contains chunks + /// of `RoomEvents`. /// /// # Arguments /// - /// * request - The easiest way to create a `Request` is using the `GetMessageBuilder` + /// * request - The easiest way to create a `Request` is using the + /// `MessagesRequestBuilder`. /// /// # Examples - /// ```ignore - /// use matrix_sdk::{AsyncClient, RoomBuilder}; - /// - /// let mut builder = RoomMessageBuilder::new(); + /// ```no_run + /// # use std::convert::TryFrom; + /// use matrix_sdk::{AsyncClient, MessagesRequestBuilder}; + /// # use matrix_sdk::identifiers::RoomId; + /// # use matrix_sdk::api::r0::filter::RoomEventFilter; + /// # use matrix_sdk::api::r0::message::get_message_events::Direction; + /// # use url::Url; + /// # use js_int::UInt; + /// + /// # let homeserver = Url::parse("http://example.com").unwrap(); + /// let mut builder = MessagesRequestBuilder::new(); /// builder.room_id(RoomId::try_from("!roomid:example.com").unwrap()) /// .from("t47429-4392820_219380_26003_2265".to_string()) /// .to("t4357353_219380_26003_2265".to_string()) /// .direction(Direction::Backward) /// .limit(UInt::new(10).unwrap()); /// - /// let mut cli = AsyncClient::new(homeserver, Some(session)).unwrap(); - /// assert!(cli.create_room(builder).await.is_ok()); + /// let mut cli = AsyncClient::new(homeserver, None).unwrap(); + /// # use futures::executor::block_on; + /// # block_on(async { + /// assert!(cli.room_messages(builder).await.is_ok()); + /// # }); /// ``` pub async fn room_messages>( &mut self, diff --git a/src/lib.rs b/src/lib.rs index 0e00b83e..de536d50 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,6 +51,6 @@ pub use async_client::{AsyncClient, AsyncClientConfig, SyncSettings}; pub use base_client::Client; pub use event_emitter::EventEmitter; pub use models::Room; -pub use request_builder::{RoomBuilder, RoomMessageBuilder}; +pub use request_builder::{RoomBuilder, MessagesRequestBuilder}; pub(crate) const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/src/request_builder.rs b/src/request_builder.rs index edf32721..42f088f5 100644 --- a/src/request_builder.rs +++ b/src/request_builder.rs @@ -174,8 +174,30 @@ impl Into for RoomBuilder { } /// Create a builder for making get_message_event requests. +/// +/// # Examples +/// ``` +/// # use matrix_sdk::{AsyncClient, MessagesRequestBuilder}; +/// # use matrix_sdk::api::r0::message::get_message_events::{self, Direction}; +/// # use matrix_sdk::identifiers::RoomId; +/// # use url::Url; +/// # let homeserver = Url::parse("http://example.com").unwrap(); +/// # let mut rt = tokio::runtime::Runtime::new().unwrap(); +/// # rt.block_on(async { +/// # let room_id = RoomId::new(homeserver.as_str()).unwrap(); +/// # let last_sync_token = "".to_string();; +/// let mut cli = AsyncClient::new(homeserver, None).unwrap(); +/// +/// let mut builder = MessagesRequestBuilder::new(); +/// builder.room_id(room_id) +/// .from(last_sync_token) +/// .direction(Direction::Forward); +/// +/// cli.room_messages(builder).await.is_err(); +/// # }) +/// ``` #[derive(Clone, Default)] -pub struct RoomMessageBuilder { +pub struct MessagesRequestBuilder { /// The room to get events from. room_id: Option, /// The token to start returning events from. @@ -200,32 +222,10 @@ pub struct RoomMessageBuilder { filter: Option, } -impl RoomMessageBuilder { - /// Create a `RoomMessageBuilder` builder to make a `get_message_events::Request`. +impl MessagesRequestBuilder { + /// Create a `MessagesRequestBuilder` builder to make a `get_message_events::Request`. /// /// The `room_id` and `from`` fields **need to be set** to create the request. - /// - /// # Examples - /// ``` - /// # use matrix_sdk::{AsyncClient, RoomMessageBuilder}; - /// # use matrix_sdk::api::r0::message::get_message_events::{self, Direction}; - /// # use matrix_sdk::identifiers::RoomId; - /// # use url::Url; - /// # let homeserver = Url::parse("http://example.com").unwrap(); - /// # let mut rt = tokio::runtime::Runtime::new().unwrap(); - /// # rt.block_on(async { - /// # let room_id = RoomId::new(homeserver.as_str()).unwrap(); - /// # let last_sync_token = "".to_string();; - /// let mut cli = AsyncClient::new(homeserver, None).unwrap(); - /// - /// let mut builder = RoomMessageBuilder::new(); - /// builder.room_id(room_id) - /// .from(last_sync_token) - /// .direction(Direction::Forward); - /// - /// cli.room_messages(builder).await.is_err(); - /// # }) - /// ``` pub fn new() -> Self { Self::default() } @@ -273,7 +273,7 @@ impl RoomMessageBuilder { } } -impl Into for RoomMessageBuilder { +impl Into for MessagesRequestBuilder { fn into(self) -> get_message_events::Request { get_message_events::Request { room_id: self.room_id.expect("`room_id` and `from` need to be set"), @@ -363,7 +363,7 @@ mod test { device_id: "DEVICEID".to_owned(), }; - let mut builder = RoomMessageBuilder::new(); + let mut builder = MessagesRequestBuilder::new(); builder .room_id(RoomId::try_from("!roomid:example.com").unwrap()) .from("t47429-4392820_219380_26003_2265".to_string()) From 2cfaf64febf9acfb34c8c8564eed12d46266c183 Mon Sep 17 00:00:00 2001 From: Devin R Date: Tue, 14 Apr 2020 06:42:42 -0400 Subject: [PATCH 09/10] cargo fmt/clippy --- src/async_client.rs | 8 ++++---- src/lib.rs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/async_client.rs b/src/async_client.rs index 547009ae..718e423b 100644 --- a/src/async_client.rs +++ b/src/async_client.rs @@ -477,7 +477,7 @@ impl AsyncClient { /// use matrix_sdk::{AsyncClient, RoomBuilder}; /// # use matrix_sdk::api::r0::room::Visibility; /// # use url::Url; - /// + /// /// # let homeserver = Url::parse("http://example.com").unwrap(); /// let mut builder = RoomBuilder::default(); /// builder.creation_content(false) @@ -509,7 +509,7 @@ impl AsyncClient { /// /// # Arguments /// - /// * request - The easiest way to create a `Request` is using the + /// * request - The easiest way to create a `Request` is using the /// `MessagesRequestBuilder`. /// /// # Examples @@ -521,7 +521,7 @@ impl AsyncClient { /// # use matrix_sdk::api::r0::message::get_message_events::Direction; /// # use url::Url; /// # use js_int::UInt; - /// + /// /// # let homeserver = Url::parse("http://example.com").unwrap(); /// let mut builder = MessagesRequestBuilder::new(); /// builder.room_id(RoomId::try_from("!roomid:example.com").unwrap()) @@ -939,7 +939,7 @@ impl AsyncClient { let request = create_message_event::Request { room_id: room_id.clone(), event_type, - txn_id: txn_id.unwrap_or(Uuid::new_v4()).to_string(), + txn_id: txn_id.unwrap_or_else(Uuid::new_v4).to_string(), data: content, }; diff --git a/src/lib.rs b/src/lib.rs index de536d50..b3c13bdb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -51,6 +51,6 @@ pub use async_client::{AsyncClient, AsyncClientConfig, SyncSettings}; pub use base_client::Client; pub use event_emitter::EventEmitter; pub use models::Room; -pub use request_builder::{RoomBuilder, MessagesRequestBuilder}; +pub use request_builder::{MessagesRequestBuilder, RoomBuilder}; pub(crate) const VERSION: &str = env!("CARGO_PKG_VERSION"); From f857fbb25bdefa7597ab27e48b8e483da9ef8f4b Mon Sep 17 00:00:00 2001 From: Devin R Date: Tue, 14 Apr 2020 07:19:58 -0400 Subject: [PATCH 10/10] remove unused sync2 json, pre-commit all files --- design.md | 2 +- tests/data/events/room_avatar.json | 1 - tests/data/sync2.json | 160 ----------------------------- 3 files changed, 1 insertion(+), 162 deletions(-) delete mode 100644 tests/data/sync2.json diff --git a/design.md b/design.md index 8b974294..2686f513 100644 --- a/design.md +++ b/design.md @@ -3,7 +3,7 @@ ## Design and Layout #### Async Client -The highest level structure that ties the other pieces of functionality together. The client is responsible for the Request/Response cycle. It can be thought of as a thin layer atop the `BaseClient` passing requests along for the `BaseClient` to handle. A user should be able to write their own `AsyncClient` using the `BaseClient`. It knows how to +The highest level structure that ties the other pieces of functionality together. The client is responsible for the Request/Response cycle. It can be thought of as a thin layer atop the `BaseClient` passing requests along for the `BaseClient` to handle. A user should be able to write their own `AsyncClient` using the `BaseClient`. It knows how to - login - send messages - encryption ... diff --git a/tests/data/events/room_avatar.json b/tests/data/events/room_avatar.json index b92f9161..92ed2519 100644 --- a/tests/data/events/room_avatar.json +++ b/tests/data/events/room_avatar.json @@ -18,4 +18,3 @@ "age": 1234 } } - diff --git a/tests/data/sync2.json b/tests/data/sync2.json deleted file mode 100644 index 6adb2c13..00000000 --- a/tests/data/sync2.json +++ /dev/null @@ -1,160 +0,0 @@ -{ - "next_batch": "s72595_4483_1934", - "presence": { - "events": [ - { - "content": { - "avatar_url": "mxc://localhost:wefuiwegh8742w", - "last_active_ago": 2478593, - "presence": "online", - "currently_active": false, - "status_msg": "Making cupcakes" - }, - "type": "m.presence", - "sender": "@example:localhost" - } - ] - }, - "account_data": { - "events": [ - { - "type": "org.example.custom.config", - "content": { - "custom_config_key": "custom_config_value" - } - } - ] - }, - "rooms": { - "join": { - "!726s6s6q:example.com": { - "summary": { - "m.heroes": [ - "@alice:example.com", - "@bob:example.com" - ], - "m.joined_member_count": 2, - "m.invited_member_count": 0 - }, - "state": { - "events": [ - { - "content": { - "membership": "join", - "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF", - "displayname": "Alice Margatroid" - }, - "type": "m.room.member", - "event_id": "$143273582443PhrSn:example.org", - "room_id": "!726s6s6q:example.com", - "sender": "@example:example.org", - "origin_server_ts": 1432735824653, - "unsigned": { - "age": 1234 - }, - "state_key": "@alice:example.org" - } - ] - }, - "timeline": { - "events": [ - { - "content": { - "membership": "join", - "avatar_url": "mxc://example.org/SEsfnsuifSDFSSEF", - "displayname": "Alice Margatroid" - }, - "type": "m.room.member", - "event_id": "$143273582443PhrSn:example.org", - "room_id": "!726s6s6q:example.com", - "sender": "@example:example.org", - "origin_server_ts": 1432735824653, - "unsigned": { - "age": 1234 - }, - "state_key": "@alice:example.org" - }, - { - "content": { - "body": "This is an example text message", - "msgtype": "m.text", - "format": "org.matrix.custom.html", - "formatted_body": "This is an example text message" - }, - "type": "m.room.message", - "event_id": "$143273582443PhrSn:example.org", - "room_id": "!726s6s6q:example.com", - "sender": "@example:example.org", - "origin_server_ts": 1432735824653, - "unsigned": { - "age": 1234 - } - } - ], - "limited": true, - "prev_batch": "t34-23535_0_0" - }, - "ephemeral": { - "events": [ - { - "content": { - "user_ids": [ - "@alice:matrix.org", - "@bob:example.com" - ] - }, - "type": "m.typing", - "room_id": "!jEsUZKDJdhlrceRyVU:example.org" - } - ] - }, - "account_data": { - "events": [ - { - "content": { - "tags": { - "u.work": { - "order": 0.9 - } - } - }, - "type": "m.tag" - }, - { - "type": "org.example.custom.room.config", - "content": { - "custom_config_key": "custom_config_value" - } - } - ] - } - } - }, - "invite": { - "!696r7674:example.com": { - "invite_state": { - "events": [ - { - "sender": "@alice:example.com", - "type": "m.room.name", - "state_key": "", - "content": { - "name": "My Room Name" - } - }, - { - "sender": "@alice:example.com", - "type": "m.room.member", - "state_key": "@bob:example.com", - "content": { - "membership": "invite" - } - } - ] - } - } - }, - "leave": {} - } - } - \ No newline at end of file