From e734de5d442c581c37e38dc1733c9f125c8e98aa Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sun, 9 Jul 2017 18:53:33 +1000 Subject: [PATCH 01/15] Implement Client::register_guest --- src/lib.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index bae4d650..7536af7a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -118,6 +118,26 @@ where }) } + /// Register as a guest. In contrast to api::r0::account::register::call(), + /// this method stores the session data returned by the endpoint in this + /// client, instead of returning it. + pub fn register_guest<'a>(&'a self) -> impl Future + 'a { + use api::r0::account::register; + + register::call(self, register::Request { + auth: None, + bind_email: None, + device_id: None, + initial_device_display_name: None, + kind: Some(register::RegistrationKind::Guest), + password: None, + username: None, + }).map(move |response| { + *self.session.borrow_mut() = + Some(Session::new(response.access_token, response.user_id)); + }) + } + /// Makes a request to a Matrix API endpoint. pub(crate) fn request<'a, E>( &'a self, From 61d848d2b5326a7e85311a84c31d8b247724e60d Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sun, 9 Jul 2017 20:30:28 +1000 Subject: [PATCH 02/15] Add hello_world example --- Cargo.toml | 3 +++ examples/hello_world.rs | 58 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 61 insertions(+) create mode 100644 examples/hello_world.rs diff --git a/Cargo.toml b/Cargo.toml index 9f1a1619..1e8c3a2a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,9 @@ version = "0.1.2" optional = true version = "0.1.4" +[dev-dependencies] +ruma-events = "0.9.0" + [features] default = ["tls"] tls = ["hyper-tls", "native-tls"] diff --git a/examples/hello_world.rs b/examples/hello_world.rs new file mode 100644 index 00000000..16149c20 --- /dev/null +++ b/examples/hello_world.rs @@ -0,0 +1,58 @@ +#![feature(conservative_impl_trait)] +#![feature(try_from)] + +extern crate futures; +extern crate hyper; +extern crate ruma_client; +extern crate ruma_events; +extern crate ruma_identifiers; +extern crate tokio_core; +extern crate url; + +use std::convert::TryFrom; + +use futures::Future; +use hyper::client::Connect; +use ruma_client::Client; +use ruma_client::api::r0; +use ruma_events::EventType; +use ruma_events::room::message::{MessageEventContent, MessageType, TextMessageEventContent}; +use ruma_identifiers::RoomAliasId; +use tokio_core::reactor::Core; +use url::Url; + +fn hello_world<'a, C: Connect>(client: &'a Client) +-> impl Future + 'a +{ + client.register_guest().and_then(move |_| { + r0::alias::get_alias::call(client, r0::alias::get_alias::Request { + room_alias: RoomAliasId::try_from("#ruma-client-test:matrix.org").unwrap(), + }) + }).and_then(move |response| { + let room_id = response.room_id; + + r0::membership::join_room_by_id::call(client, r0::membership::join_room_by_id::Request { + room_id: room_id.clone(), + third_party_signed: None, + }).and_then(move |_| { + r0::send::send_message_event::call(client, r0::send::send_message_event::Request { + room_id: room_id, + event_type: EventType::RoomMessage, + txn_id: "1".to_owned(), + data: MessageEventContent::Text(TextMessageEventContent { + body: "Hello World!".to_owned(), + msgtype: MessageType::Text, + }), + }) + }) + }).map(|_| ()) +} + +fn main() { + let mut core = Core::new().unwrap(); + let handle = core.handle(); + let server = Url::parse("https://matrix.org/").unwrap(); + + let client = Client::https(&handle, server, None).unwrap(); + core.run(hello_world(&client)).unwrap(); +} From fcd698561864455a4ac4011dde46a08bb031831a Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sun, 9 Jul 2017 21:46:45 +1000 Subject: [PATCH 03/15] Add more detailed documentation for Client::log_in --- src/lib.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 7536af7a..a49d0969 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -100,7 +100,11 @@ where } } - /// Log in to the homeserver with a username and password. + /// Log in with a username and password. + /// + /// In contrast to api::r0::session::login::call(), this method stores the + /// session data returned by the endpoint in this client, instead of + /// returning it. pub fn log_in<'a>(&'a self, user: String, password: String) -> impl Future + 'a { let request = login::Request { From ceca663d6977f10a7e816c3ab73487bfa6a1b7a9 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sun, 9 Jul 2017 21:47:01 +1000 Subject: [PATCH 04/15] Implement Client::register_user --- src/lib.rs | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index a49d0969..587f5ff3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -142,6 +142,35 @@ where }) } + /// Register as a new user on this server. + /// + /// In contrast to api::r0::account::register::call(), this method stores + /// the session data returned by the endpoint in this client, instead of + /// returning it. + /// + /// The username is the local part of the returned user_id. If it is + /// omitted from this request, the server will generate one. + pub fn register_user<'a>( + &'a self, + username: Option, + password: String, + ) -> impl Future + 'a { + use api::r0::account::register; + + register::call(self, register::Request { + auth: None, + bind_email: None, + device_id: None, + initial_device_display_name: None, + kind: Some(register::RegistrationKind::User), + password: Some(password), + username: username, + }).map(move |response| { + *self.session.borrow_mut() = + Some(Session::new(response.access_token, response.user_id)); + }) + } + /// Makes a request to a Matrix API endpoint. pub(crate) fn request<'a, E>( &'a self, From 3dae62ec253f2a85b7f411cff14b4be70b48d16e Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Wed, 12 Jul 2017 03:25:00 +1000 Subject: [PATCH 05/15] Remove Client lifetime from Futures by using Rc and clones --- examples/hello_world.rs | 52 ++++++++++++++++++--------- src/api.rs | 6 ++-- src/lib.rs | 78 ++++++++++++++++++++++++----------------- 3 files changed, 85 insertions(+), 51 deletions(-) diff --git a/examples/hello_world.rs b/examples/hello_world.rs index 16149c20..7f8d43eb 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -12,30 +12,51 @@ extern crate url; use std::convert::TryFrom; use futures::Future; -use hyper::client::Connect; use ruma_client::Client; use ruma_client::api::r0; use ruma_events::EventType; use ruma_events::room::message::{MessageEventContent, MessageType, TextMessageEventContent}; use ruma_identifiers::RoomAliasId; -use tokio_core::reactor::Core; +use tokio_core::reactor::{Core as TokioCore, Handle as TokioHandle}; use url::Url; -fn hello_world<'a, C: Connect>(client: &'a Client) --> impl Future + 'a -{ - client.register_guest().and_then(move |_| { - r0::alias::get_alias::call(client, r0::alias::get_alias::Request { +// from https://stackoverflow.com/a/43992218/1592377 +#[macro_export] +macro_rules! clone { + (@param _) => ( _ ); + (@param $x:ident) => ( $x ); + ($($n:ident),+ => move || $body:expr) => ( + { + $( let $n = $n.clone(); )+ + move || $body + } + ); + ($($n:ident),+ => move |$($p:tt),+| $body:expr) => ( + { + $( let $n = $n.clone(); )+ + move |$(clone!(@param $p),)+| $body + } + ); +} + +fn hello_world( + tokio_handle: TokioHandle, + homeserver_url: Url, +) -> impl Future + 'static { + let client = Client::https(&tokio_handle, homeserver_url, None).unwrap(); + + client.register_guest().and_then(clone!(client => move |_| { + r0::alias::get_alias::call(client.clone(), r0::alias::get_alias::Request { room_alias: RoomAliasId::try_from("#ruma-client-test:matrix.org").unwrap(), }) - }).and_then(move |response| { + })).and_then(clone!(client => move |response| { let room_id = response.room_id; - r0::membership::join_room_by_id::call(client, r0::membership::join_room_by_id::Request { + r0::membership::join_room_by_id::call(client.clone(), r0::membership::join_room_by_id::Request { room_id: room_id.clone(), third_party_signed: None, - }).and_then(move |_| { - r0::send::send_message_event::call(client, r0::send::send_message_event::Request { + }).and_then(clone!(client => move |_| { + r0::send::send_message_event::call(client.clone(), r0::send::send_message_event::Request { room_id: room_id, event_type: EventType::RoomMessage, txn_id: "1".to_owned(), @@ -44,15 +65,14 @@ fn hello_world<'a, C: Connect>(client: &'a Client) msgtype: MessageType::Text, }), }) - }) - }).map(|_| ()) + })) + })).map(|_| ()) } fn main() { - let mut core = Core::new().unwrap(); + let mut core = TokioCore::new().unwrap(); let handle = core.handle(); let server = Url::parse("https://matrix.org/").unwrap(); - let client = Client::https(&handle, server, None).unwrap(); - core.run(hello_world(&client)).unwrap(); + core.run(hello_world(handle, server)).unwrap(); } diff --git a/src/api.rs b/src/api.rs index 4049e448..2983a307 100644 --- a/src/api.rs +++ b/src/api.rs @@ -32,10 +32,10 @@ macro_rules! endpoint { use {Client, Error}; /// Make a request to this API endpoint. - pub fn call<'a, C>( - client: &'a Client, + pub fn call( + client: Client, request: Request, - ) -> impl Future + 'a + ) -> impl Future where C: Connect, { diff --git a/src/lib.rs b/src/lib.rs index 587f5ff3..a33e0b27 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,23 +45,23 @@ mod error; mod session; /// A client for the Matrix client-server API. -#[derive(Clone, Debug)] +#[derive(Debug)] pub struct Client where C: Connect, { - homeserver_url: Url, + homeserver_url: Rc, hyper: Rc>, - session: RefCell>, + session: Rc>>, } impl Client { /// Creates a new client for making HTTP requests to the given homeserver. pub fn new(handle: &Handle, homeserver_url: Url, session: Option) -> Self { Client { - homeserver_url, + homeserver_url: Rc::new(homeserver_url), hyper: Rc::new(HyperClient::configure().keep_alive(true).build(handle)), - session: RefCell::new(session), + session: Rc::new(RefCell::new(session)), } } } @@ -73,14 +73,14 @@ impl Client> { let connector = HttpsConnector::new(4, handle)?; Ok(Client { - homeserver_url, + homeserver_url: Rc::new(homeserver_url), hyper: Rc::new( HyperClient::configure() .connector(connector) .keep_alive(true) .build(handle), ), - session: RefCell::new(session), + session: Rc::new(RefCell::new(session)), }) } } @@ -94,9 +94,9 @@ where /// This allows the user to configure the details of HTTP as desired. pub fn custom(hyper_client: HyperClient, homeserver_url: Url, session: Option) -> Self { Client { - homeserver_url, + homeserver_url: Rc::new(homeserver_url), hyper: Rc::new(hyper_client), - session: RefCell::new(session), + session: Rc::new(RefCell::new(session)), } } @@ -105,8 +105,8 @@ where /// In contrast to api::r0::session::login::call(), this method stores the /// session data returned by the endpoint in this client, instead of /// returning it. - pub fn log_in<'a>(&'a self, user: String, password: String) - -> impl Future + 'a { + pub fn log_in(&self, user: String, password: String) + -> impl Future { let request = login::Request { address: None, login_type: login::LoginType::Password, @@ -115,8 +115,10 @@ where user, }; - login::call(self, request).and_then(move |response| { - *self.session.borrow_mut() = Some(Session::new(response.access_token, response.user_id)); + let session = self.session.clone(); + + login::call(self.clone(), request).and_then(move |response| { + *session.borrow_mut() = Some(Session::new(response.access_token, response.user_id)); Ok(()) }) @@ -125,10 +127,12 @@ where /// Register as a guest. In contrast to api::r0::account::register::call(), /// this method stores the session data returned by the endpoint in this /// client, instead of returning it. - pub fn register_guest<'a>(&'a self) -> impl Future + 'a { + pub fn register_guest(&self) -> impl Future { use api::r0::account::register; - register::call(self, register::Request { + let session = self.session.clone(); + + register::call(self.clone(), register::Request { auth: None, bind_email: None, device_id: None, @@ -137,8 +141,7 @@ where password: None, username: None, }).map(move |response| { - *self.session.borrow_mut() = - Some(Session::new(response.access_token, response.user_id)); + *session.borrow_mut() = Some(Session::new(response.access_token, response.user_id)); }) } @@ -150,14 +153,16 @@ where /// /// The username is the local part of the returned user_id. If it is /// omitted from this request, the server will generate one. - pub fn register_user<'a>( - &'a self, + pub fn register_user( + &self, username: Option, password: String, - ) -> impl Future + 'a { + ) -> impl Future { use api::r0::account::register; - register::call(self, register::Request { + let session = self.session.clone(); + + register::call(self.clone(), register::Request { auth: None, bind_email: None, device_id: None, @@ -166,21 +171,21 @@ where password: Some(password), username: username, }).map(move |response| { - *self.session.borrow_mut() = - Some(Session::new(response.access_token, response.user_id)); + *session.borrow_mut() = Some(Session::new(response.access_token, response.user_id)); }) } /// Makes a request to a Matrix API endpoint. - pub(crate) fn request<'a, E>( - &'a self, + pub(crate) fn request( + self, request: ::Request, - ) -> impl Future + 'a + ) -> impl Future where E: Endpoint, - ::Response: 'a, { - let mut url = self.homeserver_url.clone(); + let mut url = (*self.homeserver_url).clone(); + let hyper = self.hyper; + let session = self.session; request .try_into() @@ -194,7 +199,7 @@ where url.set_query(uri.query()); if E::METADATA.requires_authentication { - if let Some(ref session) = *self.session.borrow() { + if let Some(ref session) = *session.borrow() { url.query_pairs_mut().append_pair("access_token", session.access_token()); } else { return Err(Error::AuthenticationRequired); @@ -202,15 +207,14 @@ where } } - Uri::from_str(url.as_ref()) + Uri::from_str(url.as_ref().as_ref()) .map(move |uri| (uri, hyper_request)) .map_err(Error::from) }) .and_then(move |(uri, mut hyper_request)| { hyper_request.set_uri(uri); - self.hyper - .clone() + hyper .request(hyper_request) .map_err(Error::from) }) @@ -219,3 +223,13 @@ where }) } } + +impl Clone for Client { + fn clone(&self) -> Client { + Client { + homeserver_url: self.homeserver_url.clone(), + hyper: self.hyper.clone(), + session: self.session.clone(), + } + } +} From 002745fb2f37506f8cd4c0218ca96438aa894955 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Wed, 12 Jul 2017 17:58:32 +1000 Subject: [PATCH 06/15] Remove a few unnecessary clones in hello_worl example --- examples/hello_world.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/hello_world.rs b/examples/hello_world.rs index 7f8d43eb..a8d55858 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -46,7 +46,7 @@ fn hello_world( let client = Client::https(&tokio_handle, homeserver_url, None).unwrap(); client.register_guest().and_then(clone!(client => move |_| { - r0::alias::get_alias::call(client.clone(), r0::alias::get_alias::Request { + r0::alias::get_alias::call(client, r0::alias::get_alias::Request { room_alias: RoomAliasId::try_from("#ruma-client-test:matrix.org").unwrap(), }) })).and_then(clone!(client => move |response| { @@ -55,8 +55,8 @@ fn hello_world( r0::membership::join_room_by_id::call(client.clone(), r0::membership::join_room_by_id::Request { room_id: room_id.clone(), third_party_signed: None, - }).and_then(clone!(client => move |_| { - r0::send::send_message_event::call(client.clone(), r0::send::send_message_event::Request { + }).and_then(move |_| { + r0::send::send_message_event::call(client, r0::send::send_message_event::Request { room_id: room_id, event_type: EventType::RoomMessage, txn_id: "1".to_owned(), @@ -65,7 +65,7 @@ fn hello_world( msgtype: MessageType::Text, }), }) - })) + }) })).map(|_| ()) } From 8759d5c864ffe287bc5e098c45bf6cce5d27dd9c Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 13 Jul 2017 15:13:36 +1000 Subject: [PATCH 07/15] Refactor Client: use one Rc instead of three --- src/lib.rs | 90 +++++++++++++++++++++++++++--------------------------- 1 file changed, 45 insertions(+), 45 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a33e0b27..72eefd2e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,7 +35,6 @@ use ruma_api::Endpoint; use tokio_core::reactor::Handle; use url::Url; -use api::r0::session::login; pub use error::Error; pub use session::Session; @@ -46,23 +45,27 @@ mod session; /// A client for the Matrix client-server API. #[derive(Debug)] -pub struct Client +pub struct Client(Rc>); + +/// Data contained in Client's Rc +#[derive(Debug)] +pub struct ClientData where C: Connect, { - homeserver_url: Rc, - hyper: Rc>, - session: Rc>>, + homeserver_url: Url, + hyper: HyperClient, + session: RefCell>, } impl Client { /// Creates a new client for making HTTP requests to the given homeserver. pub fn new(handle: &Handle, homeserver_url: Url, session: Option) -> Self { - Client { - homeserver_url: Rc::new(homeserver_url), - hyper: Rc::new(HyperClient::configure().keep_alive(true).build(handle)), - session: Rc::new(RefCell::new(session)), - } + Client(Rc::new(ClientData { + homeserver_url: homeserver_url, + hyper: HyperClient::configure().keep_alive(true).build(handle), + session: RefCell::new(session), + })) } } @@ -72,16 +75,16 @@ impl Client> { pub fn https(handle: &Handle, homeserver_url: Url, session: Option) -> Result { let connector = HttpsConnector::new(4, handle)?; - Ok(Client { - homeserver_url: Rc::new(homeserver_url), - hyper: Rc::new( + Ok(Client(Rc::new(ClientData { + homeserver_url: homeserver_url, + hyper: { HyperClient::configure() .connector(connector) .keep_alive(true) - .build(handle), - ), - session: Rc::new(RefCell::new(session)), - }) + .build(handle) + }, + session: RefCell::new(session), + }))) } } @@ -93,11 +96,11 @@ where /// /// This allows the user to configure the details of HTTP as desired. pub fn custom(hyper_client: HyperClient, homeserver_url: Url, session: Option) -> Self { - Client { - homeserver_url: Rc::new(homeserver_url), - hyper: Rc::new(hyper_client), - session: Rc::new(RefCell::new(session)), - } + Client(Rc::new(ClientData { + homeserver_url: homeserver_url, + hyper: hyper_client, + session: RefCell::new(session), + })) } /// Log in with a username and password. @@ -107,20 +110,19 @@ where /// returning it. pub fn log_in(&self, user: String, password: String) -> impl Future { - let request = login::Request { + use api::r0::session::login; + + let data = self.0.clone(); + + login::call(self.clone(), login::Request { address: None, login_type: login::LoginType::Password, medium: None, password, user, - }; - - let session = self.session.clone(); - - login::call(self.clone(), request).and_then(move |response| { - *session.borrow_mut() = Some(Session::new(response.access_token, response.user_id)); - - Ok(()) + }).map(move |response| { + *data.session.borrow_mut() = + Some(Session::new(response.access_token, response.user_id)); }) } @@ -130,7 +132,7 @@ where pub fn register_guest(&self) -> impl Future { use api::r0::account::register; - let session = self.session.clone(); + let data = self.0.clone(); register::call(self.clone(), register::Request { auth: None, @@ -141,7 +143,8 @@ where password: None, username: None, }).map(move |response| { - *session.borrow_mut() = Some(Session::new(response.access_token, response.user_id)); + *data.session.borrow_mut() = + Some(Session::new(response.access_token, response.user_id)); }) } @@ -160,7 +163,7 @@ where ) -> impl Future { use api::r0::account::register; - let session = self.session.clone(); + let data = self.0.clone(); register::call(self.clone(), register::Request { auth: None, @@ -171,7 +174,8 @@ where password: Some(password), username: username, }).map(move |response| { - *session.borrow_mut() = Some(Session::new(response.access_token, response.user_id)); + *data.session.borrow_mut() = + Some(Session::new(response.access_token, response.user_id)); }) } @@ -183,9 +187,9 @@ where where E: Endpoint, { - let mut url = (*self.homeserver_url).clone(); - let hyper = self.hyper; - let session = self.session; + let data1 = self.0.clone(); + let data2 = self.0.clone(); + let mut url = self.0.homeserver_url.clone(); request .try_into() @@ -199,7 +203,7 @@ where url.set_query(uri.query()); if E::METADATA.requires_authentication { - if let Some(ref session) = *session.borrow() { + if let Some(ref session) = *data1.session.borrow() { url.query_pairs_mut().append_pair("access_token", session.access_token()); } else { return Err(Error::AuthenticationRequired); @@ -214,7 +218,7 @@ where .and_then(move |(uri, mut hyper_request)| { hyper_request.set_uri(uri); - hyper + data2.hyper .request(hyper_request) .map_err(Error::from) }) @@ -226,10 +230,6 @@ where impl Clone for Client { fn clone(&self) -> Client { - Client { - homeserver_url: self.homeserver_url.clone(), - hyper: self.hyper.clone(), - session: self.session.clone(), - } + Client(self.0.clone()) } } From ef119f71e8c288d2a828b341cc82de9b499c1938 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 4 Aug 2017 21:59:15 +0200 Subject: [PATCH 08/15] Apply small change suggested by clippy --- examples/hello_world.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/hello_world.rs b/examples/hello_world.rs index a8d55858..0d671520 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -40,10 +40,10 @@ macro_rules! clone { } fn hello_world( - tokio_handle: TokioHandle, + tokio_handle: &TokioHandle, homeserver_url: Url, ) -> impl Future + 'static { - let client = Client::https(&tokio_handle, homeserver_url, None).unwrap(); + let client = Client::https(tokio_handle, homeserver_url, None).unwrap(); client.register_guest().and_then(clone!(client => move |_| { r0::alias::get_alias::call(client, r0::alias::get_alias::Request { @@ -74,5 +74,5 @@ fn main() { let handle = core.handle(); let server = Url::parse("https://matrix.org/").unwrap(); - core.run(hello_world(handle, server)).unwrap(); + core.run(hello_world(&handle, server)).unwrap(); } From afa44674481702c552673c80134a03033b9991db Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 4 Aug 2017 22:25:58 +0200 Subject: [PATCH 09/15] Remove unused extern crate in hello_world example --- examples/hello_world.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/hello_world.rs b/examples/hello_world.rs index 0d671520..708dade4 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -2,7 +2,6 @@ #![feature(try_from)] extern crate futures; -extern crate hyper; extern crate ruma_client; extern crate ruma_events; extern crate ruma_identifiers; From 92728e53e859555f3dd74dbcbfd5cd15a3e8160e Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 4 Aug 2017 22:00:31 +0200 Subject: [PATCH 10/15] Add Client::sync() --- src/lib.rs | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 72eefd2e..5b4c1034 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,6 +25,7 @@ use std::rc::Rc; use std::str::FromStr; use futures::future::{Future, FutureFrom, IntoFuture}; +use futures::stream::{self, Stream}; use hyper::{Client as HyperClient, Uri}; use hyper::client::{Connect, HttpConnector}; #[cfg(feature = "hyper-tls")] @@ -179,6 +180,45 @@ where }) } + /// Convenience method that represents repeated calls to the sync_events endpoint as a stream. + /// + /// If the since parameter is None, the first Item might take a significant time to arrive and + /// be deserialized, because it contains all events that have occured in the whole lifetime of + /// the logged-in users account and are visible to them. + pub fn sync( + &self, + filter: Option, + since: Option, + set_presence: bool, + ) -> impl Stream { + use api::r0::sync::sync_events; + + let client = self.clone(); + let set_presence = if set_presence { + None + } else { + Some(sync_events::SetPresence::Offline) + }; + + stream::unfold(since, move |since| { + Some( + sync_events::call( + client.clone(), + sync_events::Request { + filter: filter.clone(), + since, + full_state: None, + set_presence: set_presence.clone(), + timeout: None, + }, + ).map(|res| { + let next_batch_clone = res.next_batch.clone(); + (res, Some(next_batch_clone)) + }) + ) + }) + } + /// Makes a request to a Matrix API endpoint. pub(crate) fn request( self, From 02bbfd8664ea9b6397c0590ad3b6dbbc2dccc9ac Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 31 Aug 2017 12:38:58 +0200 Subject: [PATCH 11/15] Remove unused dependency --- Cargo.toml | 1 - src/lib.rs | 1 - 2 files changed, 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1e8c3a2a..5a16cd69 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,6 @@ hyper = "0.11.1" ruma-api = "0.4.0" ruma-client-api = "0.1.0" ruma-identifiers = "0.11.0" -serde = "1.0.9" serde_json = "1.0.2" serde_urlencoded = "0.5.1" tokio-core = "0.1.8" diff --git a/src/lib.rs b/src/lib.rs index 5b4c1034..971d22d5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,7 +13,6 @@ extern crate native_tls; extern crate ruma_api; extern crate ruma_client_api; extern crate ruma_identifiers; -extern crate serde; extern crate serde_json; extern crate serde_urlencoded; extern crate tokio_core; From 71605f0113892da102cb70e94f5bb92e8da2dc8e Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 31 Aug 2017 12:39:17 +0200 Subject: [PATCH 12/15] Add examples/hello_world_await.rs --- Cargo.toml | 1 + examples/hello_world_await.rs | 73 +++++++++++++++++++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 examples/hello_world_await.rs diff --git a/Cargo.toml b/Cargo.toml index 5a16cd69..64458347 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,7 @@ optional = true version = "0.1.4" [dev-dependencies] +futures-await = { git = 'https://github.com/alexcrichton/futures-await' } ruma-events = "0.9.0" [features] diff --git a/examples/hello_world_await.rs b/examples/hello_world_await.rs new file mode 100644 index 00000000..e833ec08 --- /dev/null +++ b/examples/hello_world_await.rs @@ -0,0 +1,73 @@ +#![feature(conservative_impl_trait)] +#![feature(generators)] +#![feature(proc_macro)] +#![feature(try_from)] + +extern crate futures_await as futures; +extern crate ruma_client; +extern crate ruma_events; +extern crate ruma_identifiers; +extern crate tokio_core; +extern crate url; + +use std::convert::TryFrom; + +use futures::prelude::*; +use ruma_client::Client; +use ruma_client::api::r0; +use ruma_events::EventType; +use ruma_events::room::message::{MessageEventContent, MessageType, TextMessageEventContent}; +use ruma_identifiers::RoomAliasId; +use tokio_core::reactor::{Core as TokioCore, Handle as TokioHandle}; +use url::Url; + +fn hello_world( + tokio_handle: &TokioHandle, + homeserver_url: Url, +) -> impl Future + 'static { + let client = Client::https(tokio_handle, homeserver_url, None).unwrap(); + + async_block! { + await!(client.register_guest())?; + + let response = await!(r0::alias::get_alias::call( + client.clone(), + r0::alias::get_alias::Request { + room_alias: RoomAliasId::try_from("#ruma-client-test:matrix.org").unwrap(), + } + ))?; + + let room_id = response.room_id; + + await!(r0::membership::join_room_by_id::call( + client.clone(), + r0::membership::join_room_by_id::Request { + room_id: room_id.clone(), + third_party_signed: None, + } + ))?; + + await!(r0::send::send_message_event::call( + client.clone(), + r0::send::send_message_event::Request { + room_id: room_id, + event_type: EventType::RoomMessage, + txn_id: "1".to_owned(), + data: MessageEventContent::Text(TextMessageEventContent { + body: "Hello World!".to_owned(), + msgtype: MessageType::Text, + }), + } + ))?; + + Ok(()) + } +} + +fn main() { + let mut core = TokioCore::new().unwrap(); + let handle = core.handle(); + let server = Url::parse("https://matrix.org/").unwrap(); + + core.run(hello_world(&handle, server)).unwrap(); +} From 4eb8e65248a4cbb214cf01ba2427cf8c3fc3f050 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sat, 14 Oct 2017 12:33:51 +0200 Subject: [PATCH 13/15] Return a copy of the session object from log_in, register_* --- src/lib.rs | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 971d22d5..836d68dd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -109,7 +109,7 @@ where /// session data returned by the endpoint in this client, instead of /// returning it. pub fn log_in(&self, user: String, password: String) - -> impl Future { + -> impl Future { use api::r0::session::login; let data = self.0.clone(); @@ -121,15 +121,17 @@ where password, user, }).map(move |response| { - *data.session.borrow_mut() = - Some(Session::new(response.access_token, response.user_id)); + let session = Session::new(response.access_token, response.user_id); + *data.session.borrow_mut() = Some(session.clone()); + + session }) } /// Register as a guest. In contrast to api::r0::account::register::call(), /// this method stores the session data returned by the endpoint in this /// client, instead of returning it. - pub fn register_guest(&self) -> impl Future { + pub fn register_guest(&self) -> impl Future { use api::r0::account::register; let data = self.0.clone(); @@ -143,8 +145,10 @@ where password: None, username: None, }).map(move |response| { - *data.session.borrow_mut() = - Some(Session::new(response.access_token, response.user_id)); + let session = Session::new(response.access_token, response.user_id); + *data.session.borrow_mut() = Some(session.clone()); + + session }) } @@ -160,7 +164,7 @@ where &self, username: Option, password: String, - ) -> impl Future { + ) -> impl Future { use api::r0::account::register; let data = self.0.clone(); @@ -174,8 +178,10 @@ where password: Some(password), username: username, }).map(move |response| { - *data.session.borrow_mut() = - Some(Session::new(response.access_token, response.user_id)); + let session = Session::new(response.access_token, response.user_id); + *data.session.borrow_mut() = Some(session.clone()); + + session }) } From 76d0780f5a0561cc0d0d8351b2bef77c325bc5bf Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 19 Oct 2017 23:29:06 +0200 Subject: [PATCH 14/15] Remove aliases for Core and Handle from tokio_core --- examples/hello_world.rs | 6 +++--- examples/hello_world_await.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/examples/hello_world.rs b/examples/hello_world.rs index 708dade4..dc62b7a2 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -16,7 +16,7 @@ use ruma_client::api::r0; use ruma_events::EventType; use ruma_events::room::message::{MessageEventContent, MessageType, TextMessageEventContent}; use ruma_identifiers::RoomAliasId; -use tokio_core::reactor::{Core as TokioCore, Handle as TokioHandle}; +use tokio_core::reactor::{Core, Handle}; use url::Url; // from https://stackoverflow.com/a/43992218/1592377 @@ -39,7 +39,7 @@ macro_rules! clone { } fn hello_world( - tokio_handle: &TokioHandle, + tokio_handle: &Handle, homeserver_url: Url, ) -> impl Future + 'static { let client = Client::https(tokio_handle, homeserver_url, None).unwrap(); @@ -69,7 +69,7 @@ fn hello_world( } fn main() { - let mut core = TokioCore::new().unwrap(); + let mut core = Core::new().unwrap(); let handle = core.handle(); let server = Url::parse("https://matrix.org/").unwrap(); diff --git a/examples/hello_world_await.rs b/examples/hello_world_await.rs index e833ec08..b0167d64 100644 --- a/examples/hello_world_await.rs +++ b/examples/hello_world_await.rs @@ -18,11 +18,11 @@ use ruma_client::api::r0; use ruma_events::EventType; use ruma_events::room::message::{MessageEventContent, MessageType, TextMessageEventContent}; use ruma_identifiers::RoomAliasId; -use tokio_core::reactor::{Core as TokioCore, Handle as TokioHandle}; +use tokio_core::reactor::{Core, Handle}; use url::Url; fn hello_world( - tokio_handle: &TokioHandle, + tokio_handle: &Handle, homeserver_url: Url, ) -> impl Future + 'static { let client = Client::https(tokio_handle, homeserver_url, None).unwrap(); @@ -65,7 +65,7 @@ fn hello_world( } fn main() { - let mut core = TokioCore::new().unwrap(); + let mut core = Core::new().unwrap(); let handle = core.handle(); let server = Url::parse("https://matrix.org/").unwrap(); From 5df3d4888d0b696dd666ce2de8f2b6a11c74a0ff Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 19 Oct 2017 23:43:45 +0200 Subject: [PATCH 15/15] Turn homeserver url and room into command line params for hello_world examples --- examples/hello_world.rs | 17 ++++++++++++++--- examples/hello_world_await.rs | 18 +++++++++++++++--- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/examples/hello_world.rs b/examples/hello_world.rs index dc62b7a2..e444eeee 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -9,6 +9,8 @@ extern crate tokio_core; extern crate url; use std::convert::TryFrom; +use std::env; +use std::process::exit; use futures::Future; use ruma_client::Client; @@ -41,12 +43,13 @@ macro_rules! clone { fn hello_world( tokio_handle: &Handle, homeserver_url: Url, + room: String, ) -> impl Future + 'static { let client = Client::https(tokio_handle, homeserver_url, None).unwrap(); client.register_guest().and_then(clone!(client => move |_| { r0::alias::get_alias::call(client, r0::alias::get_alias::Request { - room_alias: RoomAliasId::try_from("#ruma-client-test:matrix.org").unwrap(), + room_alias: RoomAliasId::try_from(&room[..]).unwrap(), }) })).and_then(clone!(client => move |response| { let room_id = response.room_id; @@ -69,9 +72,17 @@ fn hello_world( } fn main() { + let (homeserver_url, room) = match (env::args().nth(1), env::args().nth(2)) { + (Some(a), Some(b)) => (a, b), + _ => { + eprintln!("Usage: {} ", env::args().next().unwrap()); + exit(1) + } + }; + let mut core = Core::new().unwrap(); let handle = core.handle(); - let server = Url::parse("https://matrix.org/").unwrap(); + let server = Url::parse(&homeserver_url).unwrap(); - core.run(hello_world(&handle, server)).unwrap(); + core.run(hello_world(&handle, server, room)).unwrap(); } diff --git a/examples/hello_world_await.rs b/examples/hello_world_await.rs index b0167d64..cd5dd3f5 100644 --- a/examples/hello_world_await.rs +++ b/examples/hello_world_await.rs @@ -11,6 +11,8 @@ extern crate tokio_core; extern crate url; use std::convert::TryFrom; +use std::env; +use std::process::exit; use futures::prelude::*; use ruma_client::Client; @@ -24,6 +26,7 @@ use url::Url; fn hello_world( tokio_handle: &Handle, homeserver_url: Url, + room: String, ) -> impl Future + 'static { let client = Client::https(tokio_handle, homeserver_url, None).unwrap(); @@ -33,7 +36,7 @@ fn hello_world( let response = await!(r0::alias::get_alias::call( client.clone(), r0::alias::get_alias::Request { - room_alias: RoomAliasId::try_from("#ruma-client-test:matrix.org").unwrap(), + room_alias: RoomAliasId::try_from(&room[..]).unwrap(), } ))?; @@ -65,9 +68,18 @@ fn hello_world( } fn main() { + let (homeserver_url, room) = match (env::args().nth(1), env::args().nth(2)) { + (Some(a), Some(b)) => (a, b), + _ => { + eprintln!("Usage: {} ", env::args().next().unwrap()); + exit(1) + } + }; + + let mut core = Core::new().unwrap(); let handle = core.handle(); - let server = Url::parse("https://matrix.org/").unwrap(); + let server = Url::parse(&homeserver_url).unwrap(); - core.run(hello_world(&handle, server)).unwrap(); + core.run(hello_world(&handle, server, room)).unwrap(); }