From 7eba14d983ec944fb118f1dacca377fba8850460 Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Thu, 16 Jun 2016 04:40:47 -0700 Subject: [PATCH 001/139] matrix-client --- LICENSE | 20 ++++++++++++++++++++ README.md | 7 +++++++ 2 files changed, 27 insertions(+) create mode 100644 LICENSE create mode 100644 README.md diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..de62627d --- /dev/null +++ b/LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2016 Jimmy Cuadra + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/README.md b/README.md new file mode 100644 index 00000000..5758490b --- /dev/null +++ b/README.md @@ -0,0 +1,7 @@ +# ruma-client + +**ruma-client** is a [Matrix](https://matrix.org/) client library for [Rust](https://www.rust-lang.org/). + +## License + +[MIT](http://opensource.org/licenses/MIT) From b1ba09a04d1866a235d18393eafa2325294d532e Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Sat, 31 Dec 2016 02:17:49 -0800 Subject: [PATCH 002/139] Start integrating with ruma-client-api. --- .gitignore | 2 ++ Cargo.toml | 19 +++++++++++++ src/error.rs | 33 +++++++++++++++++++++ src/lib.rs | 76 +++++++++++++++++++++++++++++++++++++++++++++++++ src/response.rs | 41 ++++++++++++++++++++++++++ src/session.rs | 10 +++++++ 6 files changed, 181 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 src/error.rs create mode 100644 src/lib.rs create mode 100644 src/response.rs create mode 100644 src/session.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..1b72444a --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/Cargo.lock +/target diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 00000000..3d1d6a5c --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,19 @@ +[package] +authors = ["Jimmy Cuadra "] +description = "A Matrix client library." +documentation = "https://docs.rs/ruma-client" +homepage = "https://github.com/ruma/ruma-client" +keywords = ["matrix", "chat", "messaging", "ruma"] +license = "MIT" +name = "ruma-client" +readme = "README.md" +repository = "https://github.com/ruma/ruma-client" +version = "0.1.0" + +[dependencies] +hyper = "0.9.14" +ruma-client-api = { path = "../ruma-client-api" } +ruma-identifiers = "0.6.0" +serde = "0.8.21" +serde_json = "0.8.4" +url = "1.2.4" diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 00000000..8f76a40e --- /dev/null +++ b/src/error.rs @@ -0,0 +1,33 @@ +use hyper::Error as HyperError; +use serde_json::Error as SerdeJsonError; +use url::ParseError; + +/// An error that occurs during client operations. +#[derive(Debug)] +pub enum Error { + /// An error at the HTTP layer. + Hyper(HyperError), + /// An error when parsing a string as a URL. + Url(ParseError), + /// An error when serializing or deserializing a value. + SerdeJson(SerdeJsonError) +} + +impl From for Error { + fn from(error: HyperError) -> Error { + Error::Hyper(error) + } +} + +impl From for Error { + fn from(error: ParseError) -> Error { + Error::Url(error) + } +} + +impl From for Error { + fn from(error: SerdeJsonError) -> Error { + Error::SerdeJson(error) + } +} + diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 00000000..eda49ddb --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,76 @@ +//! Crate ruma_client is a [Matrix](https://matrix.org/) client library. + +#![feature(try_from)] +#![deny(missing_debug_implementations)] +#![deny(missing_docs)] + +extern crate hyper; +extern crate ruma_client_api; +extern crate ruma_identifiers; +extern crate serde; +extern crate serde_json; +extern crate url; + +use std::convert::TryInto; + +use hyper::client::{Client as Hyper, IntoUrl}; +use hyper::method::Method as HyperMethod; +use ruma_client_api::{Endpoint, Method, supported_versions}; +use url::Url; + +pub use error::Error; +pub use session::Session; +pub use response::Response; + +mod error; +mod response; +mod session; + +/// A client for the Matrix client-server API. +#[derive(Debug)] +pub struct Client { + homeserver_url: Url, + hyper: Hyper, + session: Option, +} + +trait IntoHyperMethod { + fn into_hyper(self) -> HyperMethod; +} + +impl IntoHyperMethod for Method { + fn into_hyper(self) -> HyperMethod { + match self { + Method::Delete => HyperMethod::Delete, + Method::Get => HyperMethod::Get, + Method::Put => HyperMethod::Put, + Method::Post => HyperMethod::Post, + } + } +} + +impl Client { + /// Creates a new client for making requests to the given homeserver. + /// + /// # Errors + /// + /// Returns an error if the given homserver URL cannot be parsed as a URL. + pub fn new(homeserver_url: U) -> Result where U: IntoUrl { + Ok(Client { + homeserver_url: homeserver_url.into_url()?, + hyper: Hyper::new(), + session: None, + }) + } + + /// Get the versions of the Matrix client-server specification supported by the homeserver. + pub fn get_supported_versions(&self) + -> Result::Response>, Error> { + let response = self.hyper.request( + supported_versions::Endpoint::method().into_hyper(), + self.homeserver_url.join(&supported_versions::Endpoint::request_path(()))?, + ).send()?; + + Ok(response.try_into()?) + } +} diff --git a/src/response.rs b/src/response.rs new file mode 100644 index 00000000..ad50fd08 --- /dev/null +++ b/src/response.rs @@ -0,0 +1,41 @@ +use std::convert::TryFrom; +use std::fmt::Debug; + +use hyper::client::Response as HyperResponse; +use hyper::header::Headers; +use hyper::status::StatusCode; +use hyper::version::HttpVersion; +use serde::Deserialize; +use serde_json::from_reader; +use url::Url; + +use Error; + +/// A response from a Matrix homeserver. +#[derive(Debug)] +pub struct Response where T: Debug + Deserialize { + /// The response from the Matrix API. + pub data: T, + /// The HTTP response code. + pub status: StatusCode, + /// The HTTP response headers. + pub headers: Headers, + /// The HTTP version. + pub http_version: HttpVersion, + /// The URL that was requested. + pub url: Url, +} + +impl TryFrom for Response where T: Debug + Deserialize { + type Err = Error; + + fn try_from(hyper_response: HyperResponse) -> Result { + Ok(Response { + status: hyper_response.status, + headers: hyper_response.headers.clone(), + http_version: hyper_response.version, + url: hyper_response.url.clone(), + data: from_reader(hyper_response)?, + }) + } +} diff --git a/src/session.rs b/src/session.rs new file mode 100644 index 00000000..c050021f --- /dev/null +++ b/src/session.rs @@ -0,0 +1,10 @@ +use ruma_identifiers::UserId; +use url::Host; + +/// An active user session with a Matrix homeserver, allowing authenticated requests. +#[derive(Clone, Debug)] +pub struct Session { + access_token: String, + homeserver: Host, + user_id: UserId, +} From a48b01f2a5e31d3596e4508ddd11cb52eb548b55 Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Sat, 31 Dec 2016 02:24:12 -0800 Subject: [PATCH 003/139] Configure Travis CI. --- .travis.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..c677ed70 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,10 @@ +language: "rust" +notifications: + email: false + irc: + channels: + - secure: "AJxKl4hMtg1g8+uUqgF4yeOZKCW5rqxilF/LFicRUGZFsqurO/pmvBrWIx2NeCpjUo7IPGR78NhbRPu7Qp93hHd4UQfnDE9Aw2iU7nMdJlnSMdztilObLPGtopJQGt1HXwJquxUvqd/J95Eb5ep+PbwJMj2qkEF1e5JlGhNKnpAQVL7RQYHhKGD6n6vkqpStQvvswtSHH0Uk6nrlZEVQxrvQy7w+iw5lEHqg64Y+w17ilR/+NJrLT83UlnOGKOADJ9bh8l8GrQvqmQhFwcJv1qj5tp6Tr30eN45FIv4P1hUkXW5lSm3mgX4b1QVDeCGH8ebo/WChrUB461uZhZnVk8JrWGtcrmLP08daliQxhm6Ybm4cW9kcZXMEs64wqz/xcYX0rJo4dwoY1ZyvM1G3b6HwYEEgiU5ypM3rXzT/7z007zOxD/EjCYQumBZKarqEkH76qSlPwjsYWQOWY9gwNeh93Gg+a+0wD2HitKzxPnTYaFt67QaZxxC/h2YNcvVAxPyiC0gdTUf+cPG0KidJKexfg4cSjHQj7EnPpNPzSfqdA5XvmkEeUV4Igi/sQHSiS4OFwtaq99bIqm4FZswFJq+T4IUyTC5jzvT3b2D6AZuwJnxtYXT70iO12+q+D7V01zLI8O0qGS31NkK5NYjTULQdWuOnSANnfeCnhdDleys=" + use_notice: true +rust: + - "nightly" + From a7ce18f7528a1cb1140e01f2faa19ccd62022016 Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Sat, 31 Dec 2016 02:26:29 -0800 Subject: [PATCH 004/139] Use the Git version of ruma-client-api. --- Cargo.toml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3d1d6a5c..d87f7038 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,8 +12,10 @@ version = "0.1.0" [dependencies] hyper = "0.9.14" -ruma-client-api = { path = "../ruma-client-api" } ruma-identifiers = "0.6.0" serde = "0.8.21" serde_json = "0.8.4" url = "1.2.4" + +[dependencies.ruma-client-api] +git = "https://github.com/ruma/ruma-client-api" From 94d1e61e3550d5934f9a907dc7969a0fa771e42f Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Mon, 2 Jan 2017 02:04:22 -0800 Subject: [PATCH 005/139] Update get_supported_versions for new module structure in ruma-client-api. --- src/lib.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index eda49ddb..2c828406 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,7 +15,8 @@ use std::convert::TryInto; use hyper::client::{Client as Hyper, IntoUrl}; use hyper::method::Method as HyperMethod; -use ruma_client_api::{Endpoint, Method, supported_versions}; +use ruma_client_api::{Endpoint, Method}; +use ruma_client_api::unversioned::get_supported_versions; use url::Url; pub use error::Error; @@ -65,7 +66,7 @@ impl Client { /// Get the versions of the Matrix client-server specification supported by the homeserver. pub fn get_supported_versions(&self) - -> Result::Response>, Error> { + -> Result::Response>, Error> { let response = self.hyper.request( supported_versions::Endpoint::method().into_hyper(), self.homeserver_url.join(&supported_versions::Endpoint::request_path(()))?, From ba1a73e36361ae3fdb2ddd112226159c89a82cef Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Mon, 2 Jan 2017 02:22:33 -0800 Subject: [PATCH 006/139] Correct more module names that changed. --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2c828406..aef5a4c2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -68,8 +68,8 @@ impl Client { pub fn get_supported_versions(&self) -> Result::Response>, Error> { let response = self.hyper.request( - supported_versions::Endpoint::method().into_hyper(), - self.homeserver_url.join(&supported_versions::Endpoint::request_path(()))?, + get_supported_versions::Endpoint::method().into_hyper(), + self.homeserver_url.join(&get_supported_versions::Endpoint::request_path(()))?, ).send()?; Ok(response.try_into()?) From 43d21222dd8006d40bc4a24c14a78c94acde72fd Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Sat, 7 Jan 2017 00:11:19 -0800 Subject: [PATCH 007/139] Use Hyper's Tokio branch. --- Cargo.toml | 7 +++- src/lib.rs | 61 ++++++++++++++++++++++--------- src/response.rs | 97 +++++++++++++++++++++++++++++++++++++------------ 3 files changed, 123 insertions(+), 42 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d87f7038..ad20a3a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,11 +11,16 @@ repository = "https://github.com/ruma/ruma-client" version = "0.1.0" [dependencies] -hyper = "0.9.14" +futures = "0.1.7" ruma-identifiers = "0.6.0" serde = "0.8.21" serde_json = "0.8.4" +tokio-core = "0.1.3" url = "1.2.4" +[dependencies.hyper] +branch = "tokio" +git = "https://github.com/hyperium/hyper" + [dependencies.ruma-client-api] git = "https://github.com/ruma/ruma-client-api" diff --git a/src/lib.rs b/src/lib.rs index aef5a4c2..2ebd4038 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,27 +1,27 @@ //! Crate ruma_client is a [Matrix](https://matrix.org/) client library. -#![feature(try_from)] #![deny(missing_debug_implementations)] #![deny(missing_docs)] +extern crate futures; extern crate hyper; extern crate ruma_client_api; extern crate ruma_identifiers; extern crate serde; extern crate serde_json; +extern crate tokio_core; extern crate url; -use std::convert::TryInto; - -use hyper::client::{Client as Hyper, IntoUrl}; -use hyper::method::Method as HyperMethod; +use hyper::client::{Client as HyperClient, DefaultConnector, Request as HyperRequest}; +use hyper::Method as HyperMethod; use ruma_client_api::{Endpoint, Method}; use ruma_client_api::unversioned::get_supported_versions; +use tokio_core::reactor::Handle; use url::Url; pub use error::Error; pub use session::Session; -pub use response::Response; +pub use response::{FutureResponse, Response}; mod error; mod response; @@ -31,7 +31,7 @@ mod session; #[derive(Debug)] pub struct Client { homeserver_url: Url, - hyper: Hyper, + hyper: HyperClient, session: Option, } @@ -55,23 +55,50 @@ impl Client { /// /// # Errors /// - /// Returns an error if the given homserver URL cannot be parsed as a URL. - pub fn new(homeserver_url: U) -> Result where U: IntoUrl { + /// Returns an error if the given homeserver URL cannot be parsed as a URL. + pub fn new(handle: &Handle, homeserver_url: U) -> Result where U: TryIntoUrl { Ok(Client { - homeserver_url: homeserver_url.into_url()?, - hyper: Hyper::new(), + homeserver_url: homeserver_url.try_into()?, + hyper: HyperClient::configure().keep_alive(true).build(handle), session: None, }) } /// Get the versions of the Matrix client-server specification supported by the homeserver. - pub fn get_supported_versions(&self) - -> Result::Response>, Error> { - let response = self.hyper.request( + pub fn get_supported_versions(&mut self) + -> FutureResponse<::Response> { + let request = HyperRequest::new( get_supported_versions::Endpoint::method().into_hyper(), - self.homeserver_url.join(&get_supported_versions::Endpoint::request_path(()))?, - ).send()?; + self.homeserver_url.join( + &get_supported_versions::Endpoint::request_path(()) + ).expect("request path should be joinable").try_into().expect("url should be parsable"), + ); - Ok(response.try_into()?) + FutureResponse::from(self.hyper.request(request)) + } +} + +/// Functionally equivalent to `TryInto`, and should be replaced by that as soon as it's +/// stable and available. +pub trait TryIntoUrl { + /// Performs the conversion. + fn try_into(self) -> Result; +} + +impl TryIntoUrl for String { + fn try_into(self) -> Result { + Url::parse(&self).map_err(Error::from) + } +} + +impl<'a> TryIntoUrl for &'a str { + fn try_into(self) -> Result { + Url::parse(self).map_err(Error::from) + } +} + +impl TryIntoUrl for Url { + fn try_into(self) -> Result { + Ok(self) } } diff --git a/src/response.rs b/src/response.rs index ad50fd08..9ab4f40d 100644 --- a/src/response.rs +++ b/src/response.rs @@ -1,41 +1,90 @@ -use std::convert::TryFrom; use std::fmt::Debug; +use std::io::Write; +use std::marker::PhantomData; -use hyper::client::Response as HyperResponse; +use futures::{Async, Future, Poll, Stream}; +use hyper::client::{FutureResponse as HyperFutureResponse, Response as HyperResponse}; +use hyper::{Error as HyperError}; use hyper::header::Headers; use hyper::status::StatusCode; -use hyper::version::HttpVersion; +use hyper::HttpVersion; use serde::Deserialize; -use serde_json::from_reader; -use url::Url; +use serde_json::from_slice; use Error; +/// A `Future` that will resolve into a `Response`. +#[derive(Debug)] +pub struct FutureResponse where T: Debug + Deserialize + Send + 'static { + hyper_future_response: HyperFutureResponse, + phantom: PhantomData, +} + /// A response from a Matrix homeserver. #[derive(Debug)] pub struct Response where T: Debug + Deserialize { + /// The Hyper response. + hyper_response: HyperResponse, /// The response from the Matrix API. - pub data: T, - /// The HTTP response code. - pub status: StatusCode, - /// The HTTP response headers. - pub headers: Headers, - /// The HTTP version. - pub http_version: HttpVersion, - /// The URL that was requested. - pub url: Url, + phantom: PhantomData, } -impl TryFrom for Response where T: Debug + Deserialize { - type Err = Error; +impl Future for FutureResponse where T: Debug + Deserialize + Send + 'static { + type Item = Response; + type Error = Error; - fn try_from(hyper_response: HyperResponse) -> Result { - Ok(Response { - status: hyper_response.status, - headers: hyper_response.headers.clone(), - http_version: hyper_response.version, - url: hyper_response.url.clone(), - data: from_reader(hyper_response)?, - }) + fn poll(&mut self) -> Poll { + match self.hyper_future_response.poll() { + Ok(Async::Ready(hyper_response)) => Ok(Async::Ready(Response { + hyper_response: hyper_response, + phantom: PhantomData, + })), + Ok(Async::NotReady) => Ok(Async::NotReady), + Err(error) => Err(Error::from(error)), + } + } +} + +impl From for FutureResponse +where T: Debug + Deserialize + Send + 'static { + fn from(hyper_future_response: HyperFutureResponse) -> FutureResponse { + FutureResponse { + hyper_future_response: hyper_future_response, + phantom: PhantomData, + } + } +} + +impl Response where T: Debug + Deserialize + Send + 'static { + /// The response from the Matrix API. + pub fn data(self) -> Box> { + let bytes = self.hyper_response.body().fold(Vec::new(), |mut bytes, chunk| { + if let Err(error) = bytes.write_all(&chunk) { + return Err(HyperError::from(error)); + } + + Ok(bytes) + }).map_err(Error::from); + + let deserialized_data = bytes.and_then(|bytes| { + from_slice(bytes.as_slice()).map_err(Error::from) + }); + + deserialized_data.boxed() + } + + /// The HTTP response code. + pub fn status(&self) -> &StatusCode { + self.hyper_response.status() + } + + /// The HTTP response headers. + pub fn headers(&self) -> &Headers { + self.hyper_response.headers() + } + + /// The HTTP version. + pub fn http_version(&self) -> &HttpVersion { + self.hyper_response.version() } } From 6daa7c22f15af985ef215995a78ad504a9b5c0ec Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Sat, 7 Jan 2017 05:31:18 -0800 Subject: [PATCH 008/139] Implement HTTP requests generically for all `Endpoint`s. --- Cargo.toml | 1 + src/error.rs | 12 ++++++++++-- src/lib.rs | 35 +++++++++++++++++++++++++++-------- 3 files changed, 38 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ad20a3a2..3c756e43 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ futures = "0.1.7" ruma-identifiers = "0.6.0" serde = "0.8.21" serde_json = "0.8.4" +serde_urlencoded = "0.3.0" tokio-core = "0.1.3" url = "1.2.4" diff --git a/src/error.rs b/src/error.rs index 8f76a40e..1b30cb6a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,5 +1,6 @@ use hyper::Error as HyperError; use serde_json::Error as SerdeJsonError; +use serde_urlencoded::ser::Error as SerdeUrlEncodedSerializeError; use url::ParseError; /// An error that occurs during client operations. @@ -9,8 +10,10 @@ pub enum Error { Hyper(HyperError), /// An error when parsing a string as a URL. Url(ParseError), - /// An error when serializing or deserializing a value. - SerdeJson(SerdeJsonError) + /// An error when serializing or deserializing a JSON value. + SerdeJson(SerdeJsonError), + /// An error when serializing a query string value. + SerdeUrlEncodedSerialize(SerdeUrlEncodedSerializeError), } impl From for Error { @@ -31,3 +34,8 @@ impl From for Error { } } +impl From for Error { + fn from(error: SerdeUrlEncodedSerializeError) -> Error { + Error::SerdeUrlEncodedSerialize(error) + } +} diff --git a/src/lib.rs b/src/lib.rs index 2ebd4038..b336661c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,9 +9,12 @@ extern crate ruma_client_api; extern crate ruma_identifiers; extern crate serde; extern crate serde_json; +extern crate serde_urlencoded; extern crate tokio_core; extern crate url; +use std::fmt::Debug; + use hyper::client::{Client as HyperClient, DefaultConnector, Request as HyperRequest}; use hyper::Method as HyperMethod; use ruma_client_api::{Endpoint, Method}; @@ -66,15 +69,31 @@ impl Client { /// Get the versions of the Matrix client-server specification supported by the homeserver. pub fn get_supported_versions(&mut self) - -> FutureResponse<::Response> { - let request = HyperRequest::new( - get_supported_versions::Endpoint::method().into_hyper(), - self.homeserver_url.join( - &get_supported_versions::Endpoint::request_path(()) - ).expect("request path should be joinable").try_into().expect("url should be parsable"), - ); + -> Result::Response>, Error> { + self.request::((), (), ()) + } - FutureResponse::from(self.hyper.request(request)) + fn request( + &mut self, + body_params: E::BodyParams, + path_params: E::PathParams, + query_params: E::QueryParams, + ) -> Result, Error> + where E: Endpoint, ::Response: Debug + Send { + let mut url = self.homeserver_url.join(&E::request_path(path_params))?.try_into()?; + + url.set_query(Some(&serde_urlencoded::to_string(&query_params)?)); + + let mut request = HyperRequest::new(E::method().into_hyper(), url); + + match E::method() { + Method::Post | Method::Put => { + request.set_body(serde_json::to_string(&body_params)?); + } + _ => {} + } + + Ok(FutureResponse::from(self.hyper.request(request))) } } From bafc48292ec68696bbca92ae8ea4f1a0ab5785e5 Mon Sep 17 00:00:00 2001 From: Victor Berger Date: Sun, 8 Jan 2017 15:21:33 +0100 Subject: [PATCH 009/139] Add support for authenticated endpoints. --- src/error.rs | 2 ++ src/lib.rs | 8 ++++++++ src/session.rs | 9 ++++++--- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/error.rs b/src/error.rs index 1b30cb6a..ee2f1483 100644 --- a/src/error.rs +++ b/src/error.rs @@ -14,6 +14,8 @@ pub enum Error { SerdeJson(SerdeJsonError), /// An error when serializing a query string value. SerdeUrlEncodedSerialize(SerdeUrlEncodedSerializeError), + /// Queried endpoint requires authentication but was called on an anonymous client + AuthenticationRequired } impl From for Error { diff --git a/src/lib.rs b/src/lib.rs index b336661c..f627ae26 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -84,6 +84,14 @@ impl Client { url.set_query(Some(&serde_urlencoded::to_string(&query_params)?)); + if E::requires_authentication() { + if let Some(ref session) = self.session { + url.query_pairs_mut().append_pair("access_token", &session.access_token); + } else { + return Err(Error::AuthenticationRequired) + } + } + let mut request = HyperRequest::new(E::method().into_hyper(), url); match E::method() { diff --git a/src/session.rs b/src/session.rs index c050021f..7e450741 100644 --- a/src/session.rs +++ b/src/session.rs @@ -4,7 +4,10 @@ use url::Host; /// An active user session with a Matrix homeserver, allowing authenticated requests. #[derive(Clone, Debug)] pub struct Session { - access_token: String, - homeserver: Host, - user_id: UserId, + /// The access token of this session + pub access_token: String, + /// The homeserver this session is associated with + pub homeserver: Host, + /// the ID of the user owning this session + pub user_id: UserId, } From 1492147875e85eb08593f5ba81b7426226a5d026 Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Mon, 16 Jan 2017 23:15:25 -0800 Subject: [PATCH 010/139] Fix style issues reported by clippy and rustfmt. --- src/error.rs | 2 +- src/lib.rs | 8 ++++---- src/response.rs | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/error.rs b/src/error.rs index ee2f1483..aa9fafcf 100644 --- a/src/error.rs +++ b/src/error.rs @@ -15,7 +15,7 @@ pub enum Error { /// An error when serializing a query string value. SerdeUrlEncodedSerialize(SerdeUrlEncodedSerializeError), /// Queried endpoint requires authentication but was called on an anonymous client - AuthenticationRequired + AuthenticationRequired, } impl From for Error { diff --git a/src/lib.rs b/src/lib.rs index f627ae26..2004221d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,4 @@ -//! Crate ruma_client is a [Matrix](https://matrix.org/) client library. +//! Crate `ruma_client` is a [Matrix](https://matrix.org/) client library. #![deny(missing_debug_implementations)] #![deny(missing_docs)] @@ -15,7 +15,7 @@ extern crate url; use std::fmt::Debug; -use hyper::client::{Client as HyperClient, DefaultConnector, Request as HyperRequest}; +use hyper::client::{Client as HyperClient, HttpConnector, Request as HyperRequest}; use hyper::Method as HyperMethod; use ruma_client_api::{Endpoint, Method}; use ruma_client_api::unversioned::get_supported_versions; @@ -34,7 +34,7 @@ mod session; #[derive(Debug)] pub struct Client { homeserver_url: Url, - hyper: HyperClient, + hyper: HyperClient, session: Option, } @@ -88,7 +88,7 @@ impl Client { if let Some(ref session) = self.session { url.query_pairs_mut().append_pair("access_token", &session.access_token); } else { - return Err(Error::AuthenticationRequired) + return Err(Error::AuthenticationRequired); } } diff --git a/src/response.rs b/src/response.rs index 9ab4f40d..cb9753a0 100644 --- a/src/response.rs +++ b/src/response.rs @@ -4,7 +4,7 @@ use std::marker::PhantomData; use futures::{Async, Future, Poll, Stream}; use hyper::client::{FutureResponse as HyperFutureResponse, Response as HyperResponse}; -use hyper::{Error as HyperError}; +use hyper::Error as HyperError; use hyper::header::Headers; use hyper::status::StatusCode; use hyper::HttpVersion; From 212d3a5e7bb34fdabd3c0d0cdec7ab2220169d06 Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Mon, 16 Jan 2017 23:16:21 -0800 Subject: [PATCH 011/139] Make all of Endpoint's associated types optional parameters when building a request. --- src/lib.rs | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2004221d..417fa6e5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -70,19 +70,26 @@ impl Client { /// Get the versions of the Matrix client-server specification supported by the homeserver. pub fn get_supported_versions(&mut self) -> Result::Response>, Error> { - self.request::((), (), ()) + self.request::(None, None, None) } fn request( &mut self, - body_params: E::BodyParams, - path_params: E::PathParams, - query_params: E::QueryParams, + body_params: Option, + path_params: Option, + query_params: Option, ) -> Result, Error> where E: Endpoint, ::Response: Debug + Send { - let mut url = self.homeserver_url.join(&E::request_path(path_params))?.try_into()?; + let path = match path_params { + Some(params) => E::request_path(params), + None => E::router_path().to_string(), + }; - url.set_query(Some(&serde_urlencoded::to_string(&query_params)?)); + let mut url = self.homeserver_url.join(&path)?.try_into()?; + + if let Some(params) = query_params { + url.set_query(Some(&serde_urlencoded::to_string(¶ms)?)); + } if E::requires_authentication() { if let Some(ref session) = self.session { @@ -96,7 +103,9 @@ impl Client { match E::method() { Method::Post | Method::Put => { - request.set_body(serde_json::to_string(&body_params)?); + if let Some(params) = body_params { + request.set_body(serde_json::to_string(¶ms)?); + } } _ => {} } From 6de867b22327b400771e631bb55e43e43939507c Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Tue, 17 Jan 2017 19:33:19 -0800 Subject: [PATCH 012/139] Use Cow to avoid a string allocation. --- src/lib.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 417fa6e5..7b88faf0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,6 +13,7 @@ extern crate serde_urlencoded; extern crate tokio_core; extern crate url; +use std::borrow::Cow; use std::fmt::Debug; use hyper::client::{Client as HyperClient, HttpConnector, Request as HyperRequest}; @@ -81,11 +82,11 @@ impl Client { ) -> Result, Error> where E: Endpoint, ::Response: Debug + Send { let path = match path_params { - Some(params) => E::request_path(params), - None => E::router_path().to_string(), + Some(params) => Cow::from(E::request_path(params)), + None => Cow::from(E::router_path()), }; - let mut url = self.homeserver_url.join(&path)?.try_into()?; + let mut url = self.homeserver_url.join(path.as_ref())?.try_into()?; if let Some(params) = query_params { url.set_query(Some(&serde_urlencoded::to_string(¶ms)?)); From bccad7e40c675088be68f4a6c44db5b9ce100871 Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Tue, 17 Jan 2017 19:39:40 -0800 Subject: [PATCH 013/139] Use Hyper's master branch cause the tokio branch was merged. --- Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3c756e43..6134a9a2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,7 +20,6 @@ tokio-core = "0.1.3" url = "1.2.4" [dependencies.hyper] -branch = "tokio" git = "https://github.com/hyperium/hyper" [dependencies.ruma-client-api] From fafe30fdecede7f3df53b1be89ead10a7d0f2705 Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Thu, 11 May 2017 23:36:34 -0700 Subject: [PATCH 014/139] Revise implementation of Client::request to use the latest ruma-api/ruma-client-api. --- Cargo.toml | 19 ++++--- src/error.rs | 9 ++++ src/lib.rs | 130 +++++++++++------------------------------------- src/response.rs | 90 --------------------------------- 4 files changed, 51 insertions(+), 197 deletions(-) delete mode 100644 src/response.rs diff --git a/Cargo.toml b/Cargo.toml index 6134a9a2..486c7300 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,16 +11,21 @@ repository = "https://github.com/ruma/ruma-client" version = "0.1.0" [dependencies] -futures = "0.1.7" -ruma-identifiers = "0.6.0" -serde = "0.8.21" -serde_json = "0.8.4" -serde_urlencoded = "0.3.0" -tokio-core = "0.1.3" -url = "1.2.4" +futures = "0.1.13" +ruma-identifiers = "0.11.0" +serde = "1.0.2" +serde_json = "1.0.1" +serde_urlencoded = "0.4.3" +tokio-core = "0.1.6" +url = "1.4.0" [dependencies.hyper] git = "https://github.com/hyperium/hyper" +rev = "fed04dfb58e19b408322d4e5ca7474871e848a35" + +[dependencies.ruma-api] +git = "https://github.com/ruma/ruma-api" [dependencies.ruma-client-api] git = "https://github.com/ruma/ruma-client-api" +branch = "manual" diff --git a/src/error.rs b/src/error.rs index aa9fafcf..b2fecb50 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,4 +1,5 @@ use hyper::Error as HyperError; +use ruma_client_api::Error as RumaClientApiError; use serde_json::Error as SerdeJsonError; use serde_urlencoded::ser::Error as SerdeUrlEncodedSerializeError; use url::ParseError; @@ -10,6 +11,8 @@ pub enum Error { Hyper(HyperError), /// An error when parsing a string as a URL. Url(ParseError), + /// An error converting between ruma_client_api types and Hyper types. + RumaClientApi(RumaClientApiError), /// An error when serializing or deserializing a JSON value. SerdeJson(SerdeJsonError), /// An error when serializing a query string value. @@ -30,6 +33,12 @@ impl From for Error { } } +impl From for Error { + fn from(error: RumaClientApiError) -> Error { + Error::RumaClientApi(error) + } +} + impl From for Error { fn from(error: SerdeJsonError) -> Error { Error::SerdeJson(error) diff --git a/src/lib.rs b/src/lib.rs index 7b88faf0..dcfd2495 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,10 +2,12 @@ #![deny(missing_debug_implementations)] #![deny(missing_docs)] +#![feature(conservative_impl_trait, try_from)] extern crate futures; extern crate hyper; -extern crate ruma_client_api; +extern crate ruma_api; +pub extern crate ruma_client_api; extern crate ruma_identifiers; extern crate serde; extern crate serde_json; @@ -13,22 +15,19 @@ extern crate serde_urlencoded; extern crate tokio_core; extern crate url; -use std::borrow::Cow; -use std::fmt::Debug; +use std::convert::{TryFrom, TryInto}; -use hyper::client::{Client as HyperClient, HttpConnector, Request as HyperRequest}; -use hyper::Method as HyperMethod; -use ruma_client_api::{Endpoint, Method}; -use ruma_client_api::unversioned::get_supported_versions; +use futures::{Future, IntoFuture}; +use hyper::{Client as HyperClient, Request as HyperRequest, Response as HyperResponse}; +use hyper::client::HttpConnector; +use ruma_api::Endpoint; use tokio_core::reactor::Handle; use url::Url; pub use error::Error; pub use session::Session; -pub use response::{FutureResponse, Response}; mod error; -mod response; mod session; /// A client for the Matrix client-server API. @@ -39,103 +38,34 @@ pub struct Client { session: Option, } -trait IntoHyperMethod { - fn into_hyper(self) -> HyperMethod; -} - -impl IntoHyperMethod for Method { - fn into_hyper(self) -> HyperMethod { - match self { - Method::Delete => HyperMethod::Delete, - Method::Get => HyperMethod::Get, - Method::Put => HyperMethod::Put, - Method::Post => HyperMethod::Post, - } - } -} - impl Client { /// Creates a new client for making requests to the given homeserver. - /// - /// # Errors - /// - /// Returns an error if the given homeserver URL cannot be parsed as a URL. - pub fn new(handle: &Handle, homeserver_url: U) -> Result where U: TryIntoUrl { - Ok(Client { - homeserver_url: homeserver_url.try_into()?, + pub fn new(handle: &Handle, homeserver_url: Url) -> Self { + Client { + homeserver_url, hyper: HyperClient::configure().keep_alive(true).build(handle), session: None, - }) - } - - /// Get the versions of the Matrix client-server specification supported by the homeserver. - pub fn get_supported_versions(&mut self) - -> Result::Response>, Error> { - self.request::(None, None, None) - } - - fn request( - &mut self, - body_params: Option, - path_params: Option, - query_params: Option, - ) -> Result, Error> - where E: Endpoint, ::Response: Debug + Send { - let path = match path_params { - Some(params) => Cow::from(E::request_path(params)), - None => Cow::from(E::router_path()), - }; - - let mut url = self.homeserver_url.join(path.as_ref())?.try_into()?; - - if let Some(params) = query_params { - url.set_query(Some(&serde_urlencoded::to_string(¶ms)?)); } + } - if E::requires_authentication() { - if let Some(ref session) = self.session { - url.query_pairs_mut().append_pair("access_token", &session.access_token); - } else { - return Err(Error::AuthenticationRequired); - } - } + /// Makes a request to a Matrix API endpoint. + pub fn request(&self, request: ::Request) + -> impl Future::Response, Error = Error> + where E: Endpoint, + ::Response: 'static, + Error: From<<::Request as TryInto>::Error>, + Error: From<<::Response as TryFrom>::Error> { + let cloned_hyper = self.hyper.clone(); - let mut request = HyperRequest::new(E::method().into_hyper(), url); - - match E::method() { - Method::Post | Method::Put => { - if let Some(params) = body_params { - request.set_body(serde_json::to_string(¶ms)?); - } - } - _ => {} - } - - Ok(FutureResponse::from(self.hyper.request(request))) - } -} - -/// Functionally equivalent to `TryInto`, and should be replaced by that as soon as it's -/// stable and available. -pub trait TryIntoUrl { - /// Performs the conversion. - fn try_into(self) -> Result; -} - -impl TryIntoUrl for String { - fn try_into(self) -> Result { - Url::parse(&self).map_err(Error::from) - } -} - -impl<'a> TryIntoUrl for &'a str { - fn try_into(self) -> Result { - Url::parse(self).map_err(Error::from) - } -} - -impl TryIntoUrl for Url { - fn try_into(self) -> Result { - Ok(self) + request + .try_into() + .map_err(Error::from) + .into_future() + .and_then(move |hyper_request| { + cloned_hyper.request(hyper_request).map_err(Error::from) + }) + .and_then(|hyper_response| { + hyper_response.try_into().map_err(Error::from) + }) } } diff --git a/src/response.rs b/src/response.rs deleted file mode 100644 index cb9753a0..00000000 --- a/src/response.rs +++ /dev/null @@ -1,90 +0,0 @@ -use std::fmt::Debug; -use std::io::Write; -use std::marker::PhantomData; - -use futures::{Async, Future, Poll, Stream}; -use hyper::client::{FutureResponse as HyperFutureResponse, Response as HyperResponse}; -use hyper::Error as HyperError; -use hyper::header::Headers; -use hyper::status::StatusCode; -use hyper::HttpVersion; -use serde::Deserialize; -use serde_json::from_slice; - -use Error; - -/// A `Future` that will resolve into a `Response`. -#[derive(Debug)] -pub struct FutureResponse where T: Debug + Deserialize + Send + 'static { - hyper_future_response: HyperFutureResponse, - phantom: PhantomData, -} - -/// A response from a Matrix homeserver. -#[derive(Debug)] -pub struct Response where T: Debug + Deserialize { - /// The Hyper response. - hyper_response: HyperResponse, - /// The response from the Matrix API. - phantom: PhantomData, -} - -impl Future for FutureResponse where T: Debug + Deserialize + Send + 'static { - type Item = Response; - type Error = Error; - - fn poll(&mut self) -> Poll { - match self.hyper_future_response.poll() { - Ok(Async::Ready(hyper_response)) => Ok(Async::Ready(Response { - hyper_response: hyper_response, - phantom: PhantomData, - })), - Ok(Async::NotReady) => Ok(Async::NotReady), - Err(error) => Err(Error::from(error)), - } - } -} - -impl From for FutureResponse -where T: Debug + Deserialize + Send + 'static { - fn from(hyper_future_response: HyperFutureResponse) -> FutureResponse { - FutureResponse { - hyper_future_response: hyper_future_response, - phantom: PhantomData, - } - } -} - -impl Response where T: Debug + Deserialize + Send + 'static { - /// The response from the Matrix API. - pub fn data(self) -> Box> { - let bytes = self.hyper_response.body().fold(Vec::new(), |mut bytes, chunk| { - if let Err(error) = bytes.write_all(&chunk) { - return Err(HyperError::from(error)); - } - - Ok(bytes) - }).map_err(Error::from); - - let deserialized_data = bytes.and_then(|bytes| { - from_slice(bytes.as_slice()).map_err(Error::from) - }); - - deserialized_data.boxed() - } - - /// The HTTP response code. - pub fn status(&self) -> &StatusCode { - self.hyper_response.status() - } - - /// The HTTP response headers. - pub fn headers(&self) -> &Headers { - self.hyper_response.headers() - } - - /// The HTTP version. - pub fn http_version(&self) -> &HttpVersion { - self.hyper_response.version() - } -} From b6f0d8d8b4895fd4ba247c3a801aa699e39717ea Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Fri, 12 May 2017 00:27:07 -0700 Subject: [PATCH 015/139] Use less verbose syntax for associated types. --- src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index dcfd2495..44fbb3b8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -50,11 +50,11 @@ impl Client { /// Makes a request to a Matrix API endpoint. pub fn request(&self, request: ::Request) - -> impl Future::Response, Error = Error> + -> impl Future where E: Endpoint, - ::Response: 'static, - Error: From<<::Request as TryInto>::Error>, - Error: From<<::Response as TryFrom>::Error> { + E::Response: 'static, + Error: From<>::Error>, + Error: From<>::Error> { let cloned_hyper = self.hyper.clone(); request From 86e837d26fb10fbe76976994935e38b46453bc4d Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Fri, 7 Jul 2017 23:19:12 -0700 Subject: [PATCH 016/139] Update dependencies, use published ruma crates, add new Client constructors. --- Cargo.toml | 32 ++++++++++++++----------- src/error.rs | 14 +++++------ src/lib.rs | 66 +++++++++++++++++++++++++++++++++++++--------------- 3 files changed, 72 insertions(+), 40 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 486c7300..9f1a1619 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,21 +11,25 @@ repository = "https://github.com/ruma/ruma-client" version = "0.1.0" [dependencies] -futures = "0.1.13" +futures = "0.1.14" +hyper = "0.11.1" +ruma-api = "0.4.0" +ruma-client-api = "0.1.0" ruma-identifiers = "0.11.0" -serde = "1.0.2" -serde_json = "1.0.1" -serde_urlencoded = "0.4.3" -tokio-core = "0.1.6" -url = "1.4.0" +serde = "1.0.9" +serde_json = "1.0.2" +serde_urlencoded = "0.5.1" +tokio-core = "0.1.8" +url = "1.5.1" -[dependencies.hyper] -git = "https://github.com/hyperium/hyper" -rev = "fed04dfb58e19b408322d4e5ca7474871e848a35" +[dependencies.hyper-tls] +optional = true +version = "0.1.2" -[dependencies.ruma-api] -git = "https://github.com/ruma/ruma-api" +[dependencies.native-tls] +optional = true +version = "0.1.4" -[dependencies.ruma-client-api] -git = "https://github.com/ruma/ruma-client-api" -branch = "manual" +[features] +default = ["tls"] +tls = ["hyper-tls", "native-tls"] diff --git a/src/error.rs b/src/error.rs index b2fecb50..1cc80fb7 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,5 +1,5 @@ use hyper::Error as HyperError; -use ruma_client_api::Error as RumaClientApiError; +use ruma_api::Error as RumaApiError; use serde_json::Error as SerdeJsonError; use serde_urlencoded::ser::Error as SerdeUrlEncodedSerializeError; use url::ParseError; @@ -7,18 +7,18 @@ use url::ParseError; /// An error that occurs during client operations. #[derive(Debug)] pub enum Error { + /// Queried endpoint requires authentication but was called on an anonymous client + AuthenticationRequired, /// An error at the HTTP layer. Hyper(HyperError), /// An error when parsing a string as a URL. Url(ParseError), /// An error converting between ruma_client_api types and Hyper types. - RumaClientApi(RumaClientApiError), + RumaApi(RumaApiError), /// An error when serializing or deserializing a JSON value. SerdeJson(SerdeJsonError), /// An error when serializing a query string value. SerdeUrlEncodedSerialize(SerdeUrlEncodedSerializeError), - /// Queried endpoint requires authentication but was called on an anonymous client - AuthenticationRequired, } impl From for Error { @@ -33,9 +33,9 @@ impl From for Error { } } -impl From for Error { - fn from(error: RumaClientApiError) -> Error { - Error::RumaClientApi(error) +impl From for Error { + fn from(error: RumaApiError) -> Error { + Error::RumaApi(error) } } diff --git a/src/lib.rs b/src/lib.rs index 44fbb3b8..d8450765 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,8 +6,10 @@ extern crate futures; extern crate hyper; +#[cfg(feature = "tls")] extern crate hyper_tls; +#[cfg(feature = "tls")] extern crate native_tls; extern crate ruma_api; -pub extern crate ruma_client_api; +extern crate ruma_client_api; extern crate ruma_identifiers; extern crate serde; extern crate serde_json; @@ -15,11 +17,14 @@ extern crate serde_urlencoded; extern crate tokio_core; extern crate url; -use std::convert::{TryFrom, TryInto}; +use std::convert::TryInto; +use std::rc::Rc; -use futures::{Future, IntoFuture}; -use hyper::{Client as HyperClient, Request as HyperRequest, Response as HyperResponse}; -use hyper::client::HttpConnector; +use futures::future::{Future, FutureFrom, IntoFuture}; +use hyper::{Client as HyperClient}; +use hyper::client::{Connect, HttpConnector}; +#[cfg(feature = "hyper-tls")] use hyper_tls::HttpsConnector; +#[cfg(feature = "hyper-tls")] use native_tls::Error as NativeTlsError; use ruma_api::Endpoint; use tokio_core::reactor::Handle; use url::Url; @@ -32,40 +37,63 @@ mod session; /// A client for the Matrix client-server API. #[derive(Debug)] -pub struct Client { +pub struct Client where C: Connect { homeserver_url: Url, - hyper: HyperClient, + hyper: Rc>, session: Option, } -impl Client { - /// Creates a new client for making requests to the given homeserver. +impl Client { + /// Creates a new client for making HTTP requests to the given homeserver. pub fn new(handle: &Handle, homeserver_url: Url) -> Self { Client { homeserver_url, - hyper: HyperClient::configure().keep_alive(true).build(handle), + hyper: Rc::new(HyperClient::configure().keep_alive(true).build(handle)), + session: None, + } + } +} + +#[cfg(feature = "tls")] +impl Client> { + /// Creates a new client for making HTTPS requests to the given homeserver. + pub fn https(handle: &Handle, homeserver_url: Url) -> Result { + let connector = HttpsConnector::new(4, handle)?; + + Ok(Client { + homeserver_url, + hyper: Rc::new(HyperClient::configure().connector(connector).keep_alive(true).build(handle)), + session: None, + }) + } +} + +impl Client where C: Connect { + /// Creates a new client using the given `hyper::Client`. + /// + /// This allows the user to configure the details of HTTP as desired. + pub fn custom(hyper_client: HyperClient, homeserver_url: Url) -> Self { + Client { + homeserver_url, + hyper: Rc::new(hyper_client), session: None, } } /// Makes a request to a Matrix API endpoint. - pub fn request(&self, request: ::Request) - -> impl Future + pub(crate) fn request<'a, E>(&'a self, request: ::Request) + -> impl Future + 'a where E: Endpoint, - E::Response: 'static, - Error: From<>::Error>, - Error: From<>::Error> { - let cloned_hyper = self.hyper.clone(); - + ::Response: 'a { request .try_into() .map_err(Error::from) .into_future() .and_then(move |hyper_request| { - cloned_hyper.request(hyper_request).map_err(Error::from) + self.hyper.clone().request(hyper_request).map_err(Error::from) }) .and_then(|hyper_response| { - hyper_response.try_into().map_err(Error::from) + E::Response::future_from(hyper_response).map_err(Error::from) }) } } From 60e4d9a86c0c5b101448f73171196f048dd49ae8 Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Fri, 7 Jul 2017 23:20:42 -0700 Subject: [PATCH 017/139] Add an API module to expose endpoints. --- src/api.rs | 19 +++++++++++++++++++ src/lib.rs | 2 ++ 2 files changed, 21 insertions(+) create mode 100644 src/api.rs diff --git a/src/api.rs b/src/api.rs new file mode 100644 index 00000000..7568faaf --- /dev/null +++ b/src/api.rs @@ -0,0 +1,19 @@ +/// Endpoints that cannot change with new versions of the Matrix specification. +pub mod unversioned { + /// [GET /_matrix/client/versions](https://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-versions) + pub mod get_supported_versions { + use futures::Future; + use hyper::client::Connect; + use ruma_client_api::unversioned::get_supported_versions::Endpoint; + pub use ruma_client_api::unversioned::get_supported_versions::{Request, Response}; + + use {Client, Error}; + + /// Make a request to this API endpoint. + pub fn call<'a, C>(client: &'a Client, request: Request) + -> impl Future + 'a + where C: Connect { + client.request::(request) + } + } +} diff --git a/src/lib.rs b/src/lib.rs index d8450765..f171f476 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,6 +32,8 @@ use url::Url; pub use error::Error; pub use session::Session; +/// Matrix client-server API endpoints. +pub mod api; mod error; mod session; From 3b059d1735b6d637a22bfffab358e002af69d1a6 Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Fri, 7 Jul 2017 23:24:37 -0700 Subject: [PATCH 018/139] Run rustfmt. --- src/api.rs | 10 +++++++--- src/lib.rs | 48 +++++++++++++++++++++++++++++++++++------------- 2 files changed, 42 insertions(+), 16 deletions(-) diff --git a/src/api.rs b/src/api.rs index 7568faaf..6677497a 100644 --- a/src/api.rs +++ b/src/api.rs @@ -10,9 +10,13 @@ pub mod unversioned { use {Client, Error}; /// Make a request to this API endpoint. - pub fn call<'a, C>(client: &'a Client, request: Request) - -> impl Future + 'a - where C: Connect { + pub fn call<'a, C>( + client: &'a Client, + request: Request, + ) -> impl Future + 'a + where + C: Connect, + { client.request::(request) } } diff --git a/src/lib.rs b/src/lib.rs index f171f476..e221c88c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,8 +6,10 @@ extern crate futures; extern crate hyper; -#[cfg(feature = "tls")] extern crate hyper_tls; -#[cfg(feature = "tls")] extern crate native_tls; +#[cfg(feature = "tls")] +extern crate hyper_tls; +#[cfg(feature = "tls")] +extern crate native_tls; extern crate ruma_api; extern crate ruma_client_api; extern crate ruma_identifiers; @@ -21,10 +23,12 @@ use std::convert::TryInto; use std::rc::Rc; use futures::future::{Future, FutureFrom, IntoFuture}; -use hyper::{Client as HyperClient}; +use hyper::Client as HyperClient; use hyper::client::{Connect, HttpConnector}; -#[cfg(feature = "hyper-tls")] use hyper_tls::HttpsConnector; -#[cfg(feature = "hyper-tls")] use native_tls::Error as NativeTlsError; +#[cfg(feature = "hyper-tls")] +use hyper_tls::HttpsConnector; +#[cfg(feature = "hyper-tls")] +use native_tls::Error as NativeTlsError; use ruma_api::Endpoint; use tokio_core::reactor::Handle; use url::Url; @@ -39,7 +43,10 @@ mod session; /// A client for the Matrix client-server API. #[derive(Debug)] -pub struct Client where C: Connect { +pub struct Client +where + C: Connect, +{ homeserver_url: Url, hyper: Rc>, session: Option, @@ -64,13 +71,21 @@ impl Client> { Ok(Client { homeserver_url, - hyper: Rc::new(HyperClient::configure().connector(connector).keep_alive(true).build(handle)), + hyper: Rc::new( + HyperClient::configure() + .connector(connector) + .keep_alive(true) + .build(handle), + ), session: None, }) } } -impl Client where C: Connect { +impl Client +where + C: Connect, +{ /// Creates a new client using the given `hyper::Client`. /// /// This allows the user to configure the details of HTTP as desired. @@ -83,16 +98,23 @@ impl Client where C: Connect { } /// Makes a request to a Matrix API endpoint. - pub(crate) fn request<'a, E>(&'a self, request: ::Request) - -> impl Future + 'a - where E: Endpoint, - ::Response: 'a { + pub(crate) fn request<'a, E>( + &'a self, + request: ::Request, + ) -> impl Future + 'a + where + E: Endpoint, + ::Response: 'a, + { request .try_into() .map_err(Error::from) .into_future() .and_then(move |hyper_request| { - self.hyper.clone().request(hyper_request).map_err(Error::from) + self.hyper + .clone() + .request(hyper_request) + .map_err(Error::from) }) .and_then(|hyper_response| { E::Response::future_from(hyper_response).map_err(Error::from) From da5ce8ee117ceecc591ba99bfa456a789ab04101 Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Fri, 7 Jul 2017 23:36:05 -0700 Subject: [PATCH 019/139] Set the path and query string before making a request. --- src/error.rs | 10 +++++++++- src/lib.rs | 17 +++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/src/error.rs b/src/error.rs index 1cc80fb7..91fdccbb 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,4 +1,4 @@ -use hyper::Error as HyperError; +use hyper::error::{Error as HyperError, UriError}; use ruma_api::Error as RumaApiError; use serde_json::Error as SerdeJsonError; use serde_urlencoded::ser::Error as SerdeUrlEncodedSerializeError; @@ -11,6 +11,8 @@ pub enum Error { AuthenticationRequired, /// An error at the HTTP layer. Hyper(HyperError), + /// An error when parsing a string as a URI. + Uri(UriError), /// An error when parsing a string as a URL. Url(ParseError), /// An error converting between ruma_client_api types and Hyper types. @@ -27,6 +29,12 @@ impl From for Error { } } +impl From for Error { + fn from(error: UriError) -> Error { + Error::Uri(error) + } +} + impl From for Error { fn from(error: ParseError) -> Error { Error::Url(error) diff --git a/src/lib.rs b/src/lib.rs index e221c88c..9afdaf52 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -106,11 +106,28 @@ where E: Endpoint, ::Response: 'a, { + let mut url = self.homeserver_url.clone(); + request .try_into() .map_err(Error::from) .into_future() .and_then(move |hyper_request| { + { + let uri = hyper_request.uri(); + + url.set_path(uri.path()); + url.set_query(uri.query()); + } + + url.into_string() + .parse() + .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() .request(hyper_request) From e509f80cdfa7527aaae275b6cea91d2bed9d4610 Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Fri, 7 Jul 2017 23:49:34 -0700 Subject: [PATCH 020/139] Use a reference to convert Url into Uri. See: https://github.com/hyperium/hyper/issues/1089#issuecomment-288842526 --- src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 9afdaf52..886321dd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -21,9 +21,10 @@ extern crate url; use std::convert::TryInto; use std::rc::Rc; +use std::str::FromStr; use futures::future::{Future, FutureFrom, IntoFuture}; -use hyper::Client as HyperClient; +use hyper::{Client as HyperClient, Uri}; use hyper::client::{Connect, HttpConnector}; #[cfg(feature = "hyper-tls")] use hyper_tls::HttpsConnector; @@ -120,8 +121,7 @@ where url.set_query(uri.query()); } - url.into_string() - .parse() + Uri::from_str(url.as_ref()) .map(move |uri| (uri, hyper_request)) .map_err(Error::from) }) From d25b97227778f278827e2562c31c97c58409ac94 Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Sat, 8 Jul 2017 17:47:11 -0700 Subject: [PATCH 021/139] Expose all endpoints from ruma-client-api. --- src/api.rs | 540 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 522 insertions(+), 18 deletions(-) diff --git a/src/api.rs b/src/api.rs index 6677497a..f7eb38cb 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1,23 +1,527 @@ -/// Endpoints that cannot change with new versions of the Matrix specification. -pub mod unversioned { - /// [GET /_matrix/client/versions](https://matrix.org/docs/spec/client_server/r0.2.0.html#get-matrix-client-versions) - pub mod get_supported_versions { - use futures::Future; - use hyper::client::Connect; - use ruma_client_api::unversioned::get_supported_versions::Endpoint; - pub use ruma_client_api::unversioned::get_supported_versions::{Request, Response}; +macro_rules! endpoint { + // No reexports besides `Request` and `Response`. + ($(#[$attr:meta])+ [$($outer_mod:ident),*], $inner_mod:ident) => { + endpoint!($(#[$attr])+ [$($outer_mod),*], $inner_mod, []); + }; - use {Client, Error}; + // No imports from super. + ($(#[$attr:meta])+ [$($outer_mod:ident),*], $inner_mod:ident, [$($import:ident),*]) => { + endpoint!($(#[$attr])+ [$($outer_mod),*], $inner_mod, [], []); + }; - /// Make a request to this API endpoint. - pub fn call<'a, C>( - client: &'a Client, - request: Request, - ) -> impl Future + 'a - where - C: Connect, - { - client.request::(request) + // Explicit case. + ( + $(#[$attr:meta])+ + [$($outer_mod:ident),*], + $inner_mod:ident, + [$($import:ident),*], + [$($super_import:ident),*] + ) => { + #[$($attr)+] + pub mod $inner_mod { + use futures::Future; + use hyper::client::Connect; + use ruma_client_api::$($outer_mod::)*$inner_mod::Endpoint; + $(use super::$super_import;)* + pub use ruma_client_api::$($outer_mod::)*$inner_mod::{ + Request, + Response, + $($import),* + }; + + use {Client, Error}; + + /// Make a request to this API endpoint. + pub fn call<'a, C>( + client: &'a Client, + request: Request, + ) -> impl Future + 'a + where + C: Connect, + { + client.request::(request) + } } + }; +} + +/// Endpoints for the r0.x.x versions of the client API specification. +pub mod r0 { + /// Account registration and management. + pub mod account { + endpoint!( + /// Change the password for an account on this homeserver. + [r0, account], + change_password + ); + + endpoint!( + /// Deactivate the user's account, removing all ability for the user to log in again. + [r0, account], + deactivate + ); + + endpoint!( + /// Register for an account on this homeserver. + [r0, account], + register, + [AuthenticationData, RegistrationKind] + ); + + endpoint!( + /// Request a password change token by email. + [r0, account], + request_password_change_token + ); + + endpoint!( + /// Request an account registration token by email. + [r0, account], + request_register_token + ); + } + + /// Room aliases. + pub mod alias { + endpoint!( + /// Create a new mapping from a room alias to a room ID. + [r0, alias], + create_alias + ); + + endpoint!( + /// Remove a mapping from a room alias to a room ID. + [r0, alias], + delete_alias + ); + + endpoint!( + /// Resolve a room alias to the corresponding room ID. + [r0, alias], + get_alias + ); + } + + /// Client configuration. + pub mod config { + endpoint!( + /// Set account data for the user. + [r0, config], + set_global_account_data + ); + + endpoint!( + /// Set account data scoped to a room for the user. + [r0, config], + set_room_account_data + ); + } + + /// Account contact information. + pub mod contact { + endpoint!( + /// Add contact information to the user's account. + [r0, contact], + create_contact, + [ThreePidCredentials] + ); + + endpoint!( + /// Get a list of the third party identifiers that the homeserver has associated with the user's account. + [r0, contact], + get_contacts, + [Medium, ThirdPartyIdentifier] + ); + + endpoint!( + /// Request an email address verification token by email. + [r0, contact], + request_contact_verification_token + ); + } + + /// Event context. + pub mod context { + endpoint!( + /// Get a number of events that happened just before and after a given event. + [r0, context], + get_context + ); + } + + /// The public room directory. + pub mod directory { + endpoint!( + /// Get a number of events that happened just before and after a given event. + [r0, directory], + get_public_rooms, + [PublicRoomsChunk] + ); + } + + /// Event filters. + pub mod filter { + pub use ruma_client_api::r0::filter::{ + EventFormat, + Filter, + FilterDefinition, + RoomEventFilter, + RoomFilter, + }; + + endpoint!( + /// Create a new filter. + [r0, filter], + create_filter + ); + + endpoint!( + /// Get a filter. + [r0, filter], + get_filter + ); + } + + /// Media repository. + pub mod media { + endpoint!( + /// Upload media to the media repository. + [r0, media], + create_content + ); + + endpoint!( + /// Download media from the media repository. + [r0, media], + get_content + ); + + endpoint!( + /// Download a thumbnail image for the media in the media repository. + [r0, media], + get_content_thumbnail, + [Method] + ); + } + + /// Room membership. + pub mod membership { + pub use ruma_client_api::r0::membership::ThirdPartySigned; + + endpoint!( + /// Ban a user from a room. + [r0, membership], + ban_user + ); + + endpoint!( + /// Permanently forget a room. + [r0, membership], + forget_room + ); + + endpoint!( + /// Invite a user to a room. + [r0, membership], + invite_user + ); + + endpoint!( + /// Join a room using its ID. + [r0, membership], + join_room_by_id + ); + + endpoint!( + /// Join a room using its ID or an alias. + [r0, membership], + join_room_by_id_or_alias + ); + + endpoint!( + /// Kick a user from a room. + [r0, membership], + kick_user + ); + + endpoint!( + /// Leave a room. + [r0, membership], + leave_room + ); + + endpoint!( + /// Unban a user from a room. + [r0, membership], + unban_user + ); + } + + /// User presence. + pub mod presence { + endpoint!( + /// Get a user's presence state. + [r0, presence], + get_presence + ); + + endpoint!( + /// Get a list of presence events for users on the presence subscription list. + [r0, presence], + get_subscribed_presences + ); + + endpoint!( + /// Set a user's presence state. + [r0, presence], + set_presence + ); + + endpoint!( + /// Add or remove users from the presence subscription list. + [r0, presence], + update_presence_subscriptions + ); + } + + /// User profiles. + pub mod profile { + endpoint!( + /// Get the URL for a user's avatar. + [r0, profile], + get_avatar_url + ); + + endpoint!( + /// Get a user's display name. + [r0, profile], + get_display_name + ); + + endpoint!( + /// Get a user's full profile. + [r0, profile], + get_profile + ); + + endpoint!( + /// Set the URL to the user's avatar. + [r0, profile], + set_avatar_url + ); + + endpoint!( + /// Set the user's display name. + [r0, profile], + set_display_name + ); + } + + /// Push notifications. + pub mod push { + } + + /// Event receipts. + pub mod receipt { + endpoint!( + /// Update a receipt marker to point to a given event. + [r0, receipt], + create_receipt, + [ReceiptType] + ); + } + + /// Event redaction. + pub mod redact { + endpoint!( + /// Redact an event from a room. + [r0, redact], + redact_event + ); + } + + /// Room creation. + pub mod room { + endpoint!( + /// Create a room. + [r0, room], + create_room, + [CreationContent, RoomPreset, Visibility] + ); + } + + /// Event searches. + pub mod search { + endpoint!( + /// Search for events. + [r0, search], + search_events, + [ + Categories, + Criteria, + EventContext, + EventContextResult, + Grouping, + Groupings, + ResultCategories, + ResultGroup, + RoomEventResults, + SearchResult, + UserProfile, + GroupingKey, + OrderBy, + SearchKeys + ] + ); + } + + /// Sending events. + pub mod send { + endpoint!( + /// Send a message to a room. + [r0, send], + send_message_event + ); + + endpoint!( + /// Send a state event with an empty state key. + [r0, send], + send_state_event_for_empty_key + ); + + endpoint!( + /// Send a state event with a particular state key. + [r0, send], + send_state_event_for_key + ); + } + + /// Server administration. + pub mod server { + endpoint!( + /// Get administrative information about a user. + [r0, server], + get_user_info, + [ConnectionInfo, DeviceInfo, SessionInfo] + ); + } + + /// User session management. + pub mod session { + endpoint!( + /// Log in to an account, creating an access token. + [r0, session], + login, + [LoginType, Medium] + ); + + endpoint!( + /// Log out of an account by invalidating the access token. + [r0, session], + logout + ); + } + + /// Getting and synchronizing events. + pub mod sync { + endpoint!( + /// Get the list of members for a room. + [r0, sync], + get_member_events + ); + + endpoint!( + /// Get message and state events for a room. + [r0, sync], + get_message_events, + [Direction] + ); + + endpoint!( + /// Get the state events for the current state of a room. + [r0, sync], + get_state_events + ); + + endpoint!( + /// Get a particular state event with an empty state key for a room. + [r0, sync], + get_state_events_for_empty_key + ); + + endpoint!( + /// Get a particular state event with a particular state key for a room. + [r0, sync], + get_state_events_for_key + ); + + endpoint!( + /// Synchronize the client's state with the latest state on the homeserver. + [r0, sync], + sync_events, + [ + AccountData, + Ephemeral, + Filter, + InviteState, + InvitedRoom, + JoinedRoom, + LeftRoom, + Presence, + Rooms, + SetPresence, + State, + Timeline, + UnreadNotificationsCount + ] + ); + } + + /// Tagging rooms. + pub mod tag { + endpoint!( + /// Create a tag on a room. + [r0, tag], + create_tag + ); + + endpoint!( + /// Delete a tag on a room. + [r0, tag], + delete_tag + ); + + endpoint!( + /// Get the user's tags for a room. + [r0, tag], + get_tags + ); + } + + /// Typing notifications. + pub mod typing { + endpoint!( + /// Indicate that the user is currently typing. + [r0, typing], + create_typing_event + ); + } + + /// Voice over IP. + pub mod voip { + endpoint!( + /// Get credentials for initiating voice over IP calls via a TURN server. + [r0, voip], + get_turn_server_info + ); } } + +/// Endpoints that cannot change with new versions of the Matrix specification. +pub mod unversioned { + endpoint!( + /// Get the versions of the specification supported by this homeserver. + [unversioned], + get_supported_versions + ); +} From feaadff8db033ab963c3de424afc9cddd92fefdd Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Sat, 8 Jul 2017 22:41:11 -0700 Subject: [PATCH 022/139] Pass local imports to the more explicit version of the endpoint macro. --- src/api.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api.rs b/src/api.rs index f7eb38cb..4049e448 100644 --- a/src/api.rs +++ b/src/api.rs @@ -6,7 +6,7 @@ macro_rules! endpoint { // No imports from super. ($(#[$attr:meta])+ [$($outer_mod:ident),*], $inner_mod:ident, [$($import:ident),*]) => { - endpoint!($(#[$attr])+ [$($outer_mod),*], $inner_mod, [], []); + endpoint!($(#[$attr])+ [$($outer_mod),*], $inner_mod, [$($import),*], []); }; // Explicit case. From 6d1c167efbb2010f1bbd0559bd60d690b867591c Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Sat, 8 Jul 2017 23:25:29 -0700 Subject: [PATCH 023/139] Simplify `Session` and authenticate requests when required. --- src/lib.rs | 22 +++++++++++++++------- src/session.rs | 35 ++++++++++++++++++++++++++--------- 2 files changed, 41 insertions(+), 16 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 886321dd..efd6cf3a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -43,7 +43,7 @@ mod error; mod session; /// A client for the Matrix client-server API. -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct Client where C: Connect, @@ -55,11 +55,11 @@ where impl Client { /// Creates a new client for making HTTP requests to the given homeserver. - pub fn new(handle: &Handle, homeserver_url: Url) -> Self { + pub fn new(handle: &Handle, homeserver_url: Url, session: Option) -> Self { Client { homeserver_url, hyper: Rc::new(HyperClient::configure().keep_alive(true).build(handle)), - session: None, + session, } } } @@ -67,7 +67,7 @@ impl Client { #[cfg(feature = "tls")] impl Client> { /// Creates a new client for making HTTPS requests to the given homeserver. - pub fn https(handle: &Handle, homeserver_url: Url) -> Result { + pub fn https(handle: &Handle, homeserver_url: Url, session: Option) -> Result { let connector = HttpsConnector::new(4, handle)?; Ok(Client { @@ -78,7 +78,7 @@ impl Client> { .keep_alive(true) .build(handle), ), - session: None, + session, }) } } @@ -90,11 +90,11 @@ where /// Creates a new client using the given `hyper::Client`. /// /// This allows the user to configure the details of HTTP as desired. - pub fn custom(hyper_client: HyperClient, homeserver_url: Url) -> Self { + pub fn custom(hyper_client: HyperClient, homeserver_url: Url, session: Option) -> Self { Client { homeserver_url, hyper: Rc::new(hyper_client), - session: None, + session, } } @@ -119,6 +119,14 @@ where url.set_path(uri.path()); url.set_query(uri.query()); + + if E::METADATA.requires_authentication { + if let Some(ref session) = self.session { + url.query_pairs_mut().append_pair("access_token", session.access_token()); + } else { + return Err(Error::AuthenticationRequired); + } + } } Uri::from_str(url.as_ref()) diff --git a/src/session.rs b/src/session.rs index 7e450741..388567d4 100644 --- a/src/session.rs +++ b/src/session.rs @@ -1,13 +1,30 @@ use ruma_identifiers::UserId; -use url::Host; -/// An active user session with a Matrix homeserver, allowing authenticated requests. -#[derive(Clone, Debug)] +/// A user session, containing an access token and information about the associated user account. +#[derive(Clone, Debug, Eq, Hash, PartialEq)] pub struct Session { - /// The access token of this session - pub access_token: String, - /// The homeserver this session is associated with - pub homeserver: Host, - /// the ID of the user owning this session - pub user_id: UserId, + /// The access token used for this session. + access_token: String, + /// The user the access token was issued for. + user_id: UserId, +} + +impl Session { + /// Create a new user session from an access token and a user ID. + pub fn new(access_token: String, user_id: UserId) -> Self { + Session { + access_token, + user_id, + } + } + + /// Get the access token associated with this session. + pub fn access_token(&self) -> &str { + &self.access_token + } + + /// Get the ID of the user the session belongs to. + pub fn user_id(&self) -> &UserId { + &self.user_id + } } From 39bd63d5769341db34e22e14ec074ca89413d8d1 Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Sun, 9 Jul 2017 01:22:56 -0700 Subject: [PATCH 024/139] Add `Client::log_in`. --- src/lib.rs | 30 +++++++++++++++++++++++++----- 1 file changed, 25 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index efd6cf3a..bae4d650 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,6 +19,7 @@ extern crate serde_urlencoded; extern crate tokio_core; extern crate url; +use std::cell::RefCell; use std::convert::TryInto; use std::rc::Rc; use std::str::FromStr; @@ -34,6 +35,7 @@ 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; @@ -50,7 +52,7 @@ where { homeserver_url: Url, hyper: Rc>, - session: Option, + session: RefCell>, } impl Client { @@ -59,7 +61,7 @@ impl Client { Client { homeserver_url, hyper: Rc::new(HyperClient::configure().keep_alive(true).build(handle)), - session, + session: RefCell::new(session), } } } @@ -78,7 +80,7 @@ impl Client> { .keep_alive(true) .build(handle), ), - session, + session: RefCell::new(session), }) } } @@ -94,10 +96,28 @@ where Client { homeserver_url, hyper: Rc::new(hyper_client), - session, + session: RefCell::new(session), } } + /// Log in to the homeserver with a username and password. + pub fn log_in<'a>(&'a self, user: String, password: String) + -> impl Future + 'a { + let request = login::Request { + address: None, + login_type: login::LoginType::Password, + medium: None, + password, + user, + }; + + login::call(self, request).and_then(move |response| { + *self.session.borrow_mut() = Some(Session::new(response.access_token, response.user_id)); + + Ok(()) + }) + } + /// Makes a request to a Matrix API endpoint. pub(crate) fn request<'a, E>( &'a self, @@ -121,7 +141,7 @@ where url.set_query(uri.query()); if E::METADATA.requires_authentication { - if let Some(ref session) = self.session { + if let Some(ref session) = *self.session.borrow() { url.query_pairs_mut().append_pair("access_token", session.access_token()); } else { return Err(Error::AuthenticationRequired); From e734de5d442c581c37e38dc1733c9f125c8e98aa Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sun, 9 Jul 2017 18:53:33 +1000 Subject: [PATCH 025/139] 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 026/139] 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 027/139] 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 028/139] 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 029/139] 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 030/139] 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 031/139] 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 032/139] 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 033/139] 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 034/139] 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 035/139] 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 036/139] 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 037/139] 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 038/139] 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 039/139] 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(); } From bb96b002d8c2b31097f4c5a3181c1fe13acab825 Mon Sep 17 00:00:00 2001 From: Florian Jacob Date: Thu, 17 May 2018 17:37:58 +0200 Subject: [PATCH 040/139] [feature(conservative_impl_trait)] is stable since rust 1.26 --- examples/hello_world.rs | 1 - examples/hello_world_await.rs | 1 - src/lib.rs | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/examples/hello_world.rs b/examples/hello_world.rs index e444eeee..6039ee50 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -1,4 +1,3 @@ -#![feature(conservative_impl_trait)] #![feature(try_from)] extern crate futures; diff --git a/examples/hello_world_await.rs b/examples/hello_world_await.rs index cd5dd3f5..16c81061 100644 --- a/examples/hello_world_await.rs +++ b/examples/hello_world_await.rs @@ -1,4 +1,3 @@ -#![feature(conservative_impl_trait)] #![feature(generators)] #![feature(proc_macro)] #![feature(try_from)] diff --git a/src/lib.rs b/src/lib.rs index 836d68dd..a16c6789 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,7 @@ #![deny(missing_debug_implementations)] #![deny(missing_docs)] -#![feature(conservative_impl_trait, try_from)] +#![feature(try_from)] extern crate futures; extern crate hyper; From 66037a93391fc569679c00cce7cab65ba0235daf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Sommer?= Date: Sat, 25 Aug 2018 16:08:51 +0200 Subject: [PATCH 041/139] Update of hyper * hyper::UriError was moved to http::InvalidUri * tokio_core::reactor::Handle is no longer used by the new hyper version; tokio_core can get dropped completely --- Cargo.toml | 8 ++++---- src/api.rs | 4 ++-- src/error.rs | 9 +++++---- src/lib.rs | 23 +++++++++++------------ 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 64458347..071c2868 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,22 +12,22 @@ version = "0.1.0" [dependencies] futures = "0.1.14" -hyper = "0.11.1" +http = "0.1" +hyper = "0.12" ruma-api = "0.4.0" ruma-client-api = "0.1.0" ruma-identifiers = "0.11.0" serde_json = "1.0.2" serde_urlencoded = "0.5.1" -tokio-core = "0.1.8" url = "1.5.1" [dependencies.hyper-tls] optional = true -version = "0.1.2" +version = "0.3.0" [dependencies.native-tls] optional = true -version = "0.1.4" +version = "0.2.1" [dev-dependencies] futures-await = { git = 'https://github.com/alexcrichton/futures-await' } diff --git a/src/api.rs b/src/api.rs index 2983a307..2dbeb926 100644 --- a/src/api.rs +++ b/src/api.rs @@ -20,7 +20,7 @@ macro_rules! endpoint { #[$($attr)+] pub mod $inner_mod { use futures::Future; - use hyper::client::Connect; + use hyper::client::connect::Connect; use ruma_client_api::$($outer_mod::)*$inner_mod::Endpoint; $(use super::$super_import;)* pub use ruma_client_api::$($outer_mod::)*$inner_mod::{ @@ -37,7 +37,7 @@ macro_rules! endpoint { request: Request, ) -> impl Future where - C: Connect, + C: Connect + 'static, { client.request::(request) } diff --git a/src/error.rs b/src/error.rs index 91fdccbb..f6ca9384 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,4 +1,5 @@ -use hyper::error::{Error as HyperError, UriError}; +use http::uri::InvalidUri; +use hyper::error::Error as HyperError; use ruma_api::Error as RumaApiError; use serde_json::Error as SerdeJsonError; use serde_urlencoded::ser::Error as SerdeUrlEncodedSerializeError; @@ -12,7 +13,7 @@ pub enum Error { /// An error at the HTTP layer. Hyper(HyperError), /// An error when parsing a string as a URI. - Uri(UriError), + Uri(InvalidUri), /// An error when parsing a string as a URL. Url(ParseError), /// An error converting between ruma_client_api types and Hyper types. @@ -29,8 +30,8 @@ impl From for Error { } } -impl From for Error { - fn from(error: UriError) -> Error { +impl From for Error { + fn from(error: InvalidUri) -> Error { Error::Uri(error) } } diff --git a/src/lib.rs b/src/lib.rs index a16c6789..338c823e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ #![feature(try_from)] extern crate futures; +extern crate http; extern crate hyper; #[cfg(feature = "tls")] extern crate hyper_tls; @@ -15,7 +16,6 @@ extern crate ruma_client_api; extern crate ruma_identifiers; extern crate serde_json; extern crate serde_urlencoded; -extern crate tokio_core; extern crate url; use std::cell::RefCell; @@ -26,13 +26,13 @@ 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}; +use hyper::client::HttpConnector; +use hyper::client::connect::Connect; #[cfg(feature = "hyper-tls")] use hyper_tls::HttpsConnector; #[cfg(feature = "hyper-tls")] use native_tls::Error as NativeTlsError; use ruma_api::Endpoint; -use tokio_core::reactor::Handle; use url::Url; pub use error::Error; @@ -60,10 +60,10 @@ where 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 { + pub fn new(homeserver_url: Url, session: Option) -> Self { Client(Rc::new(ClientData { homeserver_url: homeserver_url, - hyper: HyperClient::configure().keep_alive(true).build(handle), + hyper: HyperClient::builder().keep_alive(true).build_http(), session: RefCell::new(session), })) } @@ -72,16 +72,15 @@ impl Client { #[cfg(feature = "tls")] impl Client> { /// Creates a new client for making HTTPS requests to the given homeserver. - pub fn https(handle: &Handle, homeserver_url: Url, session: Option) -> Result { - let connector = HttpsConnector::new(4, handle)?; + pub fn https(homeserver_url: Url, session: Option) -> Result { + let connector = HttpsConnector::new(4)?; Ok(Client(Rc::new(ClientData { homeserver_url: homeserver_url, hyper: { - HyperClient::configure() - .connector(connector) + HyperClient::builder() .keep_alive(true) - .build(handle) + .build(connector) }, session: RefCell::new(session), }))) @@ -90,7 +89,7 @@ impl Client> { impl Client where - C: Connect, + C: Connect + 'static, { /// Creates a new client using the given `hyper::Client`. /// @@ -261,7 +260,7 @@ where .map_err(Error::from) }) .and_then(move |(uri, mut hyper_request)| { - hyper_request.set_uri(uri); + *hyper_request.uri_mut() = uri; data2.hyper .request(hyper_request) From 04af2e41b4a7d36d33f8dfd462a81d4adb02b266 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Sommer?= Date: Fri, 31 Aug 2018 17:42:47 +0200 Subject: [PATCH 042/139] Client.log_in: Add parameter `device_id` This parameter was added to the request. https://github.com/ruma/ruma-client-api/commit/a7bce18b59fba5d5faa3e0621a7d885cc7c20071 --- src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 338c823e..b2cc3076 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -107,7 +107,7 @@ 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(&self, user: String, password: String) + pub fn log_in(&self, user: String, password: String, device_id: Option) -> impl Future { use api::r0::session::login; @@ -117,6 +117,7 @@ where address: None, login_type: login::LoginType::Password, medium: None, + device_id, password, user, }).map(move |response| { From a0ce0a9da89a61606ac2f783bacf776965bae014 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Sommer?= Date: Fri, 31 Aug 2018 15:57:56 +0200 Subject: [PATCH 043/139] Update examples --- Cargo.toml | 3 ++- examples/hello_world.rs | 13 +++++-------- examples/hello_world_await.rs | 18 +++++++----------- 3 files changed, 14 insertions(+), 20 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 071c2868..84b025dd 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,7 +31,8 @@ version = "0.2.1" [dev-dependencies] futures-await = { git = 'https://github.com/alexcrichton/futures-await' } -ruma-events = "0.9.0" +ruma-events = "0.10" +tokio-core = "0.1" [features] default = ["tls"] diff --git a/examples/hello_world.rs b/examples/hello_world.rs index 6039ee50..0667cc24 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -17,7 +17,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, Handle}; +use tokio_core::reactor::Core; use url::Url; // from https://stackoverflow.com/a/43992218/1592377 @@ -40,11 +40,10 @@ 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(); + let client = Client::https(homeserver_url, None).unwrap(); client.register_guest().and_then(clone!(client => move |_| { r0::alias::get_alias::call(client, r0::alias::get_alias::Request { @@ -79,9 +78,7 @@ fn main() { } }; - let mut core = Core::new().unwrap(); - let handle = core.handle(); - let server = Url::parse(&homeserver_url).unwrap(); - - core.run(hello_world(&handle, server, room)).unwrap(); + Core::new().unwrap() + .run(hello_world(homeserver_url.parse().unwrap(), room)) + .unwrap(); } diff --git a/examples/hello_world_await.rs b/examples/hello_world_await.rs index 16c81061..124c8283 100644 --- a/examples/hello_world_await.rs +++ b/examples/hello_world_await.rs @@ -1,5 +1,5 @@ #![feature(generators)] -#![feature(proc_macro)] +#![feature(proc_macro_non_items)] #![feature(try_from)] extern crate futures_await as futures; @@ -13,21 +13,20 @@ use std::convert::TryFrom; use std::env; use std::process::exit; -use futures::prelude::*; +use futures::prelude::{*, await}; 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, Handle}; +use tokio_core::reactor::Core; 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(); + let client = Client::https(homeserver_url, None).unwrap(); async_block! { await!(client.register_guest())?; @@ -75,10 +74,7 @@ fn main() { } }; - - let mut core = Core::new().unwrap(); - let handle = core.handle(); - let server = Url::parse(&homeserver_url).unwrap(); - - core.run(hello_world(&handle, server, room)).unwrap(); + Core::new().unwrap() + .run(hello_world(homeserver_url.parse().unwrap(), room)) + .unwrap(); } From 5fb288fc669b26291f16a2953a9b06f622092b2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Sommer?= Date: Fri, 31 Aug 2018 16:52:39 +0200 Subject: [PATCH 044/139] Cleanup the examples a little bit They run fine without this code. --- examples/hello_world.rs | 9 +-------- examples/hello_world_await.rs | 2 +- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/examples/hello_world.rs b/examples/hello_world.rs index 0667cc24..44c22e91 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -21,16 +21,9 @@ use tokio_core::reactor::Core; use url::Url; // 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(); )+ @@ -42,7 +35,7 @@ macro_rules! clone { fn hello_world( homeserver_url: Url, room: String, -) -> impl Future + 'static { +) -> impl Future { let client = Client::https(homeserver_url, None).unwrap(); client.register_guest().and_then(clone!(client => move |_| { diff --git a/examples/hello_world_await.rs b/examples/hello_world_await.rs index 124c8283..4e321da2 100644 --- a/examples/hello_world_await.rs +++ b/examples/hello_world_await.rs @@ -25,7 +25,7 @@ use url::Url; fn hello_world( homeserver_url: Url, room: String, -) -> impl Future + 'static { +) -> impl Future { let client = Client::https(homeserver_url, None).unwrap(); async_block! { From a01702093e4406128d69689141caec9dbd7310bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Sommer?= Date: Fri, 31 Aug 2018 16:54:14 +0200 Subject: [PATCH 045/139] Make cargo-clippy happy --- src/lib.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b2cc3076..eda19f68 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -62,7 +62,7 @@ impl Client { /// Creates a new client for making HTTP requests to the given homeserver. pub fn new(homeserver_url: Url, session: Option) -> Self { Client(Rc::new(ClientData { - homeserver_url: homeserver_url, + homeserver_url, hyper: HyperClient::builder().keep_alive(true).build_http(), session: RefCell::new(session), })) @@ -76,7 +76,7 @@ impl Client> { let connector = HttpsConnector::new(4)?; Ok(Client(Rc::new(ClientData { - homeserver_url: homeserver_url, + homeserver_url, hyper: { HyperClient::builder() .keep_alive(true) @@ -96,7 +96,7 @@ 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(Rc::new(ClientData { - homeserver_url: homeserver_url, + homeserver_url, hyper: hyper_client, session: RefCell::new(session), })) @@ -176,7 +176,7 @@ where initial_device_display_name: None, kind: Some(register::RegistrationKind::User), password: Some(password), - username: username, + username, }).map(move |response| { let session = Session::new(response.access_token, response.user_id); *data.session.borrow_mut() = Some(session.clone()); @@ -256,7 +256,7 @@ where } } - Uri::from_str(url.as_ref().as_ref()) + Uri::from_str(url.as_ref()) .map(move |uri| (uri, hyper_request)) .map_err(Error::from) }) From dc6f35b1438c2ca1394e4c18fac3f5d91d459a6b Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Mon, 3 Dec 2018 22:13:55 -0800 Subject: [PATCH 046/139] Update dependencies and remove futures-await example. --- Cargo.toml | 25 ++++++----- examples/hello_world_await.rs | 80 ----------------------------------- 2 files changed, 12 insertions(+), 93 deletions(-) delete mode 100644 examples/hello_world_await.rs diff --git a/Cargo.toml b/Cargo.toml index 84b025dd..95b536b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,28 +11,27 @@ repository = "https://github.com/ruma/ruma-client" version = "0.1.0" [dependencies] -futures = "0.1.14" -http = "0.1" -hyper = "0.12" -ruma-api = "0.4.0" -ruma-client-api = "0.1.0" +futures = "0.1.25" +http = "0.1.14" +hyper = "0.12.16" +ruma-api = "0.6.0" +ruma-client-api = "0.2.0" ruma-identifiers = "0.11.0" -serde_json = "1.0.2" -serde_urlencoded = "0.5.1" -url = "1.5.1" +serde_json = "1.0.33" +serde_urlencoded = "0.5.4" +url = "1.7.2" [dependencies.hyper-tls] optional = true -version = "0.3.0" +version = "0.3.1" [dependencies.native-tls] optional = true -version = "0.2.1" +version = "0.2.2" [dev-dependencies] -futures-await = { git = 'https://github.com/alexcrichton/futures-await' } -ruma-events = "0.10" -tokio-core = "0.1" +ruma-events = "0.11.0" +tokio-core = "0.1.17" [features] default = ["tls"] diff --git a/examples/hello_world_await.rs b/examples/hello_world_await.rs deleted file mode 100644 index 4e321da2..00000000 --- a/examples/hello_world_await.rs +++ /dev/null @@ -1,80 +0,0 @@ -#![feature(generators)] -#![feature(proc_macro_non_items)] -#![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 std::env; -use std::process::exit; - -use futures::prelude::{*, await}; -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( - homeserver_url: Url, - room: String, -) -> impl Future { - let client = Client::https(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(&room[..]).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 (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) - } - }; - - Core::new().unwrap() - .run(hello_world(homeserver_url.parse().unwrap(), room)) - .unwrap(); -} From 1ba4f66ba904ca2069cb5ea7c733ca06d72795cf Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sat, 22 Dec 2018 12:05:25 +0100 Subject: [PATCH 047/139] Run rustfmt --- examples/hello_world.rs | 12 +++-- src/api.rs | 9 +--- src/lib.rs | 100 +++++++++++++++++++++++----------------- 3 files changed, 68 insertions(+), 53 deletions(-) diff --git a/examples/hello_world.rs b/examples/hello_world.rs index 44c22e91..e12ff258 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -12,10 +12,10 @@ use std::env; use std::process::exit; use futures::Future; -use ruma_client::Client; use ruma_client::api::r0; -use ruma_events::EventType; +use ruma_client::Client; use ruma_events::room::message::{MessageEventContent, MessageType, TextMessageEventContent}; +use ruma_events::EventType; use ruma_identifiers::RoomAliasId; use tokio_core::reactor::Core; use url::Url; @@ -66,12 +66,16 @@ 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()); + eprintln!( + "Usage: {} ", + env::args().next().unwrap() + ); exit(1) } }; - Core::new().unwrap() + Core::new() + .unwrap() .run(hello_world(homeserver_url.parse().unwrap(), room)) .unwrap(); } diff --git a/src/api.rs b/src/api.rs index 2dbeb926..602d4016 100644 --- a/src/api.rs +++ b/src/api.rs @@ -162,11 +162,7 @@ pub mod r0 { /// Event filters. pub mod filter { pub use ruma_client_api::r0::filter::{ - EventFormat, - Filter, - FilterDefinition, - RoomEventFilter, - RoomFilter, + EventFormat, Filter, FilterDefinition, RoomEventFilter, RoomFilter, }; endpoint!( @@ -318,8 +314,7 @@ pub mod r0 { } /// Push notifications. - pub mod push { - } + pub mod push {} /// Event receipts. pub mod receipt { diff --git a/src/lib.rs b/src/lib.rs index eda19f68..5437d222 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,9 +25,9 @@ use std::str::FromStr; use futures::future::{Future, FutureFrom, IntoFuture}; use futures::stream::{self, Stream}; -use hyper::{Client as HyperClient, Uri}; -use hyper::client::HttpConnector; use hyper::client::connect::Connect; +use hyper::client::HttpConnector; +use hyper::{Client as HyperClient, Uri}; #[cfg(feature = "hyper-tls")] use hyper_tls::HttpsConnector; #[cfg(feature = "hyper-tls")] @@ -77,11 +77,7 @@ impl Client> { Ok(Client(Rc::new(ClientData { homeserver_url, - hyper: { - HyperClient::builder() - .keep_alive(true) - .build(connector) - }, + hyper: { HyperClient::builder().keep_alive(true).build(connector) }, session: RefCell::new(session), }))) } @@ -94,7 +90,11 @@ where /// Creates a new client using the given `hyper::Client`. /// /// This allows the user to configure the details of HTTP as desired. - pub fn custom(hyper_client: HyperClient, homeserver_url: Url, session: Option) -> Self { + pub fn custom( + hyper_client: HyperClient, + homeserver_url: Url, + session: Option, + ) -> Self { Client(Rc::new(ClientData { homeserver_url, hyper: hyper_client, @@ -107,20 +107,28 @@ 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(&self, user: String, password: String, device_id: Option) - -> impl Future { + pub fn log_in( + &self, + user: String, + password: String, + device_id: Option, + ) -> impl Future { 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, - device_id, - password, - user, - }).map(move |response| { + login::call( + self.clone(), + login::Request { + address: None, + login_type: login::LoginType::Password, + medium: None, + device_id, + password, + user, + }, + ) + .map(move |response| { let session = Session::new(response.access_token, response.user_id); *data.session.borrow_mut() = Some(session.clone()); @@ -136,15 +144,19 @@ where let data = self.0.clone(); - register::call(self.clone(), 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| { + register::call( + self.clone(), + 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| { let session = Session::new(response.access_token, response.user_id); *data.session.borrow_mut() = Some(session.clone()); @@ -169,15 +181,19 @@ where let data = self.0.clone(); - register::call(self.clone(), register::Request { - auth: None, - bind_email: None, - device_id: None, - initial_device_display_name: None, - kind: Some(register::RegistrationKind::User), - password: Some(password), - username, - }).map(move |response| { + register::call( + self.clone(), + register::Request { + auth: None, + bind_email: None, + device_id: None, + initial_device_display_name: None, + kind: Some(register::RegistrationKind::User), + password: Some(password), + username, + }, + ) + .map(move |response| { let session = Session::new(response.access_token, response.user_id); *data.session.borrow_mut() = Some(session.clone()); @@ -216,10 +232,11 @@ where set_presence: set_presence.clone(), timeout: None, }, - ).map(|res| { + ) + .map(|res| { let next_batch_clone = res.next_batch.clone(); (res, Some(next_batch_clone)) - }) + }), ) }) } @@ -249,7 +266,8 @@ where if E::METADATA.requires_authentication { if let Some(ref session) = *data1.session.borrow() { - url.query_pairs_mut().append_pair("access_token", session.access_token()); + url.query_pairs_mut() + .append_pair("access_token", session.access_token()); } else { return Err(Error::AuthenticationRequired); } @@ -263,9 +281,7 @@ where .and_then(move |(uri, mut hyper_request)| { *hyper_request.uri_mut() = uri; - data2.hyper - .request(hyper_request) - .map_err(Error::from) + data2.hyper.request(hyper_request).map_err(Error::from) }) .and_then(|hyper_response| { E::Response::future_from(hyper_response).map_err(Error::from) From c3ccf51b022c7c8f94b517edd601936b13a86a66 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sat, 22 Dec 2018 12:08:54 +0100 Subject: [PATCH 048/139] Use nested imports --- .rustfmt.toml | 1 + examples/hello_world.rs | 13 ++++++------- src/lib.rs | 18 +++++++++--------- 3 files changed, 16 insertions(+), 16 deletions(-) create mode 100644 .rustfmt.toml diff --git a/.rustfmt.toml b/.rustfmt.toml new file mode 100644 index 00000000..7d2cf549 --- /dev/null +++ b/.rustfmt.toml @@ -0,0 +1 @@ +merge_imports = true diff --git a/examples/hello_world.rs b/examples/hello_world.rs index e12ff258..9f55fe67 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -7,15 +7,14 @@ extern crate ruma_identifiers; extern crate tokio_core; extern crate url; -use std::convert::TryFrom; -use std::env; -use std::process::exit; +use std::{convert::TryFrom, env, process::exit}; use futures::Future; -use ruma_client::api::r0; -use ruma_client::Client; -use ruma_events::room::message::{MessageEventContent, MessageType, TextMessageEventContent}; -use ruma_events::EventType; +use ruma_client::{api::r0, Client}; +use ruma_events::{ + room::message::{MessageEventContent, MessageType, TextMessageEventContent}, + EventType, +}; use ruma_identifiers::RoomAliasId; use tokio_core::reactor::Core; use url::Url; diff --git a/src/lib.rs b/src/lib.rs index 5437d222..760ff6c6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,16 +18,16 @@ extern crate serde_json; extern crate serde_urlencoded; extern crate url; -use std::cell::RefCell; -use std::convert::TryInto; -use std::rc::Rc; -use std::str::FromStr; +use std::{cell::RefCell, convert::TryInto, rc::Rc, str::FromStr}; -use futures::future::{Future, FutureFrom, IntoFuture}; -use futures::stream::{self, Stream}; -use hyper::client::connect::Connect; -use hyper::client::HttpConnector; -use hyper::{Client as HyperClient, Uri}; +use futures::{ + future::{Future, FutureFrom, IntoFuture}, + stream::{self, Stream}, +}; +use hyper::{ + client::{connect::Connect, HttpConnector}, + Client as HyperClient, Uri, +}; #[cfg(feature = "hyper-tls")] use hyper_tls::HttpsConnector; #[cfg(feature = "hyper-tls")] From 28d7db40edd99f756b4163b5b90163b25aac6123 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sat, 22 Dec 2018 12:22:55 +0100 Subject: [PATCH 049/139] Update to Rust 2018 --- Cargo.toml | 1 + examples/hello_world.rs | 9 +-------- src/api.rs | 2 +- src/lib.rs | 25 +++++-------------------- 4 files changed, 8 insertions(+), 29 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 95b536b8..df4b21fc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,6 +2,7 @@ authors = ["Jimmy Cuadra "] description = "A Matrix client library." documentation = "https://docs.rs/ruma-client" +edition = "2018" homepage = "https://github.com/ruma/ruma-client" keywords = ["matrix", "chat", "messaging", "ruma"] license = "MIT" diff --git a/examples/hello_world.rs b/examples/hello_world.rs index 9f55fe67..ad8caafd 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -1,16 +1,9 @@ #![feature(try_from)] -extern crate futures; -extern crate ruma_client; -extern crate ruma_events; -extern crate ruma_identifiers; -extern crate tokio_core; -extern crate url; - use std::{convert::TryFrom, env, process::exit}; use futures::Future; -use ruma_client::{api::r0, Client}; +use ruma_client::{self, api::r0, Client}; use ruma_events::{ room::message::{MessageEventContent, MessageType, TextMessageEventContent}, EventType, diff --git a/src/api.rs b/src/api.rs index 602d4016..8c99d65d 100644 --- a/src/api.rs +++ b/src/api.rs @@ -29,7 +29,7 @@ macro_rules! endpoint { $($import),* }; - use {Client, Error}; + use crate::{Client, Error}; /// Make a request to this API endpoint. pub fn call( diff --git a/src/lib.rs b/src/lib.rs index 760ff6c6..fba1b29b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,20 +4,6 @@ #![deny(missing_docs)] #![feature(try_from)] -extern crate futures; -extern crate http; -extern crate hyper; -#[cfg(feature = "tls")] -extern crate hyper_tls; -#[cfg(feature = "tls")] -extern crate native_tls; -extern crate ruma_api; -extern crate ruma_client_api; -extern crate ruma_identifiers; -extern crate serde_json; -extern crate serde_urlencoded; -extern crate url; - use std::{cell::RefCell, convert::TryInto, rc::Rc, str::FromStr}; use futures::{ @@ -35,8 +21,7 @@ use native_tls::Error as NativeTlsError; use ruma_api::Endpoint; use url::Url; -pub use error::Error; -pub use session::Session; +pub use crate::{error::Error, session::Session}; /// Matrix client-server API endpoints. pub mod api; @@ -113,7 +98,7 @@ where password: String, device_id: Option, ) -> impl Future { - use api::r0::session::login; + use crate::api::r0::session::login; let data = self.0.clone(); @@ -140,7 +125,7 @@ where /// this method stores the session data returned by the endpoint in this /// client, instead of returning it. pub fn register_guest(&self) -> impl Future { - use api::r0::account::register; + use crate::api::r0::account::register; let data = self.0.clone(); @@ -177,7 +162,7 @@ where username: Option, password: String, ) -> impl Future { - use api::r0::account::register; + use crate::api::r0::account::register; let data = self.0.clone(); @@ -212,7 +197,7 @@ where since: Option, set_presence: bool, ) -> impl Stream { - use api::r0::sync::sync_events; + use crate::api::r0::sync::sync_events; let client = self.clone(); let set_presence = if set_presence { From eb92b86ce4ac26112e5fbcbcc9165f06a8e596aa Mon Sep 17 00:00:00 2001 From: Nathan Musoke Date: Thu, 25 Jan 2018 17:52:41 +1300 Subject: [PATCH 050/139] Store device_id in session The device_id is needed by the client, but otherwise inaccessible (unless provided to the server by the client). This is analogous to how the user_id is currently stored for guests, but will probably be more often used. The device_id is needed to implement e2e encryption. --- src/lib.rs | 6 +++--- src/session.rs | 10 +++++++++- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index fba1b29b..41b2eb16 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -114,7 +114,7 @@ where }, ) .map(move |response| { - let session = Session::new(response.access_token, response.user_id); + let session = Session::new(response.access_token, response.user_id, response.device_id); *data.session.borrow_mut() = Some(session.clone()); session @@ -142,7 +142,7 @@ where }, ) .map(move |response| { - let session = Session::new(response.access_token, response.user_id); + let session = Session::new(response.access_token, response.user_id, response.device_id); *data.session.borrow_mut() = Some(session.clone()); session @@ -179,7 +179,7 @@ where }, ) .map(move |response| { - let session = Session::new(response.access_token, response.user_id); + let session = Session::new(response.access_token, response.user_id, response.device_id); *data.session.borrow_mut() = Some(session.clone()); session diff --git a/src/session.rs b/src/session.rs index 388567d4..07314d26 100644 --- a/src/session.rs +++ b/src/session.rs @@ -7,14 +7,17 @@ pub struct Session { access_token: String, /// The user the access token was issued for. user_id: UserId, + /// The ID of the client device + device_id: String, } impl Session { /// Create a new user session from an access token and a user ID. - pub fn new(access_token: String, user_id: UserId) -> Self { + pub fn new(access_token: String, user_id: UserId, device_id: String) -> Self { Session { access_token, user_id, + device_id, } } @@ -27,4 +30,9 @@ impl Session { pub fn user_id(&self) -> &UserId { &self.user_id } + + /// Get ID of the device the session belongs to. + pub fn device_id(&self) -> &str { + &self.device_id + } } From 7cf5ac80c8ba60d7a53cfe9b134e8136dc6bc41c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Sommer?= Date: Tue, 22 Jan 2019 10:36:04 +0100 Subject: [PATCH 051/139] Make ruma client thread safe The new tokio engine requires a client that is safe to be send between threads. It's simply done by converting Rc to Arc and RefCell to Mutex. --- src/lib.rs | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 41b2eb16..5be158c2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,7 @@ #![deny(missing_docs)] #![feature(try_from)] -use std::{cell::RefCell, convert::TryInto, rc::Rc, str::FromStr}; +use std::{convert::TryInto, str::FromStr, sync::{Arc, Mutex}}; use futures::{ future::{Future, FutureFrom, IntoFuture}, @@ -30,7 +30,7 @@ mod session; /// A client for the Matrix client-server API. #[derive(Debug)] -pub struct Client(Rc>); +pub struct Client(Arc>); /// Data contained in Client's Rc #[derive(Debug)] @@ -40,16 +40,16 @@ where { homeserver_url: Url, hyper: HyperClient, - session: RefCell>, + session: Mutex>, } impl Client { /// Creates a new client for making HTTP requests to the given homeserver. pub fn new(homeserver_url: Url, session: Option) -> Self { - Client(Rc::new(ClientData { + Client(Arc::new(ClientData { homeserver_url, hyper: HyperClient::builder().keep_alive(true).build_http(), - session: RefCell::new(session), + session: Mutex::new(session), })) } } @@ -60,10 +60,10 @@ impl Client> { pub fn https(homeserver_url: Url, session: Option) -> Result { let connector = HttpsConnector::new(4)?; - Ok(Client(Rc::new(ClientData { + Ok(Client(Arc::new(ClientData { homeserver_url, hyper: { HyperClient::builder().keep_alive(true).build(connector) }, - session: RefCell::new(session), + session: Mutex::new(session), }))) } } @@ -80,10 +80,10 @@ where homeserver_url: Url, session: Option, ) -> Self { - Client(Rc::new(ClientData { + Client(Arc::new(ClientData { homeserver_url, hyper: hyper_client, - session: RefCell::new(session), + session: Mutex::new(session), })) } @@ -115,7 +115,7 @@ where ) .map(move |response| { let session = Session::new(response.access_token, response.user_id, response.device_id); - *data.session.borrow_mut() = Some(session.clone()); + *data.session.lock().unwrap() = Some(session.clone()); session }) @@ -143,7 +143,7 @@ where ) .map(move |response| { let session = Session::new(response.access_token, response.user_id, response.device_id); - *data.session.borrow_mut() = Some(session.clone()); + *data.session.lock().unwrap() = Some(session.clone()); session }) @@ -180,7 +180,7 @@ where ) .map(move |response| { let session = Session::new(response.access_token, response.user_id, response.device_id); - *data.session.borrow_mut() = Some(session.clone()); + *data.session.lock().unwrap() = Some(session.clone()); session }) @@ -250,7 +250,7 @@ where url.set_query(uri.query()); if E::METADATA.requires_authentication { - if let Some(ref session) = *data1.session.borrow() { + if let Some(ref session) = *data1.session.lock().unwrap() { url.query_pairs_mut() .append_pair("access_token", session.access_token()); } else { From e0f20ba0d013cf1dc809e875ad7a0cd4abe72421 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Sommer?= Date: Tue, 22 Jan 2019 10:38:31 +0100 Subject: [PATCH 052/139] Use tokio for hello_world example The crate tokio-core is deprecated. --- Cargo.toml | 2 +- examples/hello_world.rs | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index df4b21fc..4ae23b40 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,7 @@ version = "0.2.2" [dev-dependencies] ruma-events = "0.11.0" -tokio-core = "0.1.17" +tokio = "0.1" [features] default = ["tls"] diff --git a/examples/hello_world.rs b/examples/hello_world.rs index ad8caafd..da322634 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -9,7 +9,6 @@ use ruma_events::{ EventType, }; use ruma_identifiers::RoomAliasId; -use tokio_core::reactor::Core; use url::Url; // from https://stackoverflow.com/a/43992218/1592377 @@ -66,8 +65,6 @@ fn main() { } }; - Core::new() - .unwrap() - .run(hello_world(homeserver_url.parse().unwrap(), room)) - .unwrap(); + tokio::run(hello_world(homeserver_url.parse().unwrap(), room) + .map_err(|e| { dbg!(e); () })); } From fa798d7a04220343db89fc6d36108ceb9d7ad1f2 Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Fri, 8 Feb 2019 13:43:15 -0800 Subject: [PATCH 053/139] Make Session fields public. --- Cargo.toml | 4 ++++ src/lib.rs | 20 ++++++++++++++++---- src/session.rs | 12 ++++++++---- 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4ae23b40..42d6fa66 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,6 +30,10 @@ version = "0.3.1" optional = true version = "0.2.2" +[dependencies.serde] +version = "1.0.87" +features = ["derive"] + [dev-dependencies] ruma-events = "0.11.0" tokio = "0.1" diff --git a/src/lib.rs b/src/lib.rs index 5be158c2..84ade332 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -114,7 +114,11 @@ where }, ) .map(move |response| { - let session = Session::new(response.access_token, response.user_id, response.device_id); + let session = Session { + access_token: response.access_token, + device_id: response.device_id, + user_id: response.user_id, + }; *data.session.lock().unwrap() = Some(session.clone()); session @@ -142,7 +146,11 @@ where }, ) .map(move |response| { - let session = Session::new(response.access_token, response.user_id, response.device_id); + let session = Session { + access_token: response.access_token, + device_id: response.device_id, + user_id: response.user_id, + }; *data.session.lock().unwrap() = Some(session.clone()); session @@ -179,7 +187,11 @@ where }, ) .map(move |response| { - let session = Session::new(response.access_token, response.user_id, response.device_id); + let session = Session { + access_token: response.access_token, + device_id: response.device_id, + user_id: response.user_id, + }; *data.session.lock().unwrap() = Some(session.clone()); session @@ -252,7 +264,7 @@ where if E::METADATA.requires_authentication { if let Some(ref session) = *data1.session.lock().unwrap() { url.query_pairs_mut() - .append_pair("access_token", session.access_token()); + .append_pair("access_token", &session.access_token); } else { return Err(Error::AuthenticationRequired); } diff --git a/src/session.rs b/src/session.rs index 07314d26..b22809df 100644 --- a/src/session.rs +++ b/src/session.rs @@ -1,18 +1,19 @@ use ruma_identifiers::UserId; /// A user session, containing an access token and information about the associated user account. -#[derive(Clone, Debug, Eq, Hash, PartialEq)] +#[derive(Clone, Debug, serde::Deserialize, Eq, Hash, PartialEq, serde::Serialize)] pub struct Session { /// The access token used for this session. - access_token: String, + pub access_token: String, /// The user the access token was issued for. - user_id: UserId, + pub user_id: UserId, /// The ID of the client device - device_id: String, + pub device_id: String, } impl Session { /// Create a new user session from an access token and a user ID. + #[deprecated] pub fn new(access_token: String, user_id: UserId, device_id: String) -> Self { Session { access_token, @@ -22,16 +23,19 @@ impl Session { } /// Get the access token associated with this session. + #[deprecated] pub fn access_token(&self) -> &str { &self.access_token } /// Get the ID of the user the session belongs to. + #[deprecated] pub fn user_id(&self) -> &UserId { &self.user_id } /// Get ID of the device the session belongs to. + #[deprecated] pub fn device_id(&self) -> &str { &self.device_id } From 913c25e5b8a81965d60db97c67dedcedf7ad0df7 Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Thu, 11 Apr 2019 17:30:22 -0700 Subject: [PATCH 054/139] Add note about minimum Rust version. --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 5758490b..4b8bd6c8 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,10 @@ **ruma-client** is a [Matrix](https://matrix.org/) client library for [Rust](https://www.rust-lang.org/). +## Minimum Rust version + +ruma-client requires Rust 1.34 or later. + ## License [MIT](http://opensource.org/licenses/MIT) From d6c3be456695e9e510ce19b90b7ba713ca7ae086 Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Thu, 11 Apr 2019 18:31:22 -0700 Subject: [PATCH 055/139] Update dependencies. --- Cargo.toml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 42d6fa66..f505ad4b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,31 +12,31 @@ repository = "https://github.com/ruma/ruma-client" version = "0.1.0" [dependencies] -futures = "0.1.25" -http = "0.1.14" -hyper = "0.12.16" -ruma-api = "0.6.0" -ruma-client-api = "0.2.0" -ruma-identifiers = "0.11.0" -serde_json = "1.0.33" +futures = "0.1.26" +http = "0.1.17" +hyper = "0.12.27" +ruma-api = "0.7.0" +ruma-client-api = "0.3.0" +ruma-identifiers = "0.12.0" +serde_json = "1.0.39" serde_urlencoded = "0.5.4" url = "1.7.2" [dependencies.hyper-tls] optional = true -version = "0.3.1" +version = "0.3.2" [dependencies.native-tls] optional = true version = "0.2.2" [dependencies.serde] -version = "1.0.87" +version = "1.0.90" features = ["derive"] [dev-dependencies] -ruma-events = "0.11.0" -tokio = "0.1" +ruma-events = "0.12.0" +tokio = "0.1.18" [features] default = ["tls"] From 982b855d917251e1d3e099a6b5e229a926ca1b49 Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Thu, 11 Apr 2019 18:33:53 -0700 Subject: [PATCH 056/139] Remove try_from feature. --- examples/hello_world.rs | 2 -- src/lib.rs | 1 - 2 files changed, 3 deletions(-) diff --git a/examples/hello_world.rs b/examples/hello_world.rs index da322634..ff45071d 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -1,5 +1,3 @@ -#![feature(try_from)] - use std::{convert::TryFrom, env, process::exit}; use futures::Future; diff --git a/src/lib.rs b/src/lib.rs index 84ade332..2312f86f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,7 +2,6 @@ #![deny(missing_debug_implementations)] #![deny(missing_docs)] -#![feature(try_from)] use std::{convert::TryInto, str::FromStr, sync::{Arc, Mutex}}; From a66830de7aacf584676d79e86056e9ff88f0a575 Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Thu, 11 Apr 2019 22:23:37 -0700 Subject: [PATCH 057/139] Add joined rooms membership endpoint. --- src/api.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/api.rs b/src/api.rs index 8c99d65d..13bf95fe 100644 --- a/src/api.rs +++ b/src/api.rs @@ -234,6 +234,12 @@ pub mod r0 { join_room_by_id_or_alias ); + endpoint!( + /// Get a list of the user's current rooms. + [r0, membership], + joined_rooms + ); + endpoint!( /// Kick a user from a room. [r0, membership], From cd093491748ec2bf34ee2e55e2a67cd38e35ae01 Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Thu, 11 Apr 2019 22:23:46 -0700 Subject: [PATCH 058/139] Bump version to 0.2.0. --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f505ad4b..92ef6d44 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,7 +9,7 @@ license = "MIT" name = "ruma-client" readme = "README.md" repository = "https://github.com/ruma/ruma-client" -version = "0.1.0" +version = "0.2.0" [dependencies] futures = "0.1.26" From e1f5e4643b56b61ad6dc33485eb77524422354df Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 19 Apr 2019 00:54:18 +0200 Subject: [PATCH 059/139] README.md: Add Status, Contributing sections --- README.md | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 5758490b..201a1909 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,32 @@ # ruma-client -**ruma-client** is a [Matrix](https://matrix.org/) client library for [Rust](https://www.rust-lang.org/). +**ruma-client** is a [Matrix][] client library for [Rust][]. + +[Matrix]: https://matrix.org/ +[Rust]: https://www.rust-lang.org/ + +## Status + +This project is a work in progress and not ready for production usage yet. Most endpoints that are +available in this crate are usable with an up-to-date synapse server, but no comprehensive testing +has been done so far. + +As long as the matrix client-server API is still at version 0.x, only the latest API revision is +considered supported. However, due to the low amount of available manpower, it can take a long time +for all changes from a new API revision to arrive in ruma-client (at the time of writing only few +endpoints have received an update for r0.4.0). + +## Contributing + +If you want to help out, have a look at the issues here and on the other [ruma-\*][gh-org] +repositories (ruma-client-api and ruma-events in particular contain much of the code that powers +ruma-client). + +There is also a [room for ruma on matrix.org][#ruma:matrix.org], which can be used for questions +and discussion related to any of the crates in this project. + +[gh-org]: https://github.com/ruma +[#ruma:matrix.org]: https://matrix.to/#/#ruma:matrix.org ## License From 949249ea49f506bd682b2a463557af8bf8a06330 Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Sun, 2 Jun 2019 09:11:29 -0700 Subject: [PATCH 060/139] Use stable Rust on Travis. --- .travis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index c677ed70..79529cb9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,4 @@ notifications: channels: - secure: "AJxKl4hMtg1g8+uUqgF4yeOZKCW5rqxilF/LFicRUGZFsqurO/pmvBrWIx2NeCpjUo7IPGR78NhbRPu7Qp93hHd4UQfnDE9Aw2iU7nMdJlnSMdztilObLPGtopJQGt1HXwJquxUvqd/J95Eb5ep+PbwJMj2qkEF1e5JlGhNKnpAQVL7RQYHhKGD6n6vkqpStQvvswtSHH0Uk6nrlZEVQxrvQy7w+iw5lEHqg64Y+w17ilR/+NJrLT83UlnOGKOADJ9bh8l8GrQvqmQhFwcJv1qj5tp6Tr30eN45FIv4P1hUkXW5lSm3mgX4b1QVDeCGH8ebo/WChrUB461uZhZnVk8JrWGtcrmLP08daliQxhm6Ybm4cW9kcZXMEs64wqz/xcYX0rJo4dwoY1ZyvM1G3b6HwYEEgiU5ypM3rXzT/7z007zOxD/EjCYQumBZKarqEkH76qSlPwjsYWQOWY9gwNeh93Gg+a+0wD2HitKzxPnTYaFt67QaZxxC/h2YNcvVAxPyiC0gdTUf+cPG0KidJKexfg4cSjHQj7EnPpNPzSfqdA5XvmkEeUV4Igi/sQHSiS4OFwtaq99bIqm4FZswFJq+T4IUyTC5jzvT3b2D6AZuwJnxtYXT70iO12+q+D7V01zLI8O0qGS31NkK5NYjTULQdWuOnSANnfeCnhdDleys=" use_notice: true -rust: - - "nightly" From 815c54f2b97070c7e477bdd715aa407720defd43 Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Sun, 2 Jun 2019 09:30:50 -0700 Subject: [PATCH 061/139] Make ClientData private. --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 2312f86f..6df99676 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -33,7 +33,7 @@ pub struct Client(Arc>); /// Data contained in Client's Rc #[derive(Debug)] -pub struct ClientData +struct ClientData where C: Connect, { From 97b42c9d10d45c9f27932936d95dc45a34740384 Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Sun, 2 Jun 2019 09:32:06 -0700 Subject: [PATCH 062/139] Run rustfmt. --- .rustfmt.toml | 1 - .travis.yml | 6 ++++++ examples/hello_world.rs | 8 ++++++-- src/lib.rs | 6 +++++- 4 files changed, 17 insertions(+), 4 deletions(-) delete mode 100644 .rustfmt.toml diff --git a/.rustfmt.toml b/.rustfmt.toml deleted file mode 100644 index 7d2cf549..00000000 --- a/.rustfmt.toml +++ /dev/null @@ -1 +0,0 @@ -merge_imports = true diff --git a/.travis.yml b/.travis.yml index 79529cb9..15f4a38a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,4 +1,10 @@ language: "rust" +before_script: + - "rustup component add rustfmt" +script: + - "cargo fmt --all -- --check" + - "cargo build --verbose" + - "cargo test --verbose" notifications: email: false irc: diff --git a/examples/hello_world.rs b/examples/hello_world.rs index ff45071d..6c062444 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -63,6 +63,10 @@ fn main() { } }; - tokio::run(hello_world(homeserver_url.parse().unwrap(), room) - .map_err(|e| { dbg!(e); () })); + tokio::run( + hello_world(homeserver_url.parse().unwrap(), room).map_err(|e| { + dbg!(e); + () + }), + ); } diff --git a/src/lib.rs b/src/lib.rs index 6df99676..55882271 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,7 +3,11 @@ #![deny(missing_debug_implementations)] #![deny(missing_docs)] -use std::{convert::TryInto, str::FromStr, sync::{Arc, Mutex}}; +use std::{ + convert::TryInto, + str::FromStr, + sync::{Arc, Mutex}, +}; use futures::{ future::{Future, FutureFrom, IntoFuture}, From 71e1df7063d07a2f1f93e29ea9a7b67874fb021e Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Sun, 2 Jun 2019 09:40:00 -0700 Subject: [PATCH 063/139] Add clippy lints. --- src/error.rs | 14 ++++++++------ src/lib.rs | 39 ++++++++++++++++++++++++++++++++------- src/session.rs | 4 +++- 3 files changed, 43 insertions(+), 14 deletions(-) diff --git a/src/error.rs b/src/error.rs index f6ca9384..b1c6ee9e 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,3 +1,5 @@ +//! Error conditions. + use http::uri::InvalidUri; use hyper::error::Error as HyperError; use ruma_api::Error as RumaApiError; @@ -25,37 +27,37 @@ pub enum Error { } impl From for Error { - fn from(error: HyperError) -> Error { + fn from(error: HyperError) -> Self { Error::Hyper(error) } } impl From for Error { - fn from(error: InvalidUri) -> Error { + fn from(error: InvalidUri) -> Self { Error::Uri(error) } } impl From for Error { - fn from(error: ParseError) -> Error { + fn from(error: ParseError) -> Self { Error::Url(error) } } impl From for Error { - fn from(error: RumaApiError) -> Error { + fn from(error: RumaApiError) -> Self { Error::RumaApi(error) } } impl From for Error { - fn from(error: SerdeJsonError) -> Error { + fn from(error: SerdeJsonError) -> Self { Error::SerdeJson(error) } } impl From for Error { - fn from(error: SerdeUrlEncodedSerializeError) -> Error { + fn from(error: SerdeUrlEncodedSerializeError) -> Self { Error::SerdeUrlEncodedSerialize(error) } } diff --git a/src/lib.rs b/src/lib.rs index 55882271..f65274b5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,7 +1,29 @@ //! Crate `ruma_client` is a [Matrix](https://matrix.org/) client library. -#![deny(missing_debug_implementations)] -#![deny(missing_docs)] +#![deny( + missing_copy_implementations, + missing_debug_implementations, + missing_docs, + warnings +)] +#![warn( + clippy::empty_line_after_outer_attr, + clippy::expl_impl_clone_on_copy, + clippy::if_not_else, + clippy::items_after_statements, + clippy::match_same_arms, + clippy::mem_forget, + clippy::missing_docs_in_private_items, + clippy::mut_mut, + clippy::needless_borrow, + clippy::needless_continue, + clippy::single_match_else, + clippy::unicode_not_nfc, + clippy::use_self, + clippy::used_underscore_binding, + clippy::wrong_pub_self_convention, + clippy::wrong_self_convention +)] use std::{ convert::TryInto, @@ -41,15 +63,18 @@ struct ClientData where C: Connect, { + /// The URL of the homeserver to connect to. homeserver_url: Url, + /// The underlying HTTP client. hyper: HyperClient, + /// User session data. session: Mutex>, } impl Client { /// Creates a new client for making HTTP requests to the given homeserver. pub fn new(homeserver_url: Url, session: Option) -> Self { - Client(Arc::new(ClientData { + Self(Arc::new(ClientData { homeserver_url, hyper: HyperClient::builder().keep_alive(true).build_http(), session: Mutex::new(session), @@ -63,7 +88,7 @@ impl Client> { pub fn https(homeserver_url: Url, session: Option) -> Result { let connector = HttpsConnector::new(4)?; - Ok(Client(Arc::new(ClientData { + Ok(Self(Arc::new(ClientData { homeserver_url, hyper: { HyperClient::builder().keep_alive(true).build(connector) }, session: Mutex::new(session), @@ -83,7 +108,7 @@ where homeserver_url: Url, session: Option, ) -> Self { - Client(Arc::new(ClientData { + Self(Arc::new(ClientData { homeserver_url, hyper: hyper_client, session: Mutex::new(session), @@ -290,7 +315,7 @@ where } impl Clone for Client { - fn clone(&self) -> Client { - Client(self.0.clone()) + fn clone(&self) -> Self { + Self(self.0.clone()) } } diff --git a/src/session.rs b/src/session.rs index b22809df..331baeb7 100644 --- a/src/session.rs +++ b/src/session.rs @@ -1,3 +1,5 @@ +//! User sessions. + use ruma_identifiers::UserId; /// A user session, containing an access token and information about the associated user account. @@ -15,7 +17,7 @@ impl Session { /// Create a new user session from an access token and a user ID. #[deprecated] pub fn new(access_token: String, user_id: UserId, device_id: String) -> Self { - Session { + Self { access_token, user_id, device_id, From 15dd1b5b5483e657ec2346683a07c2e2f458c28b Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Sun, 2 Jun 2019 09:49:56 -0700 Subject: [PATCH 064/139] Add a session accessor to the client. --- src/lib.rs | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index f65274b5..8271cad2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -80,6 +80,17 @@ impl Client { session: Mutex::new(session), })) } + + /// Get a copy of the current `Session`, if any. + /// + /// Useful for serializing and persisting the session to be restored later. + pub fn session(&self) -> Option { + self.0 + .session + .lock() + .expect("session mutex was poisoned") + .clone() + } } #[cfg(feature = "tls")] From 5eac184768abbcf765512781139897f9ec61b8d1 Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Sun, 2 Jun 2019 10:31:35 -0700 Subject: [PATCH 065/139] Add crate documentation. --- src/lib.rs | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 8271cad2..e47e2e80 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,79 @@ //! Crate `ruma_client` is a [Matrix](https://matrix.org/) client library. +//! +//! # Usage +//! +//! Begin by creating a `Client` type, usually using the `https` method for a client that supports +//! secure connections, and then logging in: +//! +//! ```no_run +//! use futures::Future; +//! use ruma_client::Client; +//! +//! let homeserver_url = "https://example.com".parse().unwrap(); +//! let client = Client::https(homeserver_url, None).unwrap(); +//! +//! let work = client +//! .log_in("@alice:example.com".to_string(), "secret".to_string(), None) +//! .and_then(|session| { +//! // You're now logged in! Write the session to a file if you want to restore it later. +//! // Then start using the API! +//! # Ok::<(), ruma_client::Error>(()) +//! }); +//! +//! // Start `work` on a futures runtime... +//! ``` +//! +//! You can also pass an existing session to the `Client` constructor to restore a previous session +//! rather than calling `log_in`. +//! +//! For the standard use case of synchronizing with the homeserver (i.e. getting all the latest +//! events), use the `Client::sync`: +//! +//! ```no_run +//! # use futures::{Future, Stream}; +//! # use ruma_client::Client; +//! # let homeserver_url = "https://example.com".parse().unwrap(); +//! # let client = Client::https(homeserver_url, None).unwrap(); +//! let work = client.sync(None, None, true).map(|response| { +//! // Do something with the data in the response... +//! # Ok::<(), ruma_client::Error>(()) +//! }); +//! +//! // Start `work` on a futures runtime... +//! ``` +//! +//! The `Client` type also provides methods for registering a new account if you don't already have +//! one with the given homeserver. +//! +//! Beyond these basic convenience methods, `ruma-client` gives you access to the entire Matrix +//! client-server API via the `api` module. Each leaf module under this tree of modules contains +//! the necessary types for one API endpoint. Simply call the module's `call` method, passing it +//! the logged in `Client` and the relevant `Request` type. `call` will return a future that will +//! resolve to the relevant `Response` type. +//! +//! For example: +//! +//! ```no_run +//! # use futures::Future; +//! # use ruma_client::Client; +//! # let homeserver_url = "https://example.com".parse().unwrap(); +//! # let client = Client::https(homeserver_url, None).unwrap(); +//! use std::convert::TryFrom; +//! +//! use ruma_client::api::r0::alias::get_alias; +//! use ruma_identifiers::{RoomAliasId, RoomId}; +//! +//! let request = get_alias::Request { +//! room_alias: RoomAliasId::try_from("#example_room:example.com").unwrap(), +//! }; +//! +//! let work = get_alias::call(client, request).and_then(|response| { +//! assert_eq!(response.room_id, RoomId::try_from("!n8f893n9:example.com").unwrap()); +//! # Ok::<(), ruma_client::Error>(()) +//! }); +//! +//! // Start `work` on a futures runtime... +//! ``` #![deny( missing_copy_implementations, From 8699dc770821419e7bef94591a60677a5eeb699b Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Sun, 2 Jun 2019 10:47:10 -0700 Subject: [PATCH 066/139] Revise the error type to hide lower-level errors. --- src/error.rs | 49 ++++++++++++++++++++++++++++++++----------------- src/lib.rs | 3 ++- 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/src/error.rs b/src/error.rs index b1c6ee9e..b3da1b84 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,23 +1,44 @@ //! Error conditions. +use std::error::Error as StdError; +use std::fmt::{Display, Formatter, Result as FmtResult}; + use http::uri::InvalidUri; use hyper::error::Error as HyperError; use ruma_api::Error as RumaApiError; use serde_json::Error as SerdeJsonError; use serde_urlencoded::ser::Error as SerdeUrlEncodedSerializeError; -use url::ParseError; -/// An error that occurs during client operations. +/// An error that can occur during client operations. #[derive(Debug)] -pub enum Error { - /// Queried endpoint requires authentication but was called on an anonymous client +pub struct Error(pub(crate) InnerError); + +impl Display for Error { + fn fmt(&self, f: &mut Formatter) -> FmtResult { + let message = match self.0 { + InnerError::AuthenticationRequired => "The queried endpoint requires authentication but was called with an anonymous client.", + InnerError::Hyper(_) => "An HTTP error occurred.", + InnerError::Uri(_) => "Provided string could not be converted into a URI.", + InnerError::RumaApi(_) => "An error occurred converting between ruma_client_api and hyper types.", + InnerError::SerdeJson(_) => "A serialization error occurred.", + InnerError::SerdeUrlEncodedSerialize(_) => "An error occurred serializing data to a query string.", + }; + + write!(f, "{}", message) + } +} + +impl StdError for Error {} + +/// Internal representation of errors. +#[derive(Debug)] +pub(crate) enum InnerError { + /// Queried endpoint requires authentication but was called on an anonymous client. AuthenticationRequired, /// An error at the HTTP layer. Hyper(HyperError), /// An error when parsing a string as a URI. Uri(InvalidUri), - /// An error when parsing a string as a URL. - Url(ParseError), /// An error converting between ruma_client_api types and Hyper types. RumaApi(RumaApiError), /// An error when serializing or deserializing a JSON value. @@ -28,36 +49,30 @@ pub enum Error { impl From for Error { fn from(error: HyperError) -> Self { - Error::Hyper(error) + Self(InnerError::Hyper(error)) } } impl From for Error { fn from(error: InvalidUri) -> Self { - Error::Uri(error) - } -} - -impl From for Error { - fn from(error: ParseError) -> Self { - Error::Url(error) + Self(InnerError::Uri(error)) } } impl From for Error { fn from(error: RumaApiError) -> Self { - Error::RumaApi(error) + Self(InnerError::RumaApi(error)) } } impl From for Error { fn from(error: SerdeJsonError) -> Self { - Error::SerdeJson(error) + Self(InnerError::SerdeJson(error)) } } impl From for Error { fn from(error: SerdeUrlEncodedSerializeError) -> Self { - Error::SerdeUrlEncodedSerialize(error) + Self(InnerError::SerdeUrlEncodedSerialize(error)) } } diff --git a/src/lib.rs b/src/lib.rs index e47e2e80..0a8e5896 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -121,6 +121,7 @@ use native_tls::Error as NativeTlsError; use ruma_api::Endpoint; use url::Url; +use crate::error::InnerError; pub use crate::{error::Error, session::Session}; /// Matrix client-server API endpoints. @@ -380,7 +381,7 @@ where url.query_pairs_mut() .append_pair("access_token", &session.access_token); } else { - return Err(Error::AuthenticationRequired); + return Err(Error(InnerError::AuthenticationRequired)); } } } From 8e38761ad5ab1ca26731260e9189edfe0539ec5c Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Sun, 2 Jun 2019 13:12:34 -0700 Subject: [PATCH 067/139] Add clippy to CI. --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 15f4a38a..4f536691 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,10 @@ language: "rust" before_script: - "rustup component add rustfmt" + - "rustup component add clippy" script: - "cargo fmt --all -- --check" + - "cargo clippy -- -D warnings" - "cargo build --verbose" - "cargo test --verbose" notifications: From 585d22a6129e4f76e210328387d029cbc2f537b4 Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Sun, 2 Jun 2019 17:37:46 -0700 Subject: [PATCH 068/139] Run clippy on all targets and all features and fix clippy warning. --- .travis.yml | 2 +- examples/hello_world.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 4f536691..5ec9a6a3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ before_script: - "rustup component add clippy" script: - "cargo fmt --all -- --check" - - "cargo clippy -- -D warnings" + - "cargo clippy --all-targets --all-features -- -D warnings" - "cargo build --verbose" - "cargo test --verbose" notifications: diff --git a/examples/hello_world.rs b/examples/hello_world.rs index 6c062444..227af951 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -66,7 +66,6 @@ fn main() { tokio::run( hello_world(homeserver_url.parse().unwrap(), room).map_err(|e| { dbg!(e); - () }), ); } From 0f3fbec8b709032160774b40f0ed675a62358828 Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Sun, 16 Jun 2019 16:52:28 -0700 Subject: [PATCH 069/139] Add crates.io categories. [ci skip] --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 92ef6d44..698483bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,6 @@ [package] authors = ["Jimmy Cuadra "] +categories = ["api-bindings", "web-programming"] description = "A Matrix client library." documentation = "https://docs.rs/ruma-client" edition = "2018" From 9372a89e17fc8a4c1e1c6900c339abdc902303eb Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Wed, 24 Jul 2019 22:44:32 -0700 Subject: [PATCH 070/139] Run cargo-audit on CI. --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 5ec9a6a3..e6c1d326 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,12 @@ language: "rust" +cache: "cargo" before_script: - "rustup component add rustfmt" - "rustup component add clippy" + - "cargo install --force cargo-audit" + - "cargo generate-lockfile" script: + - "cargo audit" - "cargo fmt --all -- --check" - "cargo clippy --all-targets --all-features -- -D warnings" - "cargo build --verbose" From b115a047ed78e2bb743d961ebf99987b278be480 Mon Sep 17 00:00:00 2001 From: Jimmy Cuadra Date: Sat, 3 Aug 2019 14:00:41 -0700 Subject: [PATCH 071/139] Only build PRs and the master branch on CI. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index e6c1d326..8a42cce0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,7 @@ script: - "cargo clippy --all-targets --all-features -- -D warnings" - "cargo build --verbose" - "cargo test --verbose" +if: "type != push OR (tag IS blank AND branch = master)" notifications: email: false irc: From ef380003ffd7d3223078c18c7196307f968556c0 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sat, 20 Jul 2019 01:50:25 +0200 Subject: [PATCH 072/139] Update to std::future::Futures, feature(async_await) --- Cargo.toml | 25 +- examples/hello_world.rs | 84 +++---- src/api.rs | 528 ---------------------------------------- src/lib.rs | 237 +++++++++--------- 4 files changed, 178 insertions(+), 696 deletions(-) delete mode 100644 src/api.rs diff --git a/Cargo.toml b/Cargo.toml index 698483bc..58bb3266 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,16 +13,17 @@ repository = "https://github.com/ruma/ruma-client" version = "0.2.0" [dependencies] -futures = "0.1.26" +futures-preview = "0.3.0-alpha.17" http = "0.1.17" -hyper = "0.12.27" -ruma-api = "0.7.0" -ruma-client-api = "0.3.0" -ruma-identifiers = "0.12.0" +ruma-api = "0.9.0" +ruma-identifiers = "0.13.1" serde_json = "1.0.39" serde_urlencoded = "0.5.4" url = "1.7.2" +[dependencies.hyper] +git = "https://github.com/hyperium/hyper" + [dependencies.hyper-tls] optional = true version = "0.3.2" @@ -31,14 +32,20 @@ version = "0.3.2" optional = true version = "0.2.2" +[dependencies.ruma-client-api] +git = "https://github.com/ruma/ruma-client-api" +branch = "update-deps" + [dependencies.serde] version = "1.0.90" features = ["derive"] -[dev-dependencies] -ruma-events = "0.12.0" -tokio = "0.1.18" +[dev-dependencies.ruma-events] +git = "https://github.com/ruma/ruma-events" + +[dev-dependencies.tokio] +git = "https://github.com/tokio-rs/tokio" [features] -default = ["tls"] +default = [] tls = ["hyper-tls", "native-tls"] diff --git a/examples/hello_world.rs b/examples/hello_world.rs index 227af951..e2e9ec7a 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -1,7 +1,9 @@ +#![feature(async_await)] + use std::{convert::TryFrom, env, process::exit}; -use futures::Future; -use ruma_client::{self, api::r0, Client}; +use ruma_client::{self, Client}; +use ruma_client_api::r0; use ruma_events::{ room::message::{MessageEventContent, MessageType, TextMessageEventContent}, EventType, @@ -9,49 +11,47 @@ use ruma_events::{ use ruma_identifiers::RoomAliasId; use url::Url; -// from https://stackoverflow.com/a/43992218/1592377 -macro_rules! clone { - (@param _) => ( _ ); - (@param $x:ident) => ( $x ); - ($($n:ident),+ => move |$($p:tt),+| $body:expr) => ( - { - $( let $n = $n.clone(); )+ - move |$(clone!(@param $p),)+| $body - } - ); -} +async fn hello_world(homeserver_url: Url, room: String) -> Result<(), ruma_client::Error> { + let client = Client::new(homeserver_url, None); -fn hello_world( - homeserver_url: Url, - room: String, -) -> impl Future { - let client = Client::https(homeserver_url, None).unwrap(); - - client.register_guest().and_then(clone!(client => move |_| { - r0::alias::get_alias::call(client, r0::alias::get_alias::Request { + client.register_guest().await?; + let response = client + .request::(r0::alias::get_alias::Request { room_alias: RoomAliasId::try_from(&room[..]).unwrap(), }) - })).and_then(clone!(client => move |response| { - 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, - }).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(|_| ()) + let room_id = response.room_id; + + client + .request::( + r0::membership::join_room_by_id::Request { + room_id: room_id.clone(), + third_party_signed: None, + }, + ) + .await?; + + client.request::( + r0::send::send_message_event::Request { + room_id: room_id, + event_type: EventType::RoomMessage, + txn_id: "1".to_owned(), + data: MessageEventContent::Text(TextMessageEventContent { + msgtype: MessageType::Text, + body: "Hello World!".to_owned(), + format: None, + formatted_body: None, + relates_to: None, + }), + }, + ).await?; + + Ok(()) } -fn main() { +#[tokio::main] +async fn main() -> Result<(), ruma_client::Error> { let (homeserver_url, room) = match (env::args().nth(1), env::args().nth(2)) { (Some(a), Some(b)) => (a, b), _ => { @@ -63,9 +63,5 @@ fn main() { } }; - tokio::run( - hello_world(homeserver_url.parse().unwrap(), room).map_err(|e| { - dbg!(e); - }), - ); + hello_world(homeserver_url.parse().unwrap(), room).await } diff --git a/src/api.rs b/src/api.rs deleted file mode 100644 index 13bf95fe..00000000 --- a/src/api.rs +++ /dev/null @@ -1,528 +0,0 @@ -macro_rules! endpoint { - // No reexports besides `Request` and `Response`. - ($(#[$attr:meta])+ [$($outer_mod:ident),*], $inner_mod:ident) => { - endpoint!($(#[$attr])+ [$($outer_mod),*], $inner_mod, []); - }; - - // No imports from super. - ($(#[$attr:meta])+ [$($outer_mod:ident),*], $inner_mod:ident, [$($import:ident),*]) => { - endpoint!($(#[$attr])+ [$($outer_mod),*], $inner_mod, [$($import),*], []); - }; - - // Explicit case. - ( - $(#[$attr:meta])+ - [$($outer_mod:ident),*], - $inner_mod:ident, - [$($import:ident),*], - [$($super_import:ident),*] - ) => { - #[$($attr)+] - pub mod $inner_mod { - use futures::Future; - use hyper::client::connect::Connect; - use ruma_client_api::$($outer_mod::)*$inner_mod::Endpoint; - $(use super::$super_import;)* - pub use ruma_client_api::$($outer_mod::)*$inner_mod::{ - Request, - Response, - $($import),* - }; - - use crate::{Client, Error}; - - /// Make a request to this API endpoint. - pub fn call( - client: Client, - request: Request, - ) -> impl Future - where - C: Connect + 'static, - { - client.request::(request) - } - } - }; -} - -/// Endpoints for the r0.x.x versions of the client API specification. -pub mod r0 { - /// Account registration and management. - pub mod account { - endpoint!( - /// Change the password for an account on this homeserver. - [r0, account], - change_password - ); - - endpoint!( - /// Deactivate the user's account, removing all ability for the user to log in again. - [r0, account], - deactivate - ); - - endpoint!( - /// Register for an account on this homeserver. - [r0, account], - register, - [AuthenticationData, RegistrationKind] - ); - - endpoint!( - /// Request a password change token by email. - [r0, account], - request_password_change_token - ); - - endpoint!( - /// Request an account registration token by email. - [r0, account], - request_register_token - ); - } - - /// Room aliases. - pub mod alias { - endpoint!( - /// Create a new mapping from a room alias to a room ID. - [r0, alias], - create_alias - ); - - endpoint!( - /// Remove a mapping from a room alias to a room ID. - [r0, alias], - delete_alias - ); - - endpoint!( - /// Resolve a room alias to the corresponding room ID. - [r0, alias], - get_alias - ); - } - - /// Client configuration. - pub mod config { - endpoint!( - /// Set account data for the user. - [r0, config], - set_global_account_data - ); - - endpoint!( - /// Set account data scoped to a room for the user. - [r0, config], - set_room_account_data - ); - } - - /// Account contact information. - pub mod contact { - endpoint!( - /// Add contact information to the user's account. - [r0, contact], - create_contact, - [ThreePidCredentials] - ); - - endpoint!( - /// Get a list of the third party identifiers that the homeserver has associated with the user's account. - [r0, contact], - get_contacts, - [Medium, ThirdPartyIdentifier] - ); - - endpoint!( - /// Request an email address verification token by email. - [r0, contact], - request_contact_verification_token - ); - } - - /// Event context. - pub mod context { - endpoint!( - /// Get a number of events that happened just before and after a given event. - [r0, context], - get_context - ); - } - - /// The public room directory. - pub mod directory { - endpoint!( - /// Get a number of events that happened just before and after a given event. - [r0, directory], - get_public_rooms, - [PublicRoomsChunk] - ); - } - - /// Event filters. - pub mod filter { - pub use ruma_client_api::r0::filter::{ - EventFormat, Filter, FilterDefinition, RoomEventFilter, RoomFilter, - }; - - endpoint!( - /// Create a new filter. - [r0, filter], - create_filter - ); - - endpoint!( - /// Get a filter. - [r0, filter], - get_filter - ); - } - - /// Media repository. - pub mod media { - endpoint!( - /// Upload media to the media repository. - [r0, media], - create_content - ); - - endpoint!( - /// Download media from the media repository. - [r0, media], - get_content - ); - - endpoint!( - /// Download a thumbnail image for the media in the media repository. - [r0, media], - get_content_thumbnail, - [Method] - ); - } - - /// Room membership. - pub mod membership { - pub use ruma_client_api::r0::membership::ThirdPartySigned; - - endpoint!( - /// Ban a user from a room. - [r0, membership], - ban_user - ); - - endpoint!( - /// Permanently forget a room. - [r0, membership], - forget_room - ); - - endpoint!( - /// Invite a user to a room. - [r0, membership], - invite_user - ); - - endpoint!( - /// Join a room using its ID. - [r0, membership], - join_room_by_id - ); - - endpoint!( - /// Join a room using its ID or an alias. - [r0, membership], - join_room_by_id_or_alias - ); - - endpoint!( - /// Get a list of the user's current rooms. - [r0, membership], - joined_rooms - ); - - endpoint!( - /// Kick a user from a room. - [r0, membership], - kick_user - ); - - endpoint!( - /// Leave a room. - [r0, membership], - leave_room - ); - - endpoint!( - /// Unban a user from a room. - [r0, membership], - unban_user - ); - } - - /// User presence. - pub mod presence { - endpoint!( - /// Get a user's presence state. - [r0, presence], - get_presence - ); - - endpoint!( - /// Get a list of presence events for users on the presence subscription list. - [r0, presence], - get_subscribed_presences - ); - - endpoint!( - /// Set a user's presence state. - [r0, presence], - set_presence - ); - - endpoint!( - /// Add or remove users from the presence subscription list. - [r0, presence], - update_presence_subscriptions - ); - } - - /// User profiles. - pub mod profile { - endpoint!( - /// Get the URL for a user's avatar. - [r0, profile], - get_avatar_url - ); - - endpoint!( - /// Get a user's display name. - [r0, profile], - get_display_name - ); - - endpoint!( - /// Get a user's full profile. - [r0, profile], - get_profile - ); - - endpoint!( - /// Set the URL to the user's avatar. - [r0, profile], - set_avatar_url - ); - - endpoint!( - /// Set the user's display name. - [r0, profile], - set_display_name - ); - } - - /// Push notifications. - pub mod push {} - - /// Event receipts. - pub mod receipt { - endpoint!( - /// Update a receipt marker to point to a given event. - [r0, receipt], - create_receipt, - [ReceiptType] - ); - } - - /// Event redaction. - pub mod redact { - endpoint!( - /// Redact an event from a room. - [r0, redact], - redact_event - ); - } - - /// Room creation. - pub mod room { - endpoint!( - /// Create a room. - [r0, room], - create_room, - [CreationContent, RoomPreset, Visibility] - ); - } - - /// Event searches. - pub mod search { - endpoint!( - /// Search for events. - [r0, search], - search_events, - [ - Categories, - Criteria, - EventContext, - EventContextResult, - Grouping, - Groupings, - ResultCategories, - ResultGroup, - RoomEventResults, - SearchResult, - UserProfile, - GroupingKey, - OrderBy, - SearchKeys - ] - ); - } - - /// Sending events. - pub mod send { - endpoint!( - /// Send a message to a room. - [r0, send], - send_message_event - ); - - endpoint!( - /// Send a state event with an empty state key. - [r0, send], - send_state_event_for_empty_key - ); - - endpoint!( - /// Send a state event with a particular state key. - [r0, send], - send_state_event_for_key - ); - } - - /// Server administration. - pub mod server { - endpoint!( - /// Get administrative information about a user. - [r0, server], - get_user_info, - [ConnectionInfo, DeviceInfo, SessionInfo] - ); - } - - /// User session management. - pub mod session { - endpoint!( - /// Log in to an account, creating an access token. - [r0, session], - login, - [LoginType, Medium] - ); - - endpoint!( - /// Log out of an account by invalidating the access token. - [r0, session], - logout - ); - } - - /// Getting and synchronizing events. - pub mod sync { - endpoint!( - /// Get the list of members for a room. - [r0, sync], - get_member_events - ); - - endpoint!( - /// Get message and state events for a room. - [r0, sync], - get_message_events, - [Direction] - ); - - endpoint!( - /// Get the state events for the current state of a room. - [r0, sync], - get_state_events - ); - - endpoint!( - /// Get a particular state event with an empty state key for a room. - [r0, sync], - get_state_events_for_empty_key - ); - - endpoint!( - /// Get a particular state event with a particular state key for a room. - [r0, sync], - get_state_events_for_key - ); - - endpoint!( - /// Synchronize the client's state with the latest state on the homeserver. - [r0, sync], - sync_events, - [ - AccountData, - Ephemeral, - Filter, - InviteState, - InvitedRoom, - JoinedRoom, - LeftRoom, - Presence, - Rooms, - SetPresence, - State, - Timeline, - UnreadNotificationsCount - ] - ); - } - - /// Tagging rooms. - pub mod tag { - endpoint!( - /// Create a tag on a room. - [r0, tag], - create_tag - ); - - endpoint!( - /// Delete a tag on a room. - [r0, tag], - delete_tag - ); - - endpoint!( - /// Get the user's tags for a room. - [r0, tag], - get_tags - ); - } - - /// Typing notifications. - pub mod typing { - endpoint!( - /// Indicate that the user is currently typing. - [r0, typing], - create_typing_event - ); - } - - /// Voice over IP. - pub mod voip { - endpoint!( - /// Get credentials for initiating voice over IP calls via a TURN server. - [r0, voip], - get_turn_server_info - ); - } -} - -/// Endpoints that cannot change with new versions of the Matrix specification. -pub mod unversioned { - endpoint!( - /// Get the versions of the specification supported by this homeserver. - [unversioned], - get_supported_versions - ); -} diff --git a/src/lib.rs b/src/lib.rs index 0a8e5896..bd148382 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,11 +75,12 @@ //! // Start `work` on a futures runtime... //! ``` +#![feature(async_await, async_closure)] #![deny( missing_copy_implementations, missing_debug_implementations, missing_docs, - warnings + //warnings )] #![warn( clippy::empty_line_after_outer_attr, @@ -101,15 +102,16 @@ )] use std::{ - convert::TryInto, + convert::{TryFrom, TryInto}, str::FromStr, sync::{Arc, Mutex}, }; use futures::{ - future::{Future, FutureFrom, IntoFuture}, - stream::{self, Stream}, + future::Future, + stream::{self, TryStream, TryStreamExt as _}, }; +use http::Response as HttpResponse; use hyper::{ client::{connect::Connect, HttpConnector}, Client as HyperClient, Uri, @@ -125,7 +127,7 @@ use crate::error::InnerError; pub use crate::{error::Error, session::Session}; /// Matrix client-server API endpoints. -pub mod api; +//pub mod api; mod error; mod session; @@ -177,7 +179,7 @@ impl Client> { Ok(Self(Arc::new(ClientData { homeserver_url, - hyper: { HyperClient::builder().keep_alive(true).build(connector) }, + hyper: HyperClient::builder().keep_alive(true).build(connector), session: Mutex::new(session), }))) } @@ -207,50 +209,43 @@ 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( + pub async fn log_in( &self, user: String, password: String, device_id: Option, - ) -> impl Future { - use crate::api::r0::session::login; + ) -> Result { + use ruma_client_api::r0::session::login; - let data = self.0.clone(); - - login::call( - self.clone(), - login::Request { + let response = self + .request::(login::Request { address: None, login_type: login::LoginType::Password, medium: None, device_id, password, user, - }, - ) - .map(move |response| { - let session = Session { - access_token: response.access_token, - device_id: response.device_id, - user_id: response.user_id, - }; - *data.session.lock().unwrap() = Some(session.clone()); + }) + .await?; - session - }) + let session = Session { + access_token: response.access_token, + device_id: response.device_id, + user_id: response.user_id, + }; + *self.0.session.lock().unwrap() = Some(session.clone()); + + Ok(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 { - use crate::api::r0::account::register; + pub async fn register_guest(&self) -> Result { + use ruma_client_api::r0::account::register; - let data = self.0.clone(); - - register::call( - self.clone(), - register::Request { + let response = self + .request::(register::Request { auth: None, bind_email: None, device_id: None, @@ -258,18 +253,17 @@ where kind: Some(register::RegistrationKind::Guest), password: None, username: None, - }, - ) - .map(move |response| { - let session = Session { - access_token: response.access_token, - device_id: response.device_id, - user_id: response.user_id, - }; - *data.session.lock().unwrap() = Some(session.clone()); + }) + .await?; - session - }) + let session = Session { + access_token: response.access_token, + device_id: response.device_id, + user_id: response.user_id, + }; + *self.0.session.lock().unwrap() = Some(session.clone()); + + Ok(session) } /// Register as a new user on this server. @@ -280,18 +274,15 @@ 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( + pub async fn register_user( &self, username: Option, password: String, - ) -> impl Future { - use crate::api::r0::account::register; + ) -> Result { + use ruma_client_api::r0::account::register; - let data = self.0.clone(); - - register::call( - self.clone(), - register::Request { + let response = self + .request::(register::Request { auth: None, bind_email: None, device_id: None, @@ -299,18 +290,17 @@ where kind: Some(register::RegistrationKind::User), password: Some(password), username, - }, - ) - .map(move |response| { - let session = Session { - access_token: response.access_token, - device_id: response.device_id, - user_id: response.user_id, - }; - *data.session.lock().unwrap() = Some(session.clone()); + }) + .await?; - session - }) + let session = Session { + access_token: response.access_token, + device_id: response.device_id, + user_id: response.user_id, + }; + *self.0.session.lock().unwrap() = Some(session.clone()); + + Ok(session) } /// Convenience method that represents repeated calls to the sync_events endpoint as a stream. @@ -320,11 +310,19 @@ where /// the logged-in users account and are visible to them. pub fn sync( &self, - filter: Option, + filter: Option, since: Option, set_presence: bool, - ) -> impl Stream { - use crate::api::r0::sync::sync_events; + ) -> impl TryStream { + use ruma_client_api::r0::sync::sync_events; + + // TODO: Is this really the way TryStreams are supposed to work? + #[derive(Debug, PartialEq, Eq)] + enum State { + InitialSync, + Since(String), + Errored, + } let client = self.clone(); let set_presence = if set_presence { @@ -333,71 +331,80 @@ where Some(sync_events::SetPresence::Offline) }; - stream::unfold(since, move |since| { - Some( - sync_events::call( - client.clone(), - sync_events::Request { - filter: filter.clone(), + let initial_state = match since { + Some(s) => State::Since(s), + None => State::InitialSync, + }; + + stream::unfold(initial_state, move |state| { + let client = client.clone(); + let filter = filter.clone(); + + async move { + let since = match state { + State::Errored => return None, + State::Since(s) => Some(s), + State::InitialSync => None, + }; + + let res = client + .request::(sync_events::Request { + filter, 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)) - }), - ) + }) + .await; + + match res { + Ok(response) => { + let next_batch_clone = response.next_batch.clone(); + Some((Ok(response), State::Since(next_batch_clone))) + } + Err(e) => Some((Err(e.into()), State::Errored)), + } + } }) } /// Makes a request to a Matrix API endpoint. - pub(crate) fn request( - self, - request: ::Request, - ) -> impl Future - where - E: Endpoint, - { - let data1 = self.0.clone(); - let data2 = self.0.clone(); - let mut url = self.0.homeserver_url.clone(); + pub fn request( + &self, + request: E::Request, + ) -> impl Future> { + let client = self.0.clone(); - request - .try_into() - .map_err(Error::from) - .into_future() - .and_then(move |hyper_request| { - { - let uri = hyper_request.uri(); + async move { + let mut url = client.homeserver_url.clone(); - url.set_path(uri.path()); - url.set_query(uri.query()); + let mut hyper_request = request.try_into()?.map(hyper::Body::from); - if E::METADATA.requires_authentication { - if let Some(ref session) = *data1.session.lock().unwrap() { - url.query_pairs_mut() - .append_pair("access_token", &session.access_token); - } else { - return Err(Error(InnerError::AuthenticationRequired)); - } + { + let uri = hyper_request.uri(); + + url.set_path(uri.path()); + url.set_query(uri.query()); + + if E::METADATA.requires_authentication { + if let Some(ref session) = *client.session.lock().unwrap() { + url.query_pairs_mut() + .append_pair("access_token", &session.access_token); + } else { + return Err(Error(InnerError::AuthenticationRequired)); } } + } - Uri::from_str(url.as_ref()) - .map(move |uri| (uri, hyper_request)) - .map_err(Error::from) - }) - .and_then(move |(uri, mut hyper_request)| { - *hyper_request.uri_mut() = uri; + *hyper_request.uri_mut() = Uri::from_str(url.as_ref())?; - data2.hyper.request(hyper_request).map_err(Error::from) - }) - .and_then(|hyper_response| { - E::Response::future_from(hyper_response).map_err(Error::from) - }) + let hyper_response = client.hyper.request(hyper_request).await?; + let (head, body) = hyper_response.into_parts(); + let full_response = + HttpResponse::from_parts(head, body.try_concat().await?.as_ref().to_owned()); + + Ok(E::Response::try_from(full_response)?) + } } } From 419a04609857e3c646c0cfb6f39324e81542b9f1 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sat, 20 Jul 2019 12:54:30 +0200 Subject: [PATCH 073/139] Specify ruma-events git rev --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 58bb3266..340306a9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -42,6 +42,7 @@ features = ["derive"] [dev-dependencies.ruma-events] git = "https://github.com/ruma/ruma-events" +rev = "1b0be0d0e7fa1040fc51b748256b290e24677b19" [dev-dependencies.tokio] git = "https://github.com/tokio-rs/tokio" From bbeb4376352fb5f1a80b7e52ffda014cc6d12a95 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sat, 20 Jul 2019 14:23:12 +0200 Subject: [PATCH 074/139] Export type aliases HttpClient and HttpsClient --- src/lib.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index bd148382..6c6c2c1b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -149,7 +149,10 @@ where session: Mutex>, } -impl Client { +/// Non-secured variant of the client (using plain HTTP requests) +pub type HttpClient = Client; + +impl HttpClient { /// Creates a new client for making HTTP requests to the given homeserver. pub fn new(homeserver_url: Url, session: Option) -> Self { Self(Arc::new(ClientData { @@ -171,8 +174,12 @@ impl Client { } } +/// Secured variant of the client (using HTTPS requests) #[cfg(feature = "tls")] -impl Client> { +pub type HttpsClient = Client>; + +#[cfg(feature = "tls")] +impl HttpsClient { /// Creates a new client for making HTTPS requests to the given homeserver. pub fn https(homeserver_url: Url, session: Option) -> Result { let connector = HttpsConnector::new(4)?; From d9a88cb63fb3fa0c5fb175c0ed5ffb762b894f6c Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sat, 20 Jul 2019 20:34:18 +0200 Subject: [PATCH 075/139] Improve return type of sync --- src/lib.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 6c6c2c1b..cea6c75a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -109,7 +109,7 @@ use std::{ use futures::{ future::Future, - stream::{self, TryStream, TryStreamExt as _}, + stream::{self, Stream, TryStream, TryStreamExt as _}, }; use http::Response as HttpResponse; use hyper::{ @@ -320,7 +320,9 @@ where filter: Option, since: Option, set_presence: bool, - ) -> impl TryStream { + ) -> impl Stream> + + TryStream + { use ruma_client_api::r0::sync::sync_events; // TODO: Is this really the way TryStreams are supposed to work? From b21b1cec8f91ceb3a566d970848576bcfe755d9c Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sat, 20 Jul 2019 20:34:44 +0200 Subject: [PATCH 076/139] Rerun rustfmt --- 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 e2e9ec7a..33dd36a9 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -32,8 +32,8 @@ async fn hello_world(homeserver_url: Url, room: String) -> Result<(), ruma_clien ) .await?; - client.request::( - r0::send::send_message_event::Request { + client + .request::(r0::send::send_message_event::Request { room_id: room_id, event_type: EventType::RoomMessage, txn_id: "1".to_owned(), @@ -44,8 +44,8 @@ async fn hello_world(homeserver_url: Url, room: String) -> Result<(), ruma_clien formatted_body: None, relates_to: None, }), - }, - ).await?; + }) + .await?; Ok(()) } From 489be83a57e50bac1c6effa8a9744bd6d5bd7df7 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sat, 20 Jul 2019 20:34:52 +0200 Subject: [PATCH 077/139] Re-add message_log example --- examples/message_log.rs | 59 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 examples/message_log.rs diff --git a/examples/message_log.rs b/examples/message_log.rs new file mode 100644 index 00000000..99a4704d --- /dev/null +++ b/examples/message_log.rs @@ -0,0 +1,59 @@ +#![feature(async_await)] + +use std::{env, process::exit}; + +use futures::stream::{StreamExt as _, TryStreamExt as _}; +use ruma_events::collections::all::RoomEvent; +use ruma_events::room::message::{MessageEvent, MessageEventContent, TextMessageEventContent}; +use url::Url; + +async fn log_messages( + homeserver_url: Url, + username: String, + password: String, +) -> Result<(), ruma_client::Error> { + let client = ruma_client::Client::new(homeserver_url, None); + + client.log_in(username, password, None).await?; + + // vvvvvvvv Skip initial sync reponse + let mut sync_stream = Box::pin(client.sync(None, None, false).skip(1)); + + while let Some(res) = sync_stream.try_next().await? { + // Only look at rooms the user hasn't left yet + for (room_id, room) in res.rooms.join { + for event in room.timeline.events { + // Filter out the text messages + if let RoomEvent::RoomMessage(MessageEvent { + content: + MessageEventContent::Text(TextMessageEventContent { body: msg_body, .. }), + sender, + .. + }) = event + { + println!("{:?} in {:?}: {}", sender, room_id, msg_body); + } + } + } + } + + Ok(()) +} + +#[tokio::main] +async fn main() -> Result<(), ruma_client::Error> { + let (homeserver_url, username, password) = + match (env::args().nth(1), env::args().nth(2), env::args().nth(3)) { + (Some(a), Some(b), Some(c)) => (a, b, c), + _ => { + eprintln!( + "Usage: {} ", + env::args().next().unwrap() + ); + exit(1) + } + }; + + let server = Url::parse(&homeserver_url).unwrap(); + log_messages(server, username, password).await +} From 5543edb7b9af188c37f8c1dd9e8ba5dae6639396 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sat, 20 Jul 2019 20:56:00 +0200 Subject: [PATCH 078/139] Export ruma_events, ruma_identifers --- Cargo.toml | 8 ++++---- examples/hello_world.rs | 15 +++++++++------ examples/message_log.rs | 12 +++++++++--- src/lib.rs | 3 +++ 4 files changed, 25 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 340306a9..c627f372 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,14 +36,14 @@ version = "0.2.2" git = "https://github.com/ruma/ruma-client-api" branch = "update-deps" +[dependencies.ruma-events] +git = "https://github.com/ruma/ruma-events" +rev = "1b0be0d0e7fa1040fc51b748256b290e24677b19" + [dependencies.serde] version = "1.0.90" features = ["derive"] -[dev-dependencies.ruma-events] -git = "https://github.com/ruma/ruma-events" -rev = "1b0be0d0e7fa1040fc51b748256b290e24677b19" - [dev-dependencies.tokio] git = "https://github.com/tokio-rs/tokio" diff --git a/examples/hello_world.rs b/examples/hello_world.rs index 33dd36a9..33d091ff 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -2,13 +2,16 @@ use std::{convert::TryFrom, env, process::exit}; -use ruma_client::{self, Client}; -use ruma_client_api::r0; -use ruma_events::{ - room::message::{MessageEventContent, MessageType, TextMessageEventContent}, - EventType, +use ruma_client::{ + self, + events::{ + room::message::{MessageEventContent, MessageType, TextMessageEventContent}, + EventType, + }, + identifiers::RoomAliasId, + Client, }; -use ruma_identifiers::RoomAliasId; +use ruma_client_api::r0; use url::Url; async fn hello_world(homeserver_url: Url, room: String) -> Result<(), ruma_client::Error> { diff --git a/examples/message_log.rs b/examples/message_log.rs index 99a4704d..ee1c2bd7 100644 --- a/examples/message_log.rs +++ b/examples/message_log.rs @@ -3,8 +3,14 @@ use std::{env, process::exit}; use futures::stream::{StreamExt as _, TryStreamExt as _}; -use ruma_events::collections::all::RoomEvent; -use ruma_events::room::message::{MessageEvent, MessageEventContent, TextMessageEventContent}; +use ruma_client::{ + self, + events::{ + collections::all::RoomEvent, + room::message::{MessageEvent, MessageEventContent, TextMessageEventContent}, + }, + HttpClient, +}; use url::Url; async fn log_messages( @@ -12,7 +18,7 @@ async fn log_messages( username: String, password: String, ) -> Result<(), ruma_client::Error> { - let client = ruma_client::Client::new(homeserver_url, None); + let client = HttpClient::new(homeserver_url, None); client.log_in(username, password, None).await?; diff --git a/src/lib.rs b/src/lib.rs index cea6c75a..c999ddf9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -124,7 +124,10 @@ use ruma_api::Endpoint; use url::Url; use crate::error::InnerError; + pub use crate::{error::Error, session::Session}; +pub use ruma_events as events; +pub use ruma_identifiers as identifiers; /// Matrix client-server API endpoints. //pub mod api; From cfaabe9486d55794fb1ab0218b57b7144acb4881 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sun, 21 Jul 2019 01:38:19 +0200 Subject: [PATCH 079/139] Use endpoint_is_request branch for ruma-[client-]api --- Cargo.toml | 4 ++-- examples/hello_world.rs | 14 ++++++-------- src/lib.rs | 20 ++++++++++---------- 3 files changed, 18 insertions(+), 20 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c627f372..b5e3d064 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,7 @@ version = "0.2.0" [dependencies] futures-preview = "0.3.0-alpha.17" http = "0.1.17" -ruma-api = "0.9.0" +ruma-api = { git = "https://github.com/ruma/ruma-api", branch = "endpoint_is_request" } ruma-identifiers = "0.13.1" serde_json = "1.0.39" serde_urlencoded = "0.5.4" @@ -34,7 +34,7 @@ version = "0.2.2" [dependencies.ruma-client-api] git = "https://github.com/ruma/ruma-client-api" -branch = "update-deps" +branch = "endpoint_is_request" [dependencies.ruma-events] git = "https://github.com/ruma/ruma-events" diff --git a/examples/hello_world.rs b/examples/hello_world.rs index 33d091ff..b88687e2 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -19,7 +19,7 @@ async fn hello_world(homeserver_url: Url, room: String) -> Result<(), ruma_clien client.register_guest().await?; let response = client - .request::(r0::alias::get_alias::Request { + .request(r0::alias::get_alias::Request { room_alias: RoomAliasId::try_from(&room[..]).unwrap(), }) .await?; @@ -27,16 +27,14 @@ async fn hello_world(homeserver_url: Url, room: String) -> Result<(), ruma_clien let room_id = response.room_id; client - .request::( - r0::membership::join_room_by_id::Request { - room_id: room_id.clone(), - third_party_signed: None, - }, - ) + .request(r0::membership::join_room_by_id::Request { + room_id: room_id.clone(), + third_party_signed: None, + }) .await?; client - .request::(r0::send::send_message_event::Request { + .request(r0::send::send_message_event::Request { room_id: room_id, event_type: EventType::RoomMessage, txn_id: "1".to_owned(), diff --git a/src/lib.rs b/src/lib.rs index c999ddf9..4a4c0918 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -102,7 +102,7 @@ )] use std::{ - convert::{TryFrom, TryInto}, + convert::TryFrom, str::FromStr, sync::{Arc, Mutex}, }; @@ -228,7 +228,7 @@ where use ruma_client_api::r0::session::login; let response = self - .request::(login::Request { + .request(login::Request { address: None, login_type: login::LoginType::Password, medium: None, @@ -255,7 +255,7 @@ where use ruma_client_api::r0::account::register; let response = self - .request::(register::Request { + .request(register::Request { auth: None, bind_email: None, device_id: None, @@ -292,7 +292,7 @@ where use ruma_client_api::r0::account::register; let response = self - .request::(register::Request { + .request(register::Request { auth: None, bind_email: None, device_id: None, @@ -360,7 +360,7 @@ where }; let res = client - .request::(sync_events::Request { + .request(sync_events::Request { filter, since, full_state: None, @@ -381,10 +381,10 @@ where } /// Makes a request to a Matrix API endpoint. - pub fn request( + pub fn request( &self, - request: E::Request, - ) -> impl Future> { + request: Request, + ) -> impl Future> { let client = self.0.clone(); async move { @@ -398,7 +398,7 @@ where url.set_path(uri.path()); url.set_query(uri.query()); - if E::METADATA.requires_authentication { + if Request::METADATA.requires_authentication { if let Some(ref session) = *client.session.lock().unwrap() { url.query_pairs_mut() .append_pair("access_token", &session.access_token); @@ -415,7 +415,7 @@ where let full_response = HttpResponse::from_parts(head, body.try_concat().await?.as_ref().to_owned()); - Ok(E::Response::try_from(full_response)?) + Ok(Request::Response::try_from(full_response)?) } } } From a71b286dcd0d72b6ff81efebd1cc45e63fbf28fa Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sun, 21 Jul 2019 01:41:52 +0200 Subject: [PATCH 080/139] Re-export ruma_client_api from ruma_client --- examples/hello_world.rs | 2 +- src/lib.rs | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/examples/hello_world.rs b/examples/hello_world.rs index b88687e2..6ff462a0 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -4,6 +4,7 @@ use std::{convert::TryFrom, env, process::exit}; use ruma_client::{ self, + api::r0, events::{ room::message::{MessageEventContent, MessageType, TextMessageEventContent}, EventType, @@ -11,7 +12,6 @@ use ruma_client::{ identifiers::RoomAliasId, Client, }; -use ruma_client_api::r0; use url::Url; async fn hello_world(homeserver_url: Url, room: String) -> Result<(), ruma_client::Error> { diff --git a/src/lib.rs b/src/lib.rs index 4a4c0918..2384a225 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -126,6 +126,7 @@ use url::Url; use crate::error::InnerError; pub use crate::{error::Error, session::Session}; +pub use ruma_client_api as api; pub use ruma_events as events; pub use ruma_identifiers as identifiers; @@ -225,7 +226,7 @@ where password: String, device_id: Option, ) -> Result { - use ruma_client_api::r0::session::login; + use api::r0::session::login; let response = self .request(login::Request { @@ -252,7 +253,7 @@ where /// this method stores the session data returned by the endpoint in this /// client, instead of returning it. pub async fn register_guest(&self) -> Result { - use ruma_client_api::r0::account::register; + use api::r0::account::register; let response = self .request(register::Request { @@ -289,7 +290,7 @@ where username: Option, password: String, ) -> Result { - use ruma_client_api::r0::account::register; + use api::r0::account::register; let response = self .request(register::Request { @@ -320,13 +321,12 @@ where /// the logged-in users account and are visible to them. pub fn sync( &self, - filter: Option, + filter: Option, since: Option, set_presence: bool, - ) -> impl Stream> - + TryStream - { - use ruma_client_api::r0::sync::sync_events; + ) -> impl Stream> + + TryStream { + use api::r0::sync::sync_events; // TODO: Is this really the way TryStreams are supposed to work? #[derive(Debug, PartialEq, Eq)] From b2cb9a67b3c32f155d6711a747ac3296b53f1116 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 26 Jul 2019 01:40:24 +0200 Subject: [PATCH 081/139] Re-enable tls by default, update deps --- Cargo.toml | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b5e3d064..a6c738d0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,27 +15,22 @@ version = "0.2.0" [dependencies] futures-preview = "0.3.0-alpha.17" http = "0.1.17" -ruma-api = { git = "https://github.com/ruma/ruma-api", branch = "endpoint_is_request" } -ruma-identifiers = "0.13.1" +hyper = { git = "https://github.com/hyperium/hyper" } +ruma-api = { git = "https://github.com/ruma/ruma-api" } +ruma-client-api = { git = "https://github.com/ruma/ruma-client-api", branch = "update-deps" } +ruma-identifiers = "0.14.0" serde_json = "1.0.39" serde_urlencoded = "0.5.4" url = "1.7.2" -[dependencies.hyper] -git = "https://github.com/hyperium/hyper" - [dependencies.hyper-tls] optional = true -version = "0.3.2" +git = "https://github.com/hyperium/hyper-tls" [dependencies.native-tls] optional = true version = "0.2.2" -[dependencies.ruma-client-api] -git = "https://github.com/ruma/ruma-client-api" -branch = "endpoint_is_request" - [dependencies.ruma-events] git = "https://github.com/ruma/ruma-events" rev = "1b0be0d0e7fa1040fc51b748256b290e24677b19" @@ -48,5 +43,5 @@ features = ["derive"] git = "https://github.com/tokio-rs/tokio" [features] -default = [] +default = ["tls"] tls = ["hyper-tls", "native-tls"] From 098c1d767c912db4ae922bae02e959b12afc4018 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 26 Jul 2019 01:40:31 +0200 Subject: [PATCH 082/139] Update doc-tests --- src/lib.rs | 60 +++++++++++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 26 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 2384a225..0508cd81 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,21 +6,26 @@ //! secure connections, and then logging in: //! //! ```no_run -//! use futures::Future; +//! # #![feature(impl_trait_in_bindings)] +//! #![feature(async_await)] //! use ruma_client::Client; //! -//! let homeserver_url = "https://example.com".parse().unwrap(); -//! let client = Client::https(homeserver_url, None).unwrap(); +//! let work = async { +//! let homeserver_url = "https://example.com".parse().unwrap(); +//! let client = Client::https(homeserver_url, None).unwrap(); //! -//! let work = client -//! .log_in("@alice:example.com".to_string(), "secret".to_string(), None) -//! .and_then(|session| { -//! // You're now logged in! Write the session to a file if you want to restore it later. -//! // Then start using the API! -//! # Ok::<(), ruma_client::Error>(()) -//! }); +//! let session = client +//! .log_in("@alice:example.com".to_string(), "secret".to_string(), None) +//! .await?; +//! +//! // You're now logged in! Write the session to a file if you want to restore it later. +//! // Then start using the API! +//! # Ok(()) +//! }; //! //! // Start `work` on a futures runtime... +//! # let work_typehint: impl futures::future::TryFuture +//! # = work; //! ``` //! //! You can also pass an existing session to the `Client` constructor to restore a previous session @@ -30,16 +35,18 @@ //! events), use the `Client::sync`: //! //! ```no_run -//! # use futures::{Future, Stream}; +//! # #![feature(async_await)] +//! # use futures::stream::{StreamExt as _, TryStreamExt as _}; //! # use ruma_client::Client; //! # let homeserver_url = "https://example.com".parse().unwrap(); //! # let client = Client::https(homeserver_url, None).unwrap(); -//! let work = client.sync(None, None, true).map(|response| { -//! // Do something with the data in the response... -//! # Ok::<(), ruma_client::Error>(()) -//! }); -//! -//! // Start `work` on a futures runtime... +//! # async { +//! let mut sync_stream = Box::pin(client.sync(None, None, true)); +//! while let Some(response) = sync_stream.try_next().await? { +//! // Do something with the data in the response... +//! } +//! # Result::<(), ruma_client::Error>::Ok(()) +//! # }; //! ``` //! //! The `Client` type also provides methods for registering a new account if you don't already have @@ -54,7 +61,7 @@ //! For example: //! //! ```no_run -//! # use futures::Future; +//! # #![feature(async_await)] //! # use ruma_client::Client; //! # let homeserver_url = "https://example.com".parse().unwrap(); //! # let client = Client::https(homeserver_url, None).unwrap(); @@ -63,16 +70,17 @@ //! use ruma_client::api::r0::alias::get_alias; //! use ruma_identifiers::{RoomAliasId, RoomId}; //! -//! let request = get_alias::Request { -//! room_alias: RoomAliasId::try_from("#example_room:example.com").unwrap(), -//! }; +//! async { +//! let response = client +//! .request(get_alias::Request { +//! room_alias: RoomAliasId::try_from("#example_room:example.com").unwrap(), +//! }) +//! .await?; //! -//! let work = get_alias::call(client, request).and_then(|response| { //! assert_eq!(response.room_id, RoomId::try_from("!n8f893n9:example.com").unwrap()); -//! # Ok::<(), ruma_client::Error>(()) -//! }); -//! -//! // Start `work` on a futures runtime... +//! # Result::<(), ruma_client::Error>::Ok(()) +//! } +//! # ; //! ``` #![feature(async_await, async_closure)] From 413f489f0caa5a30aa6c142d9a293dbb2eb6cd71 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sun, 4 Aug 2019 16:42:33 +0200 Subject: [PATCH 083/139] Update dependencies --- Cargo.toml | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a6c738d0..fd124c62 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,14 +14,14 @@ version = "0.2.0" [dependencies] futures-preview = "0.3.0-alpha.17" -http = "0.1.17" +http = "0.1.18" hyper = { git = "https://github.com/hyperium/hyper" } -ruma-api = { git = "https://github.com/ruma/ruma-api" } -ruma-client-api = { git = "https://github.com/ruma/ruma-client-api", branch = "update-deps" } +ruma-api = "0.10.0" +ruma-client-api = { git = "https://github.com/ruma/ruma-client-api" } ruma-identifiers = "0.14.0" -serde_json = "1.0.39" -serde_urlencoded = "0.5.4" -url = "1.7.2" +serde_json = "1.0.40" +serde_urlencoded = "0.6.1" +url = "2.0.0" [dependencies.hyper-tls] optional = true @@ -29,14 +29,14 @@ git = "https://github.com/hyperium/hyper-tls" [dependencies.native-tls] optional = true -version = "0.2.2" +version = "0.2.3" [dependencies.ruma-events] git = "https://github.com/ruma/ruma-events" rev = "1b0be0d0e7fa1040fc51b748256b290e24677b19" [dependencies.serde] -version = "1.0.90" +version = "1.0.98" features = ["derive"] [dev-dependencies.tokio] @@ -45,3 +45,7 @@ git = "https://github.com/tokio-rs/tokio" [features] default = ["tls"] tls = ["hyper-tls", "native-tls"] + +[patch.crates-io.ruma-events] +git = "https://github.com/ruma/ruma-events" +rev = "1b0be0d0e7fa1040fc51b748256b290e24677b19" \ No newline at end of file From 721dc6f413ba0059ed6641f5875afcd8752c81dc Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sat, 7 Sep 2019 11:59:00 +0200 Subject: [PATCH 084/139] Update dependencies --- Cargo.toml | 14 +++++++------- src/lib.rs | 5 ++--- 2 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fd124c62..e19da024 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,17 +15,17 @@ version = "0.2.0" [dependencies] futures-preview = "0.3.0-alpha.17" http = "0.1.18" -hyper = { git = "https://github.com/hyperium/hyper" } +hyper = "0.13.0-alpha.1" ruma-api = "0.10.0" ruma-client-api = { git = "https://github.com/ruma/ruma-client-api" } ruma-identifiers = "0.14.0" serde_json = "1.0.40" serde_urlencoded = "0.6.1" -url = "2.0.0" +url = "2.1.0" [dependencies.hyper-tls] optional = true -git = "https://github.com/hyperium/hyper-tls" +version = "0.4.0-alpha.1" [dependencies.native-tls] optional = true @@ -36,11 +36,11 @@ git = "https://github.com/ruma/ruma-events" rev = "1b0be0d0e7fa1040fc51b748256b290e24677b19" [dependencies.serde] -version = "1.0.98" +version = "1.0.99" features = ["derive"] -[dev-dependencies.tokio] -git = "https://github.com/tokio-rs/tokio" +[dev-dependencies] +tokio = "0.2.0-alpha.4" [features] default = ["tls"] @@ -48,4 +48,4 @@ tls = ["hyper-tls", "native-tls"] [patch.crates-io.ruma-events] git = "https://github.com/ruma/ruma-events" -rev = "1b0be0d0e7fa1040fc51b748256b290e24677b19" \ No newline at end of file +rev = "1b0be0d0e7fa1040fc51b748256b290e24677b19" diff --git a/src/lib.rs b/src/lib.rs index 0508cd81..e27317fe 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -83,7 +83,6 @@ //! # ; //! ``` -#![feature(async_await, async_closure)] #![deny( missing_copy_implementations, missing_debug_implementations, @@ -194,7 +193,7 @@ pub type HttpsClient = Client>; impl HttpsClient { /// Creates a new client for making HTTPS requests to the given homeserver. pub fn https(homeserver_url: Url, session: Option) -> Result { - let connector = HttpsConnector::new(4)?; + let connector = HttpsConnector::new()?; Ok(Self(Arc::new(ClientData { homeserver_url, @@ -333,7 +332,7 @@ where since: Option, set_presence: bool, ) -> impl Stream> - + TryStream { + + TryStream { use api::r0::sync::sync_events; // TODO: Is this really the way TryStreams are supposed to work? From af9f08ad2d766a147969160a2cdb180cadb5999a Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 3 Oct 2019 11:11:48 +0200 Subject: [PATCH 085/139] Update dependencies --- Cargo.toml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e19da024..745e847c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,9 +13,9 @@ repository = "https://github.com/ruma/ruma-client" version = "0.2.0" [dependencies] -futures-preview = "0.3.0-alpha.17" +futures-preview = "0.3.0-alpha.18" http = "0.1.18" -hyper = "0.13.0-alpha.1" +hyper = { version = "0.13.0-alpha.4", features = ["unstable-stream"] } ruma-api = "0.10.0" ruma-client-api = { git = "https://github.com/ruma/ruma-client-api" } ruma-identifiers = "0.14.0" @@ -25,7 +25,7 @@ url = "2.1.0" [dependencies.hyper-tls] optional = true -version = "0.4.0-alpha.1" +version = "0.4.0-alpha.4" [dependencies.native-tls] optional = true @@ -36,11 +36,11 @@ git = "https://github.com/ruma/ruma-events" rev = "1b0be0d0e7fa1040fc51b748256b290e24677b19" [dependencies.serde] -version = "1.0.99" +version = "1.0.101" features = ["derive"] [dev-dependencies] -tokio = "0.2.0-alpha.4" +tokio = "0.2.0-alpha.6" [features] default = ["tls"] From 4329d32af716ab611c0a7ec9037f81272741ca64 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Mon, 14 Oct 2019 22:31:47 +0200 Subject: [PATCH 086/139] Update deps --- Cargo.toml | 30 +++++++----------------------- 1 file changed, 7 insertions(+), 23 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 745e847c..b416446d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,39 +13,23 @@ repository = "https://github.com/ruma/ruma-client" version = "0.2.0" [dependencies] -futures-preview = "0.3.0-alpha.18" +futures-preview = "0.3.0-alpha.19" http = "0.1.18" hyper = { version = "0.13.0-alpha.4", features = ["unstable-stream"] } +hyper-tls = { version = "0.4.0-alpha.4", optional = true } ruma-api = "0.10.0" -ruma-client-api = { git = "https://github.com/ruma/ruma-client-api" } +ruma-client-api = { git = "https://github.com/ruma/ruma-client-api", branch = "event-result" } +ruma-events = { git = "https://github.com/ruma/ruma-events", branch = "event-result-2" } ruma-identifiers = "0.14.0" -serde_json = "1.0.40" +native-tls = { version = "0.2.3", optional = true } +serde = { version = "1.0.101", features = ["derive"] } +serde_json = "1.0.41" serde_urlencoded = "0.6.1" url = "2.1.0" -[dependencies.hyper-tls] -optional = true -version = "0.4.0-alpha.4" - -[dependencies.native-tls] -optional = true -version = "0.2.3" - -[dependencies.ruma-events] -git = "https://github.com/ruma/ruma-events" -rev = "1b0be0d0e7fa1040fc51b748256b290e24677b19" - -[dependencies.serde] -version = "1.0.101" -features = ["derive"] - [dev-dependencies] tokio = "0.2.0-alpha.6" [features] default = ["tls"] tls = ["hyper-tls", "native-tls"] - -[patch.crates-io.ruma-events] -git = "https://github.com/ruma/ruma-events" -rev = "1b0be0d0e7fa1040fc51b748256b290e24677b19" From 0dbd20285fe1367b60f45c1cb55df5eebdda3ee9 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 17 Oct 2019 00:43:24 +0200 Subject: [PATCH 087/139] Update ruma-api --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index b416446d..6fd59e5d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,7 +17,7 @@ futures-preview = "0.3.0-alpha.19" http = "0.1.18" hyper = { version = "0.13.0-alpha.4", features = ["unstable-stream"] } hyper-tls = { version = "0.4.0-alpha.4", optional = true } -ruma-api = "0.10.0" +ruma-api = { git = "https://github.com/ruma/ruma-api", branch = "serverless" } ruma-client-api = { git = "https://github.com/ruma/ruma-client-api", branch = "event-result" } ruma-events = { git = "https://github.com/ruma/ruma-events", branch = "event-result-2" } ruma-identifiers = "0.14.0" From a55fe5511ecfac39f9fb6ac071cc3d2d853ce0ca Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Wed, 30 Oct 2019 18:43:22 +0100 Subject: [PATCH 088/139] Remove #![feature(async_await)] from examples --- examples/hello_world.rs | 2 -- examples/message_log.rs | 2 -- 2 files changed, 4 deletions(-) diff --git a/examples/hello_world.rs b/examples/hello_world.rs index 6ff462a0..9019c4c4 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -1,5 +1,3 @@ -#![feature(async_await)] - use std::{convert::TryFrom, env, process::exit}; use ruma_client::{ diff --git a/examples/message_log.rs b/examples/message_log.rs index ee1c2bd7..3a55cb53 100644 --- a/examples/message_log.rs +++ b/examples/message_log.rs @@ -1,5 +1,3 @@ -#![feature(async_await)] - use std::{env, process::exit}; use futures::stream::{StreamExt as _, TryStreamExt as _}; From 682dda60fa15aa8d0fc6d845d9a597bffcfa76a3 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Wed, 30 Oct 2019 18:43:38 +0100 Subject: [PATCH 089/139] Update dependencies --- Cargo.toml | 18 +++++++++--------- examples/hello_world.rs | 3 +-- examples/message_log.rs | 7 ++++++- 3 files changed, 16 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6fd59e5d..1c5972c2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,22 +13,22 @@ repository = "https://github.com/ruma/ruma-client" version = "0.2.0" [dependencies] -futures-preview = "0.3.0-alpha.19" -http = "0.1.18" -hyper = { version = "0.13.0-alpha.4", features = ["unstable-stream"] } -hyper-tls = { version = "0.4.0-alpha.4", optional = true } -ruma-api = { git = "https://github.com/ruma/ruma-api", branch = "serverless" } -ruma-client-api = { git = "https://github.com/ruma/ruma-client-api", branch = "event-result" } -ruma-events = { git = "https://github.com/ruma/ruma-events", branch = "event-result-2" } +futures-preview = "=0.3.0-alpha.19" +http = "=0.1.18" +hyper = { version = "=0.13.0-alpha.4", features = ["unstable-stream"] } +hyper-tls = { version = "=0.4.0-alpha.4", optional = true } +ruma-api = "0.11.0" +ruma-client-api = "0.4.0" +ruma-events = "0.15.1" ruma-identifiers = "0.14.0" native-tls = { version = "0.2.3", optional = true } -serde = { version = "1.0.101", features = ["derive"] } +serde = { version = "1.0.102", features = ["derive"] } serde_json = "1.0.41" serde_urlencoded = "0.6.1" url = "2.1.0" [dev-dependencies] -tokio = "0.2.0-alpha.6" +tokio = "=0.2.0-alpha.6" [features] default = ["tls"] diff --git a/examples/hello_world.rs b/examples/hello_world.rs index 9019c4c4..6b7e8140 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -4,7 +4,7 @@ use ruma_client::{ self, api::r0, events::{ - room::message::{MessageEventContent, MessageType, TextMessageEventContent}, + room::message::{MessageEventContent, TextMessageEventContent}, EventType, }, identifiers::RoomAliasId, @@ -37,7 +37,6 @@ async fn hello_world(homeserver_url: Url, room: String) -> Result<(), ruma_clien event_type: EventType::RoomMessage, txn_id: "1".to_owned(), data: MessageEventContent::Text(TextMessageEventContent { - msgtype: MessageType::Text, body: "Hello World!".to_owned(), format: None, formatted_body: None, diff --git a/examples/message_log.rs b/examples/message_log.rs index 3a55cb53..9b70ef07 100644 --- a/examples/message_log.rs +++ b/examples/message_log.rs @@ -26,7 +26,12 @@ async fn log_messages( while let Some(res) = sync_stream.try_next().await? { // Only look at rooms the user hasn't left yet for (room_id, room) in res.rooms.join { - for event in room.timeline.events { + for event in room + .timeline + .events + .into_iter() + .flat_map(|r| r.into_result()) + { // Filter out the text messages if let RoomEvent::RoomMessage(MessageEvent { content: From 6e13de95631eca7e29cf568d96cbeb1f96901580 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Wed, 30 Oct 2019 18:44:20 +0100 Subject: [PATCH 090/139] Bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 1c5972c2..450b3ed8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ license = "MIT" name = "ruma-client" readme = "README.md" repository = "https://github.com/ruma/ruma-client" -version = "0.2.0" +version = "0.3.0-beta.1" [dependencies] futures-preview = "=0.3.0-alpha.19" From ba332af83ec4737a97f791fa5a67e19a74430b65 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Wed, 30 Oct 2019 18:48:06 +0100 Subject: [PATCH 091/139] Update http dependency was accidentally changed to exact version in previous dependency update --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 450b3ed8..aaa4596c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,7 +14,7 @@ version = "0.3.0-beta.1" [dependencies] futures-preview = "=0.3.0-alpha.19" -http = "=0.1.18" +http = "0.1.19" hyper = { version = "=0.13.0-alpha.4", features = ["unstable-stream"] } hyper-tls = { version = "=0.4.0-alpha.4", optional = true } ruma-api = "0.11.0" From 8d734d88fce3c11c100cecaf04b32c73f85a2056 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 31 Oct 2019 22:35:45 +0100 Subject: [PATCH 092/139] Update travis configuration --- .travis.yml | 40 +++++++++++++++++++++++++++++++--------- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/.travis.yml b/.travis.yml index 8a42cce0..e8386efc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,16 +1,38 @@ language: "rust" cache: "cargo" +rust: + - 1.34.2 + - stable + - beta + - nightly +jobs: + allow_failures: + - rust: nightly + fast_finish: true + before_script: - - "rustup component add rustfmt" - - "rustup component add clippy" - - "cargo install --force cargo-audit" - - "cargo generate-lockfile" + - rustup component add rustfmt + - | + if [ "$TRAVIS_RUST_VERSION" != "1.34.2" ]; then + rustup component add clippy + fi + - | + if [ "$TRAVIS_RUST_VERSION" == "stable" ]; then + cargo install --force cargo-audit + fi + - cargo generate-lockfile script: - - "cargo audit" - - "cargo fmt --all -- --check" - - "cargo clippy --all-targets --all-features -- -D warnings" - - "cargo build --verbose" - - "cargo test --verbose" + - | + if [ "$TRAVIS_RUST_VERSION" == "stable" ]; then + cargo audit + fi + - cargo fmt -- --check + - | + if [ "$TRAVIS_RUST_VERSION" != "1.34.2" ]; then + cargo clippy --all-targets --all-features -- -D warnings + fi + - cargo build --verbose + - cargo test --verbose if: "type != push OR (tag IS blank AND branch = master)" notifications: email: false From b8f5194bd314b75f5e27bfd5effef46162d03681 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 31 Oct 2019 22:36:41 +0100 Subject: [PATCH 093/139] =?UTF-8?q?Remove=20#![deny(warnings)],=20#![warn(?= =?UTF-8?q?clippy::=E2=80=A6)]?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/lib.rs | 21 +-------------------- 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e27317fe..67128969 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -86,26 +86,7 @@ #![deny( missing_copy_implementations, missing_debug_implementations, - missing_docs, - //warnings -)] -#![warn( - clippy::empty_line_after_outer_attr, - clippy::expl_impl_clone_on_copy, - clippy::if_not_else, - clippy::items_after_statements, - clippy::match_same_arms, - clippy::mem_forget, - clippy::missing_docs_in_private_items, - clippy::mut_mut, - clippy::needless_borrow, - clippy::needless_continue, - clippy::single_match_else, - clippy::unicode_not_nfc, - clippy::use_self, - clippy::used_underscore_binding, - clippy::wrong_pub_self_convention, - clippy::wrong_self_convention + missing_docs )] use std::{ From ca3d77e620fb9d6ebc60a2740b79dc97ec4f106e Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 31 Oct 2019 22:37:27 +0100 Subject: [PATCH 094/139] Fix warnings --- examples/hello_world.rs | 2 +- src/lib.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/hello_world.rs b/examples/hello_world.rs index 6b7e8140..e3ca809f 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -33,7 +33,7 @@ async fn hello_world(homeserver_url: Url, room: String) -> Result<(), ruma_clien client .request(r0::send::send_message_event::Request { - room_id: room_id, + room_id, event_type: EventType::RoomMessage, txn_id: "1".to_owned(), data: MessageEventContent::Text(TextMessageEventContent { diff --git a/src/lib.rs b/src/lib.rs index 67128969..e8de521b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -352,7 +352,7 @@ where filter, since, full_state: None, - set_presence: set_presence.clone(), + set_presence, timeout: None, }) .await; @@ -362,7 +362,7 @@ where let next_batch_clone = response.next_batch.clone(); Some((Ok(response), State::Since(next_batch_clone))) } - Err(e) => Some((Err(e.into()), State::Errored)), + Err(e) => Some((Err(e), State::Errored)), } } }) From a43ba86836c6dccf8c90c12adfb8d5931fca206e Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sat, 2 Nov 2019 14:31:12 +0100 Subject: [PATCH 095/139] Add some backticks in doc comments --- src/lib.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e8de521b..fbbc0eac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -205,7 +205,7 @@ where /// Log in with a username and password. /// - /// In contrast to api::r0::session::login::call(), this method stores the + /// 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 async fn log_in( @@ -237,7 +237,7 @@ where Ok(session) } - /// Register as a guest. In contrast to api::r0::account::register::call(), + /// 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 async fn register_guest(&self) -> Result { @@ -267,7 +267,7 @@ where /// Register as a new user on this server. /// - /// In contrast to api::r0::account::register::call(), this method stores + /// 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. /// From 3cbc3f04bdae5d4b3c5783e00c1155940eb8e9cb Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 7 Nov 2019 19:01:28 +0100 Subject: [PATCH 096/139] Remove #![feature(async_await)] from doc tests --- src/lib.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index fbbc0eac..63951705 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -7,7 +7,6 @@ //! //! ```no_run //! # #![feature(impl_trait_in_bindings)] -//! #![feature(async_await)] //! use ruma_client::Client; //! //! let work = async { @@ -35,7 +34,6 @@ //! events), use the `Client::sync`: //! //! ```no_run -//! # #![feature(async_await)] //! # use futures::stream::{StreamExt as _, TryStreamExt as _}; //! # use ruma_client::Client; //! # let homeserver_url = "https://example.com".parse().unwrap(); @@ -61,7 +59,6 @@ //! For example: //! //! ```no_run -//! # #![feature(async_await)] //! # use ruma_client::Client; //! # let homeserver_url = "https://example.com".parse().unwrap(); //! # let client = Client::https(homeserver_url, None).unwrap(); From d1b1e3729bc1e18bea9abc63fc34ecb46254fe1b Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 7 Nov 2019 19:15:42 +0100 Subject: [PATCH 097/139] Remove 1.34.2 from CI, update README.md --- .travis.yml | 1 - README.md | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index e8386efc..51855555 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: "rust" cache: "cargo" rust: - - 1.34.2 - stable - beta - nightly diff --git a/README.md b/README.md index 19dc41f9..6bc9d236 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ and discussion related to any of the crates in this project. ## Minimum Rust version -ruma-client requires Rust 1.34 or later. +ruma-client requires Rust 1.39.0 or later. ## License From 82f652abb43c2795b9b2f735af83ee2241e58b34 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 7 Nov 2019 19:31:40 +0100 Subject: [PATCH 098/139] Remove #![feature(impl_trait_in_bindings)] from doc test --- src/lib.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 63951705..415be2ea 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,7 +6,6 @@ //! secure connections, and then logging in: //! //! ```no_run -//! # #![feature(impl_trait_in_bindings)] //! use ruma_client::Client; //! //! let work = async { @@ -19,12 +18,8 @@ //! //! // You're now logged in! Write the session to a file if you want to restore it later. //! // Then start using the API! -//! # Ok(()) +//! # Result::<(), ruma_client::Error>::Ok(()) //! }; -//! -//! // Start `work` on a futures runtime... -//! # let work_typehint: impl futures::future::TryFuture -//! # = work; //! ``` //! //! You can also pass an existing session to the `Client` constructor to restore a previous session From c9579984554a59ed11f99e11e8064333172fefb2 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Tue, 12 Nov 2019 01:20:20 +0100 Subject: [PATCH 099/139] Add #![warn(rust_2018_idioms)], fix warning --- src/error.rs | 2 +- src/lib.rs | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/error.rs b/src/error.rs index b3da1b84..289cbef2 100644 --- a/src/error.rs +++ b/src/error.rs @@ -14,7 +14,7 @@ use serde_urlencoded::ser::Error as SerdeUrlEncodedSerializeError; pub struct Error(pub(crate) InnerError); impl Display for Error { - fn fmt(&self, f: &mut Formatter) -> FmtResult { + fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { let message = match self.0 { InnerError::AuthenticationRequired => "The queried endpoint requires authentication but was called with an anonymous client.", InnerError::Hyper(_) => "An HTTP error occurred.", diff --git a/src/lib.rs b/src/lib.rs index 415be2ea..5275c05e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -75,6 +75,7 @@ //! # ; //! ``` +#![warn(rust_2018_idioms)] #![deny( missing_copy_implementations, missing_debug_implementations, From 9e097539e44293c8070e1b8a5d7a03119d7b67b1 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Tue, 3 Dec 2019 20:47:24 +0100 Subject: [PATCH 100/139] Remove outdated conditionals from .travis.yml --- .travis.yml | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 51855555..26e87600 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,10 +11,7 @@ jobs: before_script: - rustup component add rustfmt - - | - if [ "$TRAVIS_RUST_VERSION" != "1.34.2" ]; then - rustup component add clippy - fi + - rustup component add clippy - | if [ "$TRAVIS_RUST_VERSION" == "stable" ]; then cargo install --force cargo-audit @@ -26,10 +23,7 @@ script: cargo audit fi - cargo fmt -- --check - - | - if [ "$TRAVIS_RUST_VERSION" != "1.34.2" ]; then - cargo clippy --all-targets --all-features -- -D warnings - fi + - cargo clippy --all-targets --all-features -- -D warnings - cargo build --verbose - cargo test --verbose if: "type != push OR (tag IS blank AND branch = master)" From fcd1b204eb43972a87135d0975d406d23ffd066c Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 29 Nov 2019 18:31:21 +0100 Subject: [PATCH 101/139] Update dependencies --- Cargo.toml | 10 +++++----- src/lib.rs | 19 ++++++++++++++----- 2 files changed, 19 insertions(+), 10 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index aaa4596c..1c5bd53c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,16 +14,16 @@ version = "0.3.0-beta.1" [dependencies] futures-preview = "=0.3.0-alpha.19" -http = "0.1.19" +http = "0.1.20" hyper = { version = "=0.13.0-alpha.4", features = ["unstable-stream"] } hyper-tls = { version = "=0.4.0-alpha.4", optional = true } -ruma-api = "0.11.0" -ruma-client-api = "0.4.0" +ruma-api = "0.12.0-alpha.1" +ruma-client-api = "0.5.0-alpha.1" ruma-events = "0.15.1" ruma-identifiers = "0.14.0" native-tls = { version = "0.2.3", optional = true } -serde = { version = "1.0.102", features = ["derive"] } -serde_json = "1.0.41" +serde = { version = "1.0.103", features = ["derive"] } +serde_json = "1.0.42" serde_urlencoded = "0.6.1" url = "2.1.0" diff --git a/src/lib.rs b/src/lib.rs index 5275c05e..a76132e1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -101,7 +101,7 @@ use hyper::{ use hyper_tls::HttpsConnector; #[cfg(feature = "hyper-tls")] use native_tls::Error as NativeTlsError; -use ruma_api::Endpoint; +use ruma_api::{Endpoint, Outgoing}; use url::Url; use crate::error::InnerError; @@ -305,8 +305,8 @@ where filter: Option, since: Option, set_presence: bool, - ) -> impl Stream> - + TryStream { + ) -> impl Stream> + + TryStream { use api::r0::sync::sync_events; // TODO: Is this really the way TryStreams are supposed to work? @@ -365,7 +365,14 @@ where pub fn request( &self, request: Request, - ) -> impl Future> { + ) -> impl Future::Incoming, Error>> + // We need to duplicate Endpoint's where clauses because the compiler is not smart enough yet. + // See https://github.com/rust-lang/rust/issues/54149 + where + Request::Incoming: TryFrom>, Error = ruma_api::Error>, + ::Incoming: + TryFrom>, Error = ruma_api::Error>, + { let client = self.0.clone(); async move { @@ -396,7 +403,9 @@ where let full_response = HttpResponse::from_parts(head, body.try_concat().await?.as_ref().to_owned()); - Ok(Request::Response::try_from(full_response)?) + Ok(::Incoming::try_from( + full_response, + )?) } } } From 7208e66dff601fc379b5c1cac1a44a7a7c277273 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 12 Dec 2019 21:18:40 +0100 Subject: [PATCH 102/139] Update dependencies, release 0.3.0-beta.2 --- Cargo.toml | 20 +++++++++++--------- examples/message_log.rs | 2 +- src/lib.rs | 37 +++++++++++++++++++++---------------- 3 files changed, 33 insertions(+), 26 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1c5bd53c..c87d7664 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,25 +10,27 @@ license = "MIT" name = "ruma-client" readme = "README.md" repository = "https://github.com/ruma/ruma-client" -version = "0.3.0-beta.1" +version = "0.3.0-beta.2" [dependencies] -futures-preview = "=0.3.0-alpha.19" -http = "0.1.20" -hyper = { version = "=0.13.0-alpha.4", features = ["unstable-stream"] } -hyper-tls = { version = "=0.4.0-alpha.4", optional = true } -ruma-api = "0.12.0-alpha.1" -ruma-client-api = "0.5.0-alpha.1" +futures-core = "0.3.1" +futures-util = "0.3.1" +http = "0.2.0" +hyper = "0.13.0" +hyper-tls = { version = "0.4.0", optional = true } +ruma-api = "0.12.0" +ruma-client-api = "0.5.0" ruma-events = "0.15.1" ruma-identifiers = "0.14.0" native-tls = { version = "0.2.3", optional = true } serde = { version = "1.0.103", features = ["derive"] } -serde_json = "1.0.42" +serde_json = "1.0.44" serde_urlencoded = "0.6.1" +tokio = "0.2.4" url = "2.1.0" [dev-dependencies] -tokio = "=0.2.0-alpha.6" +tokio = { version = "0.2.4", features = ["macros"] } [features] default = ["tls"] diff --git a/examples/message_log.rs b/examples/message_log.rs index 9b70ef07..4be27514 100644 --- a/examples/message_log.rs +++ b/examples/message_log.rs @@ -1,6 +1,6 @@ use std::{env, process::exit}; -use futures::stream::{StreamExt as _, TryStreamExt as _}; +use futures_util::stream::{StreamExt as _, TryStreamExt as _}; use ruma_client::{ self, events::{ diff --git a/src/lib.rs b/src/lib.rs index a76132e1..8b4622ac 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -88,20 +88,22 @@ use std::{ sync::{Arc, Mutex}, }; -use futures::{ +use futures_core::{ future::Future, - stream::{self, Stream, TryStream, TryStreamExt as _}, + stream::{Stream, TryStream}, }; +use futures_util::stream; use http::Response as HttpResponse; use hyper::{ - client::{connect::Connect, HttpConnector}, - Client as HyperClient, Uri, + client::connect::Connection, client::HttpConnector, service::Service, Client as HyperClient, + Uri, }; #[cfg(feature = "hyper-tls")] use hyper_tls::HttpsConnector; #[cfg(feature = "hyper-tls")] use native_tls::Error as NativeTlsError; use ruma_api::{Endpoint, Outgoing}; +use tokio::io::{AsyncRead, AsyncWrite}; use url::Url; use crate::error::InnerError; @@ -118,14 +120,11 @@ mod session; /// A client for the Matrix client-server API. #[derive(Debug)] -pub struct Client(Arc>); +pub struct Client(Arc>); /// Data contained in Client's Rc #[derive(Debug)] -struct ClientData -where - C: Connect, -{ +struct ClientData { /// The URL of the homeserver to connect to. homeserver_url: Url, /// The underlying HTTP client. @@ -167,7 +166,7 @@ pub type HttpsClient = Client>; impl HttpsClient { /// Creates a new client for making HTTPS requests to the given homeserver. pub fn https(homeserver_url: Url, session: Option) -> Result { - let connector = HttpsConnector::new()?; + let connector = HttpsConnector::new(); Ok(Self(Arc::new(ClientData { homeserver_url, @@ -179,7 +178,10 @@ impl HttpsClient { impl Client where - C: Connect + 'static, + C: Service + Clone + Send + Sync + 'static, + C::Response: Connection + AsyncRead + AsyncWrite + Send + Unpin + 'static, + C::Future: Send + Unpin + 'static, + C::Error: Into>, { /// Creates a new client using the given `hyper::Client`. /// @@ -375,9 +377,9 @@ where { let client = self.0.clone(); - async move { - let mut url = client.homeserver_url.clone(); + let mut url = client.homeserver_url.clone(); + async move { let mut hyper_request = request.try_into()?.map(hyper::Body::from); { @@ -400,8 +402,11 @@ where let hyper_response = client.hyper.request(hyper_request).await?; let (head, body) = hyper_response.into_parts(); - let full_response = - HttpResponse::from_parts(head, body.try_concat().await?.as_ref().to_owned()); + + // FIXME: We read the reponse into a contiguous buffer here (not actually required for + // deserialization) and then copy the whole thing to convert from Bytes to Vec. + let full_body = hyper::body::to_bytes(body).await?; + let full_response = HttpResponse::from_parts(head, full_body.as_ref().to_owned()); Ok(::Incoming::try_from( full_response, @@ -410,7 +415,7 @@ where } } -impl Clone for Client { +impl Clone for Client { fn clone(&self) -> Self { Self(self.0.clone()) } From 5e2f9650585c60a231bebfc096658dedc07c7be8 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Thu, 12 Dec 2019 23:59:48 +0100 Subject: [PATCH 103/139] Fix doctests --- src/lib.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 8b4622ac..816fb4c4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,7 @@ //! //! let work = async { //! let homeserver_url = "https://example.com".parse().unwrap(); -//! let client = Client::https(homeserver_url, None).unwrap(); +//! let client = Client::https(homeserver_url, None); //! //! let session = client //! .log_in("@alice:example.com".to_string(), "secret".to_string(), None) @@ -29,10 +29,10 @@ //! events), use the `Client::sync`: //! //! ```no_run -//! # use futures::stream::{StreamExt as _, TryStreamExt as _}; +//! # use futures_util::stream::{StreamExt as _, TryStreamExt as _}; //! # use ruma_client::Client; //! # let homeserver_url = "https://example.com".parse().unwrap(); -//! # let client = Client::https(homeserver_url, None).unwrap(); +//! # let client = Client::https(homeserver_url, None); //! # async { //! let mut sync_stream = Box::pin(client.sync(None, None, true)); //! while let Some(response) = sync_stream.try_next().await? { @@ -56,7 +56,7 @@ //! ```no_run //! # use ruma_client::Client; //! # let homeserver_url = "https://example.com".parse().unwrap(); -//! # let client = Client::https(homeserver_url, None).unwrap(); +//! # let client = Client::https(homeserver_url, None); //! use std::convert::TryFrom; //! //! use ruma_client::api::r0::alias::get_alias; From c0390aba0d1bab3ab1d3bbb5a3d90c2f6445c506 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 13 Dec 2019 00:00:09 +0100 Subject: [PATCH 104/139] Remove useless Result, native_tls dependency --- Cargo.toml | 3 +-- src/lib.rs | 8 +++----- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c87d7664..e05ee56e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,6 @@ ruma-api = "0.12.0" ruma-client-api = "0.5.0" ruma-events = "0.15.1" ruma-identifiers = "0.14.0" -native-tls = { version = "0.2.3", optional = true } serde = { version = "1.0.103", features = ["derive"] } serde_json = "1.0.44" serde_urlencoded = "0.6.1" @@ -34,4 +33,4 @@ tokio = { version = "0.2.4", features = ["macros"] } [features] default = ["tls"] -tls = ["hyper-tls", "native-tls"] +tls = ["hyper-tls"] diff --git a/src/lib.rs b/src/lib.rs index 816fb4c4..7e7d3fe2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -100,8 +100,6 @@ use hyper::{ }; #[cfg(feature = "hyper-tls")] use hyper_tls::HttpsConnector; -#[cfg(feature = "hyper-tls")] -use native_tls::Error as NativeTlsError; use ruma_api::{Endpoint, Outgoing}; use tokio::io::{AsyncRead, AsyncWrite}; use url::Url; @@ -165,14 +163,14 @@ pub type HttpsClient = Client>; #[cfg(feature = "tls")] impl HttpsClient { /// Creates a new client for making HTTPS requests to the given homeserver. - pub fn https(homeserver_url: Url, session: Option) -> Result { + pub fn https(homeserver_url: Url, session: Option) -> Self { let connector = HttpsConnector::new(); - Ok(Self(Arc::new(ClientData { + Self(Arc::new(ClientData { homeserver_url, hyper: HyperClient::builder().keep_alive(true).build(connector), session: Mutex::new(session), - }))) + })) } } From 4a221a3bfb748b91d2d88273dae68dcce04ebfad Mon Sep 17 00:00:00 2001 From: Dimitris Apostolou Date: Sun, 15 Dec 2019 22:41:42 +0200 Subject: [PATCH 105/139] Fix typos --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7e7d3fe2..125d41fa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -298,7 +298,7 @@ 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 + /// be deserialized, because it contains all events that have occurred in the whole lifetime of /// the logged-in users account and are visible to them. pub fn sync( &self, @@ -401,7 +401,7 @@ where let hyper_response = client.hyper.request(hyper_request).await?; let (head, body) = hyper_response.into_parts(); - // FIXME: We read the reponse into a contiguous buffer here (not actually required for + // FIXME: We read the response into a contiguous buffer here (not actually required for // deserialization) and then copy the whole thing to convert from Bytes to Vec. let full_body = hyper::body::to_bytes(body).await?; let full_response = HttpResponse::from_parts(head, full_body.as_ref().to_owned()); From 19219dea6b7d6d91356e346c5125a756730a5064 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Mon, 16 Dec 2019 21:11:31 +0100 Subject: [PATCH 106/139] Update dependencies --- Cargo.toml | 5 ++--- src/lib.rs | 11 ++--------- 2 files changed, 4 insertions(+), 12 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index e05ee56e..1e30b4b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,16 +16,15 @@ version = "0.3.0-beta.2" futures-core = "0.3.1" futures-util = "0.3.1" http = "0.2.0" -hyper = "0.13.0" +hyper = "0.13.1" hyper-tls = { version = "0.4.0", optional = true } ruma-api = "0.12.0" ruma-client-api = "0.5.0" ruma-events = "0.15.1" -ruma-identifiers = "0.14.0" +ruma-identifiers = "0.14.1" serde = { version = "1.0.103", features = ["derive"] } serde_json = "1.0.44" serde_urlencoded = "0.6.1" -tokio = "0.2.4" url = "2.1.0" [dev-dependencies] diff --git a/src/lib.rs b/src/lib.rs index 125d41fa..84a95dd0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -94,14 +94,10 @@ use futures_core::{ }; use futures_util::stream; use http::Response as HttpResponse; -use hyper::{ - client::connect::Connection, client::HttpConnector, service::Service, Client as HyperClient, - Uri, -}; +use hyper::{client::HttpConnector, Client as HyperClient, Uri}; #[cfg(feature = "hyper-tls")] use hyper_tls::HttpsConnector; use ruma_api::{Endpoint, Outgoing}; -use tokio::io::{AsyncRead, AsyncWrite}; use url::Url; use crate::error::InnerError; @@ -176,10 +172,7 @@ impl HttpsClient { impl Client where - C: Service + Clone + Send + Sync + 'static, - C::Response: Connection + AsyncRead + AsyncWrite + Send + Unpin + 'static, - C::Future: Send + Unpin + 'static, - C::Error: Into>, + C: hyper::client::connect::Connect, { /// Creates a new client using the given `hyper::Client`. /// From 8dfe42e846ac18eef21928f69071e03f8b7e42c8 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Mon, 16 Dec 2019 21:56:05 +0100 Subject: [PATCH 107/139] Fix client impl bounds --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 84a95dd0..d550bca0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -172,7 +172,7 @@ impl HttpsClient { impl Client where - C: hyper::client::connect::Connect, + C: hyper::client::connect::Connect + Clone + Send + Sync + 'static, { /// Creates a new client using the given `hyper::Client`. /// From 413d25ab339239fe7178f39c420bc022dd263b7c Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Tue, 4 Feb 2020 11:28:55 +0100 Subject: [PATCH 108/139] Upgrade dependencies --- Cargo.toml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1e30b4b7..cb613d44 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,22 +13,22 @@ repository = "https://github.com/ruma/ruma-client" version = "0.3.0-beta.2" [dependencies] -futures-core = "0.3.1" -futures-util = "0.3.1" +futures-core = "0.3.2" +futures-util = "0.3.2" http = "0.2.0" -hyper = "0.13.1" -hyper-tls = { version = "0.4.0", optional = true } -ruma-api = "0.12.0" +hyper = "0.13.2" +hyper-tls = { version = "0.4.1", optional = true } +ruma-api = "0.12.1" ruma-client-api = "0.5.0" ruma-events = "0.15.1" ruma-identifiers = "0.14.1" -serde = { version = "1.0.103", features = ["derive"] } -serde_json = "1.0.44" +serde = { version = "1.0.104", features = ["derive"] } +serde_json = "1.0.46" serde_urlencoded = "0.6.1" -url = "2.1.0" +url = "2.1.1" [dev-dependencies] -tokio = { version = "0.2.4", features = ["macros"] } +tokio = { version = "0.2.11", features = ["macros"] } [features] default = ["tls"] From ab68029b80fca1cea013918395b7f87d6eb61fd5 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Tue, 4 Feb 2020 11:31:39 +0100 Subject: [PATCH 109/139] Add myself to the authors array in Cargo.toml --- Cargo.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index cb613d44..dae2f42c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,8 @@ [package] -authors = ["Jimmy Cuadra "] +authors = [ + "Jimmy Cuadra ", + "Jonas Platte ", +] categories = ["api-bindings", "web-programming"] description = "A Matrix client library." documentation = "https://docs.rs/ruma-client" From e4cf0fbf1ef75ecc7c03e4bd0369adc95cd42ee1 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Tue, 4 Feb 2020 11:38:07 +0100 Subject: [PATCH 110/139] Clean up lib.rs --- src/lib.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index d550bca0..bb9c5d1e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -102,16 +102,15 @@ use url::Url; use crate::error::InnerError; -pub use crate::{error::Error, session::Session}; pub use ruma_client_api as api; pub use ruma_events as events; pub use ruma_identifiers as identifiers; -/// Matrix client-server API endpoints. -//pub mod api; mod error; mod session; +pub use self::{error::Error, session::Session}; + /// A client for the Matrix client-server API. #[derive(Debug)] pub struct Client(Arc>); From aee5693fd8eb1fcb34627fa51dcde106bc77e471 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Tue, 4 Feb 2020 19:20:43 +0100 Subject: [PATCH 111/139] Use stream::try_unfold from futures 0.3.2 --- src/lib.rs | 34 +++++----------------------------- 1 file changed, 5 insertions(+), 29 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index bb9c5d1e..bcae4278 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -301,14 +301,6 @@ where + TryStream { use api::r0::sync::sync_events; - // TODO: Is this really the way TryStreams are supposed to work? - #[derive(Debug, PartialEq, Eq)] - enum State { - InitialSync, - Since(String), - Errored, - } - let client = self.clone(); let set_presence = if set_presence { None @@ -316,23 +308,12 @@ where Some(sync_events::SetPresence::Offline) }; - let initial_state = match since { - Some(s) => State::Since(s), - None => State::InitialSync, - }; - - stream::unfold(initial_state, move |state| { + stream::try_unfold(since, move |since| { let client = client.clone(); let filter = filter.clone(); async move { - let since = match state { - State::Errored => return None, - State::Since(s) => Some(s), - State::InitialSync => None, - }; - - let res = client + let response = client .request(sync_events::Request { filter, since, @@ -340,15 +321,10 @@ where set_presence, timeout: None, }) - .await; + .await?; - match res { - Ok(response) => { - let next_batch_clone = response.next_batch.clone(); - Some((Ok(response), State::Since(next_batch_clone))) - } - Err(e) => Some((Err(e), State::Errored)), - } + let next_batch_clone = response.next_batch.clone(); + Ok(Some((response, Some(next_batch_clone)))) } }) } From fde5338d506c5a056850d49d47078caa7622371d Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 7 Feb 2020 19:12:04 +0100 Subject: [PATCH 112/139] Move fn session from impl HttpClient to impl Client --- src/lib.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index bcae4278..90390721 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -138,17 +138,6 @@ impl HttpClient { session: Mutex::new(session), })) } - - /// Get a copy of the current `Session`, if any. - /// - /// Useful for serializing and persisting the session to be restored later. - pub fn session(&self) -> Option { - self.0 - .session - .lock() - .expect("session mutex was poisoned") - .clone() - } } /// Secured variant of the client (using HTTPS requests) @@ -188,6 +177,17 @@ where })) } + /// Get a copy of the current `Session`, if any. + /// + /// Useful for serializing and persisting the session to be restored later. + pub fn session(&self) -> Option { + self.0 + .session + .lock() + .expect("session mutex was poisoned") + .clone() + } + /// Log in with a username and password. /// /// In contrast to `api::r0::session::login::call()`, this method stores the From b412c584365d3e2a9b117b9ef9070c7becb067a8 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sun, 9 Feb 2020 21:48:11 +0100 Subject: [PATCH 113/139] Update dependencies, rewrite error module --- Cargo.toml | 10 ++-- examples/hello_world.rs | 2 +- examples/message_log.rs | 5 +- src/error.rs | 110 +++++++++++++++++++--------------------- src/lib.rs | 25 ++++----- 5 files changed, 74 insertions(+), 78 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index dae2f42c..066f0803 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,17 +16,17 @@ repository = "https://github.com/ruma/ruma-client" version = "0.3.0-beta.2" [dependencies] -futures-core = "0.3.2" -futures-util = "0.3.2" +futures-core = "0.3.4" +futures-util = "0.3.4" http = "0.2.0" hyper = "0.13.2" hyper-tls = { version = "0.4.1", optional = true } -ruma-api = "0.12.1" -ruma-client-api = "0.5.0" +ruma-api = "0.13.0" +ruma-client-api = "0.6.0" ruma-events = "0.15.1" ruma-identifiers = "0.14.1" serde = { version = "1.0.104", features = ["derive"] } -serde_json = "1.0.46" +serde_json = "1.0.47" serde_urlencoded = "0.6.1" url = "2.1.1" diff --git a/examples/hello_world.rs b/examples/hello_world.rs index e3ca809f..8ab65dc6 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -32,7 +32,7 @@ async fn hello_world(homeserver_url: Url, room: String) -> Result<(), ruma_clien .await?; client - .request(r0::send::send_message_event::Request { + .request(r0::message::create_message_event::Request { room_id, event_type: EventType::RoomMessage, txn_id: "1".to_owned(), diff --git a/examples/message_log.rs b/examples/message_log.rs index 4be27514..d010967c 100644 --- a/examples/message_log.rs +++ b/examples/message_log.rs @@ -18,7 +18,10 @@ async fn log_messages( ) -> Result<(), ruma_client::Error> { let client = HttpClient::new(homeserver_url, None); - client.log_in(username, password, None).await?; + client.log_in(username, password, None, None).await?; + + // TODO: This is a horrible way to obtain an initial next_batch token that generates way too + // much server load and network traffic. Fix this! // vvvvvvvv Skip initial sync reponse let mut sync_stream = Box::pin(client.sync(None, None, false).skip(1)); diff --git a/src/error.rs b/src/error.rs index 289cbef2..ba71344a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -3,76 +3,68 @@ use std::error::Error as StdError; use std::fmt::{Display, Formatter, Result as FmtResult}; -use http::uri::InvalidUri; -use hyper::error::Error as HyperError; -use ruma_api::Error as RumaApiError; -use serde_json::Error as SerdeJsonError; -use serde_urlencoded::ser::Error as SerdeUrlEncodedSerializeError; +use ruma_api::error::{FromHttpResponseError, IntoHttpError}; /// An error that can occur during client operations. #[derive(Debug)] -pub struct Error(pub(crate) InnerError); +#[non_exhaustive] +pub enum Error { + /// Queried endpoint requires authentication but was called on an anonymous client. + AuthenticationRequired, + /// Construction of the HTTP request failed (this should never happen). + IntoHttp(IntoHttpError), + /// The request's URL is invalid (this should never happen). + Url(UrlError), + /// Couldn't obtain an HTTP response (e.g. due to network or DNS issues). + Response(ResponseError), + /// Converting the HTTP response to one of ruma's types failed. + FromHttpResponse(FromHttpResponseError), +} impl Display for Error { fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { - let message = match self.0 { - InnerError::AuthenticationRequired => "The queried endpoint requires authentication but was called with an anonymous client.", - InnerError::Hyper(_) => "An HTTP error occurred.", - InnerError::Uri(_) => "Provided string could not be converted into a URI.", - InnerError::RumaApi(_) => "An error occurred converting between ruma_client_api and hyper types.", - InnerError::SerdeJson(_) => "A serialization error occurred.", - InnerError::SerdeUrlEncodedSerialize(_) => "An error occurred serializing data to a query string.", - }; + match self { + Self::AuthenticationRequired => { + write!(f, "The queried endpoint requires authentication but was called with an anonymous client.") + } + Self::IntoHttp(err) => write!(f, "HTTP request construction failed: {}", err), + Self::Url(UrlError(err)) => write!(f, "Invalid URL: {}", err), + Self::Response(ResponseError(err)) => write!(f, "Couldn't obtain a response: {}", err), + Self::FromHttpResponse(err) => write!(f, "HTTP response conversion failed: {}", err), + } + } +} - write!(f, "{}", message) +impl From for Error { + fn from(err: IntoHttpError) -> Self { + Error::IntoHttp(err) + } +} + +#[doc(hidden)] +impl From for Error { + fn from(err: http::uri::InvalidUri) -> Self { + Error::Url(UrlError(err)) + } +} + +#[doc(hidden)] +impl From for Error { + fn from(err: hyper::Error) -> Self { + Error::Response(ResponseError(err)) + } +} + +impl From for Error { + fn from(err: FromHttpResponseError) -> Self { + Error::FromHttpResponse(err) } } impl StdError for Error {} -/// Internal representation of errors. #[derive(Debug)] -pub(crate) enum InnerError { - /// Queried endpoint requires authentication but was called on an anonymous client. - AuthenticationRequired, - /// An error at the HTTP layer. - Hyper(HyperError), - /// An error when parsing a string as a URI. - Uri(InvalidUri), - /// An error converting between ruma_client_api types and Hyper types. - RumaApi(RumaApiError), - /// An error when serializing or deserializing a JSON value. - SerdeJson(SerdeJsonError), - /// An error when serializing a query string value. - SerdeUrlEncodedSerialize(SerdeUrlEncodedSerializeError), -} +pub struct UrlError(http::uri::InvalidUri); -impl From for Error { - fn from(error: HyperError) -> Self { - Self(InnerError::Hyper(error)) - } -} - -impl From for Error { - fn from(error: InvalidUri) -> Self { - Self(InnerError::Uri(error)) - } -} - -impl From for Error { - fn from(error: RumaApiError) -> Self { - Self(InnerError::RumaApi(error)) - } -} - -impl From for Error { - fn from(error: SerdeJsonError) -> Self { - Self(InnerError::SerdeJson(error)) - } -} - -impl From for Error { - fn from(error: SerdeUrlEncodedSerializeError) -> Self { - Self(InnerError::SerdeUrlEncodedSerialize(error)) - } -} +#[derive(Debug)] +pub struct ResponseError(hyper::Error); diff --git a/src/lib.rs b/src/lib.rs index 90390721..06a828bc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -97,11 +97,13 @@ use http::Response as HttpResponse; use hyper::{client::HttpConnector, Client as HyperClient, Uri}; #[cfg(feature = "hyper-tls")] use hyper_tls::HttpsConnector; -use ruma_api::{Endpoint, Outgoing}; +use ruma_api::{ + error::{FromHttpRequestError, FromHttpResponseError, IntoHttpError}, + Endpoint, Outgoing, +}; +use ruma_identifiers::DeviceId; use url::Url; -use crate::error::InnerError; - pub use ruma_client_api as api; pub use ruma_events as events; pub use ruma_identifiers as identifiers; @@ -197,18 +199,17 @@ where &self, user: String, password: String, - device_id: Option, + device_id: Option, + initial_device_display_name: Option, ) -> Result { use api::r0::session::login; let response = self .request(login::Request { - address: None, - login_type: login::LoginType::Password, - medium: None, + user: login::UserInfo::MatrixId(user), + login_info: login::LoginInfo::Password { password }, device_id, - password, - user, + initial_device_display_name, }) .await?; @@ -337,9 +338,9 @@ where // We need to duplicate Endpoint's where clauses because the compiler is not smart enough yet. // See https://github.com/rust-lang/rust/issues/54149 where - Request::Incoming: TryFrom>, Error = ruma_api::Error>, + Request::Incoming: TryFrom>, Error = FromHttpRequestError>, ::Incoming: - TryFrom>, Error = ruma_api::Error>, + TryFrom>, Error = FromHttpResponseError>, { let client = self.0.clone(); @@ -359,7 +360,7 @@ where url.query_pairs_mut() .append_pair("access_token", &session.access_token); } else { - return Err(Error(InnerError::AuthenticationRequired)); + return Err(Error::AuthenticationRequired); } } } From 4aef331886fa2105dc40bc8305ed9f46a4095e1d Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sun, 9 Feb 2020 22:03:57 +0100 Subject: [PATCH 114/139] Remove unused import --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 06a828bc..6c238c2e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -98,7 +98,7 @@ use hyper::{client::HttpConnector, Client as HyperClient, Uri}; #[cfg(feature = "hyper-tls")] use hyper_tls::HttpsConnector; use ruma_api::{ - error::{FromHttpRequestError, FromHttpResponseError, IntoHttpError}, + error::{FromHttpRequestError, FromHttpResponseError}, Endpoint, Outgoing, }; use ruma_identifiers::DeviceId; From 62afce2fd382e18813cea02bf404b0b3fcf19e38 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sun, 9 Feb 2020 22:10:03 +0100 Subject: [PATCH 115/139] Fix doctest --- src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index 6c238c2e..b7274620 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,7 +13,7 @@ //! let client = Client::https(homeserver_url, None); //! //! let session = client -//! .log_in("@alice:example.com".to_string(), "secret".to_string(), None) +//! .log_in("@alice:example.com".to_string(), "secret".to_string(), None, None) //! .await?; //! //! // You're now logged in! Write the session to a file if you want to restore it later. From db1c95015c0aa1996285aa18bf7035fef8361215 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sun, 9 Feb 2020 22:23:19 +0100 Subject: [PATCH 116/139] Bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 066f0803..2fea7843 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ license = "MIT" name = "ruma-client" readme = "README.md" repository = "https://github.com/ruma/ruma-client" -version = "0.3.0-beta.2" +version = "0.3.0" [dependencies] futures-core = "0.3.4" From 1d689b2d7f5e5206b63e0d1276fb5c68d2083baa Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Tue, 10 Mar 2020 12:04:39 +0100 Subject: [PATCH 117/139] Remove deprecated `keep_alive` call It doesn't need to be replaced, as the behavior we specified explititly is the default --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index b7274620..b71593e1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -136,7 +136,7 @@ impl HttpClient { pub fn new(homeserver_url: Url, session: Option) -> Self { Self(Arc::new(ClientData { homeserver_url, - hyper: HyperClient::builder().keep_alive(true).build_http(), + hyper: HyperClient::builder().build_http(), session: Mutex::new(session), })) } @@ -154,7 +154,7 @@ impl HttpsClient { Self(Arc::new(ClientData { homeserver_url, - hyper: HyperClient::builder().keep_alive(true).build(connector), + hyper: HyperClient::builder().build(connector), session: Mutex::new(session), })) } From 8522f8ada9b7b7efa49a2455540c1f3beb852840 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 3 Apr 2020 19:18:07 +0200 Subject: [PATCH 118/139] CI: Disable IRC notifications --- .travis.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 26e87600..e7f2baac 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,10 +27,3 @@ script: - cargo build --verbose - cargo test --verbose if: "type != push OR (tag IS blank AND branch = master)" -notifications: - email: false - irc: - channels: - - secure: "AJxKl4hMtg1g8+uUqgF4yeOZKCW5rqxilF/LFicRUGZFsqurO/pmvBrWIx2NeCpjUo7IPGR78NhbRPu7Qp93hHd4UQfnDE9Aw2iU7nMdJlnSMdztilObLPGtopJQGt1HXwJquxUvqd/J95Eb5ep+PbwJMj2qkEF1e5JlGhNKnpAQVL7RQYHhKGD6n6vkqpStQvvswtSHH0Uk6nrlZEVQxrvQy7w+iw5lEHqg64Y+w17ilR/+NJrLT83UlnOGKOADJ9bh8l8GrQvqmQhFwcJv1qj5tp6Tr30eN45FIv4P1hUkXW5lSm3mgX4b1QVDeCGH8ebo/WChrUB461uZhZnVk8JrWGtcrmLP08daliQxhm6Ybm4cW9kcZXMEs64wqz/xcYX0rJo4dwoY1ZyvM1G3b6HwYEEgiU5ypM3rXzT/7z007zOxD/EjCYQumBZKarqEkH76qSlPwjsYWQOWY9gwNeh93Gg+a+0wD2HitKzxPnTYaFt67QaZxxC/h2YNcvVAxPyiC0gdTUf+cPG0KidJKexfg4cSjHQj7EnPpNPzSfqdA5XvmkEeUV4Igi/sQHSiS4OFwtaq99bIqm4FZswFJq+T4IUyTC5jzvT3b2D6AZuwJnxtYXT70iO12+q+D7V01zLI8O0qGS31NkK5NYjTULQdWuOnSANnfeCnhdDleys=" - use_notice: true - From 201ff8c1851c10eea5dfd091d7db963917ddf601 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Mon, 6 Apr 2020 11:38:46 +0200 Subject: [PATCH 119/139] Update dependencies --- Cargo.toml | 16 ++++++++-------- examples/message_log.rs | 5 +++-- src/error.rs | 12 ++++++++---- src/lib.rs | 14 ++++---------- 4 files changed, 23 insertions(+), 24 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 2fea7843..bb2dd0b7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,20 +18,20 @@ version = "0.3.0" [dependencies] futures-core = "0.3.4" futures-util = "0.3.4" -http = "0.2.0" -hyper = "0.13.2" +http = "0.2.1" +hyper = "0.13.4" hyper-tls = { version = "0.4.1", optional = true } -ruma-api = "0.13.0" -ruma-client-api = "0.6.0" -ruma-events = "0.15.1" +ruma-api = "0.15.0" +ruma-client-api = "0.7.1" +ruma-events = "0.18.0" ruma-identifiers = "0.14.1" -serde = { version = "1.0.104", features = ["derive"] } -serde_json = "1.0.47" +serde = { version = "1.0.106", features = ["derive"] } +serde_json = "1.0.51" serde_urlencoded = "0.6.1" url = "2.1.1" [dev-dependencies] -tokio = { version = "0.2.11", features = ["macros"] } +tokio = { version = "0.2.16", features = ["macros"] } [features] default = ["tls"] diff --git a/examples/message_log.rs b/examples/message_log.rs index d010967c..44a63801 100644 --- a/examples/message_log.rs +++ b/examples/message_log.rs @@ -3,6 +3,7 @@ use std::{env, process::exit}; use futures_util::stream::{StreamExt as _, TryStreamExt as _}; use ruma_client::{ self, + api::r0::sync::sync_events::SetPresence, events::{ collections::all::RoomEvent, room::message::{MessageEvent, MessageEventContent, TextMessageEventContent}, @@ -23,8 +24,8 @@ async fn log_messages( // TODO: This is a horrible way to obtain an initial next_batch token that generates way too // much server load and network traffic. Fix this! - // vvvvvvvv Skip initial sync reponse - let mut sync_stream = Box::pin(client.sync(None, None, false).skip(1)); + // Skip initial sync reponse vvvvvvvv + let mut sync_stream = Box::pin(client.sync(None, None, SetPresence::Online).skip(1)); while let Some(res) = sync_stream.try_next().await? { // Only look at rooms the user hasn't left yet diff --git a/src/error.rs b/src/error.rs index ba71344a..6e96f486 100644 --- a/src/error.rs +++ b/src/error.rs @@ -5,6 +5,8 @@ use std::fmt::{Display, Formatter, Result as FmtResult}; use ruma_api::error::{FromHttpResponseError, IntoHttpError}; +use crate::api; + /// An error that can occur during client operations. #[derive(Debug)] #[non_exhaustive] @@ -18,7 +20,7 @@ pub enum Error { /// Couldn't obtain an HTTP response (e.g. due to network or DNS issues). Response(ResponseError), /// Converting the HTTP response to one of ruma's types failed. - FromHttpResponse(FromHttpResponseError), + FromHttpResponse(FromHttpResponseError), } impl Display for Error { @@ -30,7 +32,9 @@ impl Display for Error { Self::IntoHttp(err) => write!(f, "HTTP request construction failed: {}", err), Self::Url(UrlError(err)) => write!(f, "Invalid URL: {}", err), Self::Response(ResponseError(err)) => write!(f, "Couldn't obtain a response: {}", err), - Self::FromHttpResponse(err) => write!(f, "HTTP response conversion failed: {}", err), + // FIXME: ruma-client-api's Error type currently doesn't implement + // `Display`, update this when it does. + Self::FromHttpResponse(_) => write!(f, "HTTP response conversion failed"), } } } @@ -55,8 +59,8 @@ impl From for Error { } } -impl From for Error { - fn from(err: FromHttpResponseError) -> Self { +impl From> for Error { + fn from(err: FromHttpResponseError) -> Self { Error::FromHttpResponse(err) } } diff --git a/src/lib.rs b/src/lib.rs index b71593e1..a0f36f39 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -297,18 +297,12 @@ where &self, filter: Option, since: Option, - set_presence: bool, + set_presence: api::r0::sync::sync_events::SetPresence, ) -> impl Stream> + TryStream { use api::r0::sync::sync_events; let client = self.clone(); - let set_presence = if set_presence { - None - } else { - Some(sync_events::SetPresence::Offline) - }; - stream::try_unfold(since, move |since| { let client = client.clone(); let filter = filter.clone(); @@ -318,7 +312,7 @@ where .request(sync_events::Request { filter, since, - full_state: None, + full_state: false, set_presence, timeout: None, }) @@ -331,7 +325,7 @@ where } /// Makes a request to a Matrix API endpoint. - pub fn request( + pub fn request>( &self, request: Request, ) -> impl Future::Incoming, Error>> @@ -340,7 +334,7 @@ where where Request::Incoming: TryFrom>, Error = FromHttpRequestError>, ::Incoming: - TryFrom>, Error = FromHttpResponseError>, + TryFrom>, Error = FromHttpResponseError>, { let client = self.0.clone(); From b974182c7274477ef4cb1106f4bb549e6b3dbd6d Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Mon, 6 Apr 2020 19:48:26 +0200 Subject: [PATCH 120/139] Fix doctest --- src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index a0f36f39..a3948ef1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,11 +30,11 @@ //! //! ```no_run //! # use futures_util::stream::{StreamExt as _, TryStreamExt as _}; -//! # use ruma_client::Client; +//! # use ruma_client::{api::r0::sync::sync_events::SetPresence, Client}; //! # let homeserver_url = "https://example.com".parse().unwrap(); //! # let client = Client::https(homeserver_url, None); //! # async { -//! let mut sync_stream = Box::pin(client.sync(None, None, true)); +//! let mut sync_stream = Box::pin(client.sync(None, None, SetPresence::Online)); //! while let Some(response) = sync_stream.try_next().await? { //! // Do something with the data in the response... //! } From c253265fd6ad8ccab45c5e8a5bc9d14c27000c96 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 10 Apr 2020 13:51:34 +0200 Subject: [PATCH 121/139] Update README.md --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 6bc9d236..ee77efb5 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,10 @@ # ruma-client +[![crates.io page](https://img.shields.io/crates/v/ruma-client.svg)](https://crates.io/crates/ruma-client) +[![docs.rs page](https://docs.rs/ruma-client/badge.svg)](https://docs.rs/ruma-client/) +[![build status](https://travis-ci.org/ruma/ruma-client.svg?branch=master)](https://travis-ci.org/ruma/ruma-client) +![license: MIT](https://img.shields.io/crates/l/ruma-client.svg) + **ruma-client** is a [Matrix][] client library for [Rust][]. [Matrix]: https://matrix.org/ @@ -31,7 +36,3 @@ and discussion related to any of the crates in this project. ## Minimum Rust version ruma-client requires Rust 1.39.0 or later. - -## License - -[MIT](http://opensource.org/licenses/MIT) From a207807f59a5ed712e924fc08f84bbbea1c18838 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Tue, 14 Apr 2020 19:49:29 +0200 Subject: [PATCH 122/139] Add timeout parameter to sync, update doctest --- examples/message_log.rs | 19 +++++++++++++------ src/lib.rs | 14 ++++++++++++-- 2 files changed, 25 insertions(+), 8 deletions(-) diff --git a/examples/message_log.rs b/examples/message_log.rs index 44a63801..10895f33 100644 --- a/examples/message_log.rs +++ b/examples/message_log.rs @@ -1,4 +1,4 @@ -use std::{env, process::exit}; +use std::{env, process::exit, time::Duration}; use futures_util::stream::{StreamExt as _, TryStreamExt as _}; use ruma_client::{ @@ -21,11 +21,18 @@ async fn log_messages( client.log_in(username, password, None, None).await?; - // TODO: This is a horrible way to obtain an initial next_batch token that generates way too - // much server load and network traffic. Fix this! - - // Skip initial sync reponse vvvvvvvv - let mut sync_stream = Box::pin(client.sync(None, None, SetPresence::Online).skip(1)); + let mut sync_stream = Box::pin( + client + .sync( + None, + None, + SetPresence::Online, + Some(Duration::from_secs(30)), + ) + // TODO: This is a horrible way to obtain an initial next_batch token that generates way + // too much server load and network traffic. Fix this! + .skip(1), + ); while let Some(res) = sync_stream.try_next().await? { // Only look at rooms the user hasn't left yet diff --git a/src/lib.rs b/src/lib.rs index a3948ef1..ff1c39af 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,12 +29,20 @@ //! events), use the `Client::sync`: //! //! ```no_run +//! use std::time::Duration; +//! //! # use futures_util::stream::{StreamExt as _, TryStreamExt as _}; //! # use ruma_client::{api::r0::sync::sync_events::SetPresence, Client}; //! # let homeserver_url = "https://example.com".parse().unwrap(); //! # let client = Client::https(homeserver_url, None); +//! # let next_batch_token = String::new(); //! # async { -//! let mut sync_stream = Box::pin(client.sync(None, None, SetPresence::Online)); +//! let mut sync_stream = Box::pin(client.sync( +//! None, +//! Some(next_batch_token), +//! SetPresence::Online, +//! Some(Duration::from_secs(30)), +//! )); //! while let Some(response) = sync_stream.try_next().await? { //! // Do something with the data in the response... //! } @@ -86,6 +94,7 @@ use std::{ convert::TryFrom, str::FromStr, sync::{Arc, Mutex}, + time::Duration, }; use futures_core::{ @@ -298,6 +307,7 @@ where filter: Option, since: Option, set_presence: api::r0::sync::sync_events::SetPresence, + timeout: Option, ) -> impl Stream> + TryStream { use api::r0::sync::sync_events; @@ -314,7 +324,7 @@ where since, full_state: false, set_presence, - timeout: None, + timeout, }) .await?; From dc73e6d6c493ca2fc2c4224e0413ba7e7da891f5 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Tue, 14 Apr 2020 19:59:48 +0200 Subject: [PATCH 123/139] Bump dependencies, including our own (beta) --- Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bb2dd0b7..5cd84e43 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ license = "MIT" name = "ruma-client" readme = "README.md" repository = "https://github.com/ruma/ruma-client" -version = "0.3.0" +version = "0.4.0-beta.1" [dependencies] futures-core = "0.3.4" @@ -22,7 +22,7 @@ http = "0.2.1" hyper = "0.13.4" hyper-tls = { version = "0.4.1", optional = true } ruma-api = "0.15.0" -ruma-client-api = "0.7.1" +ruma-client-api = "0.7.2" ruma-events = "0.18.0" ruma-identifiers = "0.14.1" serde = { version = "1.0.106", features = ["derive"] } @@ -31,7 +31,7 @@ serde_urlencoded = "0.6.1" url = "2.1.1" [dev-dependencies] -tokio = { version = "0.2.16", features = ["macros"] } +tokio = { version = "0.2.18", features = ["macros"] } [features] default = ["tls"] From d0c777ff9a053782b3f94d40e4d64a2ed4f4a91b Mon Sep 17 00:00:00 2001 From: Andreas Studer Date: Sun, 19 Apr 2020 14:38:00 +0200 Subject: [PATCH 124/139] Add request_with_url_params method This method allows a client to add any URL parameters when doing an API call. This can be used by application services to add URL parameters like user_id. --- src/lib.rs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index ff1c39af..edeac004 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -111,6 +111,7 @@ use ruma_api::{ Endpoint, Outgoing, }; use ruma_identifiers::DeviceId; +use std::collections::BTreeMap; use url::Url; pub use ruma_client_api as api; @@ -341,6 +342,22 @@ where ) -> impl Future::Incoming, Error>> // We need to duplicate Endpoint's where clauses because the compiler is not smart enough yet. // See https://github.com/rust-lang/rust/issues/54149 + where + Request::Incoming: TryFrom>, Error = FromHttpRequestError>, + ::Incoming: + TryFrom>, Error = FromHttpResponseError>, + { + self.request_with_url_params(request, None) + } + + /// Makes a request to a Matrix API endpoint including additional URL parameters. + pub fn request_with_url_params>( + &self, + request: Request, + params: Option>, + ) -> impl Future::Incoming, Error>> + // We need to duplicate Endpoint's where clauses because the compiler is not smart enough yet. + // See https://github.com/rust-lang/rust/issues/54149 where Request::Incoming: TryFrom>, Error = FromHttpRequestError>, ::Incoming: @@ -359,6 +376,12 @@ where url.set_path(uri.path()); url.set_query(uri.query()); + if let Some(params) = params { + for (key, value) in params { + url.query_pairs_mut().append_pair(&key, &value); + } + } + if Request::METADATA.requires_authentication { if let Some(ref session) = *client.session.lock().unwrap() { url.query_pairs_mut() From 7bb0c8a8c536614bf0e7b45aea1367d92f196026 Mon Sep 17 00:00:00 2001 From: Andreas Studer Date: Sun, 19 Apr 2020 16:56:40 +0200 Subject: [PATCH 125/139] Move user_id and device_id into Identification Not all callers will need the identification information. --- src/lib.rs | 35 +++++++++++++++++++++++++++-------- src/session.rs | 25 +++++++++++++++++++------ 2 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index edeac004..fb563c6d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -23,7 +23,20 @@ //! ``` //! //! You can also pass an existing session to the `Client` constructor to restore a previous session -//! rather than calling `log_in`. +//! rather than calling `log_in`. This can also be used to create a session for an application service +//! that does not need to log in, but uses the access_token directly: +//! +//! ```no_run +//! use ruma_client::{Client, Session}; +//! +//! let work = async { +//! let homeserver_url = "https://example.com".parse().unwrap(); +//! let session = Session{access_token: "as_access_token".to_string(), identification: None}; +//! let client = Client::https(homeserver_url, Some(session)); +//! +//! // make calls to the API +//! }; +//! ``` //! //! For the standard use case of synchronizing with the homeserver (i.e. getting all the latest //! events), use the `Client::sync`: @@ -121,7 +134,7 @@ pub use ruma_identifiers as identifiers; mod error; mod session; -pub use self::{error::Error, session::Session}; +pub use self::{error::Error, session::Identification, session::Session}; /// A client for the Matrix client-server API. #[derive(Debug)] @@ -225,8 +238,10 @@ where let session = Session { access_token: response.access_token, - device_id: response.device_id, - user_id: response.user_id, + identification: Some(Identification { + device_id: response.device_id, + user_id: response.user_id, + }), }; *self.0.session.lock().unwrap() = Some(session.clone()); @@ -253,8 +268,10 @@ where let session = Session { access_token: response.access_token, - device_id: response.device_id, - user_id: response.user_id, + identification: Some(Identification { + device_id: response.device_id, + user_id: response.user_id, + }), }; *self.0.session.lock().unwrap() = Some(session.clone()); @@ -290,8 +307,10 @@ where let session = Session { access_token: response.access_token, - device_id: response.device_id, - user_id: response.user_id, + identification: Some(Identification { + device_id: response.device_id, + user_id: response.user_id, + }), }; *self.0.session.lock().unwrap() = Some(session.clone()); diff --git a/src/session.rs b/src/session.rs index 331baeb7..f66ee982 100644 --- a/src/session.rs +++ b/src/session.rs @@ -7,6 +7,14 @@ use ruma_identifiers::UserId; pub struct Session { /// The access token used for this session. pub access_token: String, + /// Identification information for a user + pub identification: Option, +} + +/// The identification information about the associated user account if the session is associated with +/// a single user account. +#[derive(Clone, Debug, serde::Deserialize, Eq, Hash, PartialEq, serde::Serialize)] +pub struct Identification { /// The user the access token was issued for. pub user_id: UserId, /// The ID of the client device @@ -19,8 +27,7 @@ impl Session { pub fn new(access_token: String, user_id: UserId, device_id: String) -> Self { Self { access_token, - user_id, - device_id, + identification: Some(Identification { user_id, device_id }), } } @@ -32,13 +39,19 @@ impl Session { /// Get the ID of the user the session belongs to. #[deprecated] - pub fn user_id(&self) -> &UserId { - &self.user_id + pub fn user_id(&self) -> Option<&UserId> { + if let Some(identification) = &self.identification { + return Some(&identification.user_id); + } + None } /// Get ID of the device the session belongs to. #[deprecated] - pub fn device_id(&self) -> &str { - &self.device_id + pub fn device_id(&self) -> Option<&str> { + if let Some(identification) = &self.identification { + return Some(&identification.device_id); + } + None } } From 1b1f8b63413680f51734c15a95280cfff6864f81 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Sun, 19 Apr 2020 20:19:38 +0200 Subject: [PATCH 126/139] Update dependencies --- Cargo.toml | 10 +++++----- src/lib.rs | 18 ++++++++++++------ 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5cd84e43..37b89038 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,12 +19,12 @@ version = "0.4.0-beta.1" futures-core = "0.3.4" futures-util = "0.3.4" http = "0.2.1" -hyper = "0.13.4" +hyper = "0.13.5" hyper-tls = { version = "0.4.1", optional = true } -ruma-api = "0.15.0" -ruma-client-api = "0.7.2" -ruma-events = "0.18.0" -ruma-identifiers = "0.14.1" +ruma-api = "0.16.0-rc.1" +ruma-client-api = "0.8.0-rc.1" +ruma-events = "0.19.0-rc.1" +ruma-identifiers = "0.15.1" serde = { version = "1.0.106", features = ["derive"] } serde_json = "1.0.51" serde_urlencoded = "0.6.1" diff --git a/src/lib.rs b/src/lib.rs index fb563c6d..dca34a4f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -257,8 +257,8 @@ where let response = self .request(register::Request { auth: None, - bind_email: None, device_id: None, + inhibit_login: false, initial_device_display_name: None, kind: Some(register::RegistrationKind::Guest), password: None, @@ -267,9 +267,12 @@ where .await?; let session = Session { - access_token: response.access_token, + // since we supply inhibit_login: false above, the access token needs to be there + // TODO: maybe unwrap is not the best solution though + access_token: response.access_token.unwrap(), identification: Some(Identification { - device_id: response.device_id, + // same as access_token + device_id: response.device_id.unwrap(), user_id: response.user_id, }), }; @@ -296,8 +299,8 @@ where let response = self .request(register::Request { auth: None, - bind_email: None, device_id: None, + inhibit_login: false, initial_device_display_name: None, kind: Some(register::RegistrationKind::User), password: Some(password), @@ -306,9 +309,12 @@ where .await?; let session = Session { - access_token: response.access_token, + // since we supply inhibit_login: false above, the access token needs to be there + // TODO: maybe unwrap is not the best solution though + access_token: response.access_token.unwrap(), identification: Some(Identification { - device_id: response.device_id, + // same as access_token + device_id: response.device_id.unwrap(), user_id: response.user_id, }), }; From e44087f8b820f7a98b5c34c778b8e1c287de6c89 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Mon, 20 Apr 2020 13:21:10 +0200 Subject: [PATCH 127/139] Support endpoints with s other than ruma_client_api::Error --- Cargo.toml | 1 + examples/hello_world.rs | 4 ++-- examples/message_log.rs | 4 ++-- src/error.rs | 25 +++++++++++-------------- src/lib.rs | 29 +++++++++++++++-------------- 5 files changed, 31 insertions(+), 32 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 37b89038..470c74d5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -31,6 +31,7 @@ serde_urlencoded = "0.6.1" url = "2.1.1" [dev-dependencies] +anyhow = "1.0.28" tokio = { version = "0.2.18", features = ["macros"] } [features] diff --git a/examples/hello_world.rs b/examples/hello_world.rs index 8ab65dc6..6667e8c4 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -12,7 +12,7 @@ use ruma_client::{ }; use url::Url; -async fn hello_world(homeserver_url: Url, room: String) -> Result<(), ruma_client::Error> { +async fn hello_world(homeserver_url: Url, room: String) -> anyhow::Result<()> { let client = Client::new(homeserver_url, None); client.register_guest().await?; @@ -49,7 +49,7 @@ async fn hello_world(homeserver_url: Url, room: String) -> Result<(), ruma_clien } #[tokio::main] -async fn main() -> Result<(), ruma_client::Error> { +async fn main() -> anyhow::Result<()> { let (homeserver_url, room) = match (env::args().nth(1), env::args().nth(2)) { (Some(a), Some(b)) => (a, b), _ => { diff --git a/examples/message_log.rs b/examples/message_log.rs index 10895f33..f8ef4c18 100644 --- a/examples/message_log.rs +++ b/examples/message_log.rs @@ -16,7 +16,7 @@ async fn log_messages( homeserver_url: Url, username: String, password: String, -) -> Result<(), ruma_client::Error> { +) -> anyhow::Result<()> { let client = HttpClient::new(homeserver_url, None); client.log_in(username, password, None, None).await?; @@ -61,7 +61,7 @@ async fn log_messages( } #[tokio::main] -async fn main() -> Result<(), ruma_client::Error> { +async fn main() -> anyhow::Result<()> { let (homeserver_url, username, password) = match (env::args().nth(1), env::args().nth(2), env::args().nth(3)) { (Some(a), Some(b), Some(c)) => (a, b, c), diff --git a/src/error.rs b/src/error.rs index 6e96f486..4fa8bd61 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,16 +1,13 @@ //! Error conditions. -use std::error::Error as StdError; -use std::fmt::{Display, Formatter, Result as FmtResult}; +use std::fmt::{self, Debug, Display, Formatter}; use ruma_api::error::{FromHttpResponseError, IntoHttpError}; -use crate::api; - /// An error that can occur during client operations. #[derive(Debug)] #[non_exhaustive] -pub enum Error { +pub enum Error { /// Queried endpoint requires authentication but was called on an anonymous client. AuthenticationRequired, /// Construction of the HTTP request failed (this should never happen). @@ -20,11 +17,11 @@ pub enum Error { /// Couldn't obtain an HTTP response (e.g. due to network or DNS issues). Response(ResponseError), /// Converting the HTTP response to one of ruma's types failed. - FromHttpResponse(FromHttpResponseError), + FromHttpResponse(FromHttpResponseError), } -impl Display for Error { - fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult { +impl Display for Error { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { Self::AuthenticationRequired => { write!(f, "The queried endpoint requires authentication but was called with an anonymous client.") @@ -39,33 +36,33 @@ impl Display for Error { } } -impl From for Error { +impl From for Error { fn from(err: IntoHttpError) -> Self { Error::IntoHttp(err) } } #[doc(hidden)] -impl From for Error { +impl From for Error { fn from(err: http::uri::InvalidUri) -> Self { Error::Url(UrlError(err)) } } #[doc(hidden)] -impl From for Error { +impl From for Error { fn from(err: hyper::Error) -> Self { Error::Response(ResponseError(err)) } } -impl From> for Error { - fn from(err: FromHttpResponseError) -> Self { +impl From> for Error { + fn from(err: FromHttpResponseError) -> Self { Error::FromHttpResponse(err) } } -impl StdError for Error {} +impl std::error::Error for Error {} #[derive(Debug)] pub struct UrlError(http::uri::InvalidUri); diff --git a/src/lib.rs b/src/lib.rs index dca34a4f..efe27347 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,7 @@ //! //! // You're now logged in! Write the session to a file if you want to restore it later. //! // Then start using the API! -//! # Result::<(), ruma_client::Error>::Ok(()) +//! # Result::<(), ruma_client::Error<_>>::Ok(()) //! }; //! ``` //! @@ -59,7 +59,7 @@ //! while let Some(response) = sync_stream.try_next().await? { //! // Do something with the data in the response... //! } -//! # Result::<(), ruma_client::Error>::Ok(()) +//! # Result::<(), ruma_client::Error<_>>::Ok(()) //! # }; //! ``` //! @@ -91,7 +91,7 @@ //! .await?; //! //! assert_eq!(response.room_id, RoomId::try_from("!n8f893n9:example.com").unwrap()); -//! # Result::<(), ruma_client::Error>::Ok(()) +//! # Result::<(), ruma_client::Error<_>>::Ok(()) //! } //! # ; //! ``` @@ -224,7 +224,7 @@ where password: String, device_id: Option, initial_device_display_name: Option, - ) -> Result { + ) -> Result> { use api::r0::session::login; let response = self @@ -251,7 +251,7 @@ 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 async fn register_guest(&self) -> Result { + pub async fn register_guest(&self) -> Result> { use api::r0::account::register; let response = self @@ -293,7 +293,7 @@ where &self, username: Option, password: String, - ) -> Result { + ) -> Result> { use api::r0::account::register; let response = self @@ -334,8 +334,9 @@ where since: Option, set_presence: api::r0::sync::sync_events::SetPresence, timeout: Option, - ) -> impl Stream> - + TryStream { + ) -> impl Stream>> + + TryStream> + { use api::r0::sync::sync_events; let client = self.clone(); @@ -361,32 +362,32 @@ where } /// Makes a request to a Matrix API endpoint. - pub fn request>( + pub fn request( &self, request: Request, - ) -> impl Future::Incoming, Error>> + ) -> impl Future::Incoming, Error>> // We need to duplicate Endpoint's where clauses because the compiler is not smart enough yet. // See https://github.com/rust-lang/rust/issues/54149 where Request::Incoming: TryFrom>, Error = FromHttpRequestError>, ::Incoming: - TryFrom>, Error = FromHttpResponseError>, + TryFrom>, Error = FromHttpResponseError>, { self.request_with_url_params(request, None) } /// Makes a request to a Matrix API endpoint including additional URL parameters. - pub fn request_with_url_params>( + pub fn request_with_url_params( &self, request: Request, params: Option>, - ) -> impl Future::Incoming, Error>> + ) -> impl Future::Incoming, Error>> // We need to duplicate Endpoint's where clauses because the compiler is not smart enough yet. // See https://github.com/rust-lang/rust/issues/54149 where Request::Incoming: TryFrom>, Error = FromHttpRequestError>, ::Incoming: - TryFrom>, Error = FromHttpResponseError>, + TryFrom>, Error = FromHttpResponseError>, { let client = self.0.clone(); From c08b847ea7a27be2c81217c54d8b05cb936f2559 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Mon, 20 Apr 2020 16:13:20 +0200 Subject: [PATCH 128/139] Update deps --- Cargo.toml | 8 ++++---- src/lib.rs | 12 ++++++++---- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 470c74d5..d3df0fad 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,10 +21,10 @@ futures-util = "0.3.4" http = "0.2.1" hyper = "0.13.5" hyper-tls = { version = "0.4.1", optional = true } -ruma-api = "0.16.0-rc.1" -ruma-client-api = "0.8.0-rc.1" -ruma-events = "0.19.0-rc.1" -ruma-identifiers = "0.15.1" +ruma-api = "0.16.0-rc.2" +ruma-client-api = "0.8.0-rc.3" +ruma-events = "0.19.0" +ruma-identifiers = "0.16.0" serde = { version = "1.0.106", features = ["derive"] } serde_json = "1.0.51" serde_urlencoded = "0.6.1" diff --git a/src/lib.rs b/src/lib.rs index efe27347..7f8f6399 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -251,7 +251,7 @@ 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 async fn register_guest(&self) -> Result> { + pub async fn register_guest(&self) -> Result> { use api::r0::account::register; let response = self @@ -293,7 +293,7 @@ where &self, username: Option, password: String, - ) -> Result> { + ) -> Result> { use api::r0::account::register; let response = self @@ -365,7 +365,9 @@ where pub fn request( &self, request: Request, - ) -> impl Future::Incoming, Error>> + ) -> impl Future< + Output = Result<::Incoming, Error>, + > // We need to duplicate Endpoint's where clauses because the compiler is not smart enough yet. // See https://github.com/rust-lang/rust/issues/54149 where @@ -381,7 +383,9 @@ where &self, request: Request, params: Option>, - ) -> impl Future::Incoming, Error>> + ) -> impl Future< + Output = Result<::Incoming, Error>, + > // We need to duplicate Endpoint's where clauses because the compiler is not smart enough yet. // See https://github.com/rust-lang/rust/issues/54149 where From 79ab5de536d505b03c94ef21140efee326fbaf58 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Mon, 20 Apr 2020 17:20:11 +0200 Subject: [PATCH 129/139] Update deps again --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index d3df0fad..e055c74d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,8 +22,8 @@ http = "0.2.1" hyper = "0.13.5" hyper-tls = { version = "0.4.1", optional = true } ruma-api = "0.16.0-rc.2" -ruma-client-api = "0.8.0-rc.3" -ruma-events = "0.19.0" +ruma-client-api = "0.8.0-rc.4" +ruma-events = "0.20.0" ruma-identifiers = "0.16.0" serde = { version = "1.0.106", features = ["derive"] } serde_json = "1.0.51" From 6373bab18acf9f9ebb66e81c2d989a2c698720ce Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Mon, 20 Apr 2020 17:22:41 +0200 Subject: [PATCH 130/139] Bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index e055c74d..671043d6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ license = "MIT" name = "ruma-client" readme = "README.md" repository = "https://github.com/ruma/ruma-client" -version = "0.4.0-beta.1" +version = "0.4.0-beta.2" [dependencies] futures-core = "0.3.4" From b3438bb99d3c6ce26d9071aba69706398ad789f0 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Wed, 22 Apr 2020 13:31:26 +0200 Subject: [PATCH 131/139] Update ruma-api, ruma-client-api, ruma-events --- Cargo.toml | 4 ++-- examples/hello_world.rs | 3 ++- examples/message_log.rs | 2 +- src/lib.rs | 36 ++++++------------------------------ 4 files changed, 11 insertions(+), 34 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 671043d6..c9b4d43d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,9 +21,9 @@ futures-util = "0.3.4" http = "0.2.1" hyper = "0.13.5" hyper-tls = { version = "0.4.1", optional = true } -ruma-api = "0.16.0-rc.2" +ruma-api = "0.16.0-rc.3" ruma-client-api = "0.8.0-rc.4" -ruma-events = "0.20.0" +ruma-events = "0.21.0-beta.1" ruma-identifiers = "0.16.0" serde = { version = "1.0.106", features = ["derive"] } serde_json = "1.0.51" diff --git a/examples/hello_world.rs b/examples/hello_world.rs index 6667e8c4..33020285 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -41,7 +41,8 @@ async fn hello_world(homeserver_url: Url, room: String) -> anyhow::Result<()> { format: None, formatted_body: None, relates_to: None, - }), + }) + .into(), }) .await?; diff --git a/examples/message_log.rs b/examples/message_log.rs index f8ef4c18..8971d43a 100644 --- a/examples/message_log.rs +++ b/examples/message_log.rs @@ -41,7 +41,7 @@ async fn log_messages( .timeline .events .into_iter() - .flat_map(|r| r.into_result()) + .flat_map(|r| r.deserialize()) { // Filter out the text messages if let RoomEvent::RoomMessage(MessageEvent { diff --git a/src/lib.rs b/src/lib.rs index 7f8f6399..4ad8fece 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -119,10 +119,7 @@ use http::Response as HttpResponse; use hyper::{client::HttpConnector, Client as HyperClient, Uri}; #[cfg(feature = "hyper-tls")] use hyper_tls::HttpsConnector; -use ruma_api::{ - error::{FromHttpRequestError, FromHttpResponseError}, - Endpoint, Outgoing, -}; +use ruma_api::Endpoint; use ruma_identifiers::DeviceId; use std::collections::BTreeMap; use url::Url; @@ -334,9 +331,8 @@ where since: Option, set_presence: api::r0::sync::sync_events::SetPresence, timeout: Option, - ) -> impl Stream>> - + TryStream> - { + ) -> impl Stream>> + + TryStream> { use api::r0::sync::sync_events; let client = self.clone(); @@ -365,16 +361,7 @@ where pub fn request( &self, request: Request, - ) -> impl Future< - Output = Result<::Incoming, Error>, - > - // We need to duplicate Endpoint's where clauses because the compiler is not smart enough yet. - // See https://github.com/rust-lang/rust/issues/54149 - where - Request::Incoming: TryFrom>, Error = FromHttpRequestError>, - ::Incoming: - TryFrom>, Error = FromHttpResponseError>, - { + ) -> impl Future>> { self.request_with_url_params(request, None) } @@ -383,16 +370,7 @@ where &self, request: Request, params: Option>, - ) -> impl Future< - Output = Result<::Incoming, Error>, - > - // We need to duplicate Endpoint's where clauses because the compiler is not smart enough yet. - // See https://github.com/rust-lang/rust/issues/54149 - where - Request::Incoming: TryFrom>, Error = FromHttpRequestError>, - ::Incoming: - TryFrom>, Error = FromHttpResponseError>, - { + ) -> impl Future>> { let client = self.0.clone(); let mut url = client.homeserver_url.clone(); @@ -432,9 +410,7 @@ where let full_body = hyper::body::to_bytes(body).await?; let full_response = HttpResponse::from_parts(head, full_body.as_ref().to_owned()); - Ok(::Incoming::try_from( - full_response, - )?) + Ok(Request::Response::try_from(full_response)?) } } } From fbb68eea84546febed047198fa01a47ce7c7416a Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Wed, 22 Apr 2020 22:57:57 +0200 Subject: [PATCH 132/139] Bump version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index c9b4d43d..a1daf89d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ license = "MIT" name = "ruma-client" readme = "README.md" repository = "https://github.com/ruma/ruma-client" -version = "0.4.0-beta.2" +version = "0.4.0-beta.3" [dependencies] futures-core = "0.3.4" From 288d5d37cb88ff176c5efd6e6054d7a53ea9c3e4 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Wed, 22 Apr 2020 23:10:44 +0200 Subject: [PATCH 133/139] More version bumps --- Cargo.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index a1daf89d..72c06e8a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,7 +13,7 @@ license = "MIT" name = "ruma-client" readme = "README.md" repository = "https://github.com/ruma/ruma-client" -version = "0.4.0-beta.3" +version = "0.4.0-beta.4" [dependencies] futures-core = "0.3.4" @@ -22,7 +22,7 @@ http = "0.2.1" hyper = "0.13.5" hyper-tls = { version = "0.4.1", optional = true } ruma-api = "0.16.0-rc.3" -ruma-client-api = "0.8.0-rc.4" +ruma-client-api = "0.8.0-rc.5" ruma-events = "0.21.0-beta.1" ruma-identifiers = "0.16.0" serde = { version = "1.0.106", features = ["derive"] } From 9b3156ad6c6b17d6ec560f2a3227b7b67384fc64 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 24 Apr 2020 19:45:54 +0200 Subject: [PATCH 134/139] travis: disable cache --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index e7f2baac..4830e4fc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,4 @@ language: "rust" -cache: "cargo" rust: - stable - beta From 4ec060071dd776ea254b22bdf4d1b2b88fefc797 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 24 Apr 2020 21:11:49 +0200 Subject: [PATCH 135/139] Switch CI from travis to builds.sr.ht --- .builds/beta.yml | 27 +++++++++++++++++++++++++++ .builds/nightly.yml | 32 ++++++++++++++++++++++++++++++++ .builds/stable.yml | 29 +++++++++++++++++++++++++++++ .travis.yml | 28 ---------------------------- 4 files changed, 88 insertions(+), 28 deletions(-) create mode 100644 .builds/beta.yml create mode 100644 .builds/nightly.yml create mode 100644 .builds/stable.yml delete mode 100644 .travis.yml diff --git a/.builds/beta.yml b/.builds/beta.yml new file mode 100644 index 00000000..a076189b --- /dev/null +++ b/.builds/beta.yml @@ -0,0 +1,27 @@ +image: archlinux +packages: + - rustup +sources: + - https://github.com/ruma/ruma-client +tasks: + - rustup: | + # We specify --profile minimal because we'd otherwise download docs + rustup toolchain install beta --profile minimal -c rustfmt -c clippy + rustup default beta + - test: | + cd ruma-client + + # We don't want the build to stop on individual failure of independent + # tools, so capture tool exit codes and set the task exit code manually + set +e + + cargo fmt -- --check + fmt_exit=$? + + cargo clippy --all-targets --all-features -- -D warnings + clippy_exit=$? + + cargo test --verbose + test_exit=$? + + exit $(( $fmt_exit || $clippy_exit || $test_exit )) diff --git a/.builds/nightly.yml b/.builds/nightly.yml new file mode 100644 index 00000000..db3fe2e6 --- /dev/null +++ b/.builds/nightly.yml @@ -0,0 +1,32 @@ +image: archlinux +packages: + - rustup +sources: + - https://github.com/ruma/ruma-client +tasks: + - rustup: | + rustup toolchain install nightly --profile minimal + rustup default nightly + + # Try installing rustfmt & clippy for nightly, but don't fail the build + # if they are not available + rustup component add rustfmt || true + rustup component add clippy || true + - test: | + cd ruma-client + + # We don't want the build to stop on individual failure of independent + # tools, so capture tool exit codes and set the task exit code manually + set +e + + if ( rustup component list | grep -q rustfmt ); then + cargo fmt -- --check + fi + fmt_exit=$? + + if ( rustup component list | grep -q clippy ); then + cargo clippy --all-targets --all-features -- -D warnings + fi + clippy_exit=$? + + exit $(( $fmt_exit || $clippy_exit )) diff --git a/.builds/stable.yml b/.builds/stable.yml new file mode 100644 index 00000000..421d3baa --- /dev/null +++ b/.builds/stable.yml @@ -0,0 +1,29 @@ +image: archlinux +packages: + - rustup +sources: + - https://github.com/ruma/ruma-client +tasks: + - rustup: | + # We specify --profile minimal because we'd otherwise download docs + rustup toolchain install stable --profile minimal -c rustfmt -c clippy + rustup default stable + - test: | + cd ruma-client + + # We don't want the build to stop on individual failure of independent + # tools, so capture tool exit codes and set the task exit code manually + set +e + + cargo fmt -- --check + fmt_exit=$? + + cargo clippy --all-targets --all-features -- -D warnings + clippy_exit=$? + + cargo test --verbose + test_exit=$? + + exit $(( $fmt_exit || $clippy_exit || $test_exit )) + # TODO: Add audit task once cargo-audit binary releases are available. + # See https://github.com/RustSec/cargo-audit/issues/66 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 4830e4fc..00000000 --- a/.travis.yml +++ /dev/null @@ -1,28 +0,0 @@ -language: "rust" -rust: - - stable - - beta - - nightly -jobs: - allow_failures: - - rust: nightly - fast_finish: true - -before_script: - - rustup component add rustfmt - - rustup component add clippy - - | - if [ "$TRAVIS_RUST_VERSION" == "stable" ]; then - cargo install --force cargo-audit - fi - - cargo generate-lockfile -script: - - | - if [ "$TRAVIS_RUST_VERSION" == "stable" ]; then - cargo audit - fi - - cargo fmt -- --check - - cargo clippy --all-targets --all-features -- -D warnings - - cargo build --verbose - - cargo test --verbose -if: "type != push OR (tag IS blank AND branch = master)" From 326e705468f5f9488a69c96e54c61ac13c01432b Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 22 May 2020 17:58:25 +0200 Subject: [PATCH 136/139] Fix hello_world example --- 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 33020285..254b7a5a 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -10,6 +10,7 @@ use ruma_client::{ identifiers::RoomAliasId, Client, }; +use serde_json::value::to_raw_value as to_raw_json_value; use url::Url; async fn hello_world(homeserver_url: Url, room: String) -> anyhow::Result<()> { @@ -36,13 +37,12 @@ async fn hello_world(homeserver_url: Url, room: String) -> anyhow::Result<()> { room_id, event_type: EventType::RoomMessage, txn_id: "1".to_owned(), - data: MessageEventContent::Text(TextMessageEventContent { + data: to_raw_json_value(&MessageEventContent::Text(TextMessageEventContent { body: "Hello World!".to_owned(), format: None, formatted_body: None, relates_to: None, - }) - .into(), + }))?, }) .await?; From 5ad4fd11c95348f5504002ec2f148e421563ed5c Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 22 May 2020 17:24:18 +0200 Subject: [PATCH 137/139] Improve Display implementation for Error --- src/error.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/error.rs b/src/error.rs index 4fa8bd61..f517d2d2 100644 --- a/src/error.rs +++ b/src/error.rs @@ -20,7 +20,7 @@ pub enum Error { FromHttpResponse(FromHttpResponseError), } -impl Display for Error { +impl Display for Error { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { match self { Self::AuthenticationRequired => { @@ -29,9 +29,7 @@ impl Display for Error { Self::IntoHttp(err) => write!(f, "HTTP request construction failed: {}", err), Self::Url(UrlError(err)) => write!(f, "Invalid URL: {}", err), Self::Response(ResponseError(err)) => write!(f, "Couldn't obtain a response: {}", err), - // FIXME: ruma-client-api's Error type currently doesn't implement - // `Display`, update this when it does. - Self::FromHttpResponse(_) => write!(f, "HTTP response conversion failed"), + Self::FromHttpResponse(err) => write!(f, "HTTP response conversion failed: {}", err), } } } @@ -62,7 +60,7 @@ impl From> for Error { } } -impl std::error::Error for Error {} +impl std::error::Error for Error {} #[derive(Debug)] pub struct UrlError(http::uri::InvalidUri); From d42852e1a31f9fd140a20b17ecfc5064144fe8b7 Mon Sep 17 00:00:00 2001 From: Jonas Platte Date: Fri, 22 May 2020 18:07:25 +0200 Subject: [PATCH 138/139] Update dependencies, bump version --- Cargo.toml | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 72c06e8a..37558be1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,26 +13,26 @@ license = "MIT" name = "ruma-client" readme = "README.md" repository = "https://github.com/ruma/ruma-client" -version = "0.4.0-beta.4" +version = "0.4.0" [dependencies] -futures-core = "0.3.4" -futures-util = "0.3.4" +futures-core = "0.3.5" +futures-util = "0.3.5" http = "0.2.1" hyper = "0.13.5" hyper-tls = { version = "0.4.1", optional = true } -ruma-api = "0.16.0-rc.3" -ruma-client-api = "0.8.0-rc.5" -ruma-events = "0.21.0-beta.1" -ruma-identifiers = "0.16.0" -serde = { version = "1.0.106", features = ["derive"] } -serde_json = "1.0.51" +ruma-api = "0.16.1" +ruma-client-api = "0.9.0" +ruma-events = "0.21.2" +ruma-identifiers = "0.16.1" +serde = { version = "1.0.110", features = ["derive"] } +serde_json = "1.0.53" serde_urlencoded = "0.6.1" url = "2.1.1" [dev-dependencies] -anyhow = "1.0.28" -tokio = { version = "0.2.18", features = ["macros"] } +anyhow = "1.0.31" +tokio = { version = "0.2.21", features = ["macros"] } [features] default = ["tls"] From fab0ef566f143c1926bff4af4a0a4751379eff1f Mon Sep 17 00:00:00 2001 From: Lieuwe Rooijakkers Date: Tue, 4 Aug 2020 19:53:38 +0200 Subject: [PATCH 139/139] Update Ruma crates dependencies --- Cargo.toml | 9 +++++---- examples/hello_world.rs | 3 +-- examples/message_log.rs | 26 ++++++++++++++------------ src/lib.rs | 9 +++++---- src/session.rs | 8 ++++---- 5 files changed, 29 insertions(+), 26 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 37558be1..6f65a811 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,10 +21,11 @@ futures-util = "0.3.5" http = "0.2.1" hyper = "0.13.5" hyper-tls = { version = "0.4.1", optional = true } -ruma-api = "0.16.1" -ruma-client-api = "0.9.0" -ruma-events = "0.21.2" -ruma-identifiers = "0.16.1" +ruma-api = "=0.17.0-alpha.1" +ruma-client-api = "=0.10.0-alpha.1" +ruma-common = "0.2.0" +ruma-events = "=0.22.0-alpha.1" +ruma-identifiers = "0.17.1" serde = { version = "1.0.110", features = ["derive"] } serde_json = "1.0.53" serde_urlencoded = "0.6.1" diff --git a/examples/hello_world.rs b/examples/hello_world.rs index 254b7a5a..df3ff6ad 100644 --- a/examples/hello_world.rs +++ b/examples/hello_world.rs @@ -39,8 +39,7 @@ async fn hello_world(homeserver_url: Url, room: String) -> anyhow::Result<()> { txn_id: "1".to_owned(), data: to_raw_json_value(&MessageEventContent::Text(TextMessageEventContent { body: "Hello World!".to_owned(), - format: None, - formatted_body: None, + formatted: None, relates_to: None, }))?, }) diff --git a/examples/message_log.rs b/examples/message_log.rs index 8971d43a..222243c6 100644 --- a/examples/message_log.rs +++ b/examples/message_log.rs @@ -3,13 +3,11 @@ use std::{env, process::exit, time::Duration}; use futures_util::stream::{StreamExt as _, TryStreamExt as _}; use ruma_client::{ self, - api::r0::sync::sync_events::SetPresence, - events::{ - collections::all::RoomEvent, - room::message::{MessageEvent, MessageEventContent, TextMessageEventContent}, - }, + events::room::message::{MessageEventContent, TextMessageEventContent}, HttpClient, }; +use ruma_common::presence::PresenceState; +use ruma_events::{AnySyncMessageEvent, AnySyncRoomEvent, SyncMessageEvent}; use url::Url; async fn log_messages( @@ -26,7 +24,7 @@ async fn log_messages( .sync( None, None, - SetPresence::Online, + PresenceState::Online, Some(Duration::from_secs(30)), ) // TODO: This is a horrible way to obtain an initial next_batch token that generates way @@ -44,12 +42,16 @@ async fn log_messages( .flat_map(|r| r.deserialize()) { // Filter out the text messages - if let RoomEvent::RoomMessage(MessageEvent { - content: - MessageEventContent::Text(TextMessageEventContent { body: msg_body, .. }), - sender, - .. - }) = event + if let AnySyncRoomEvent::Message(AnySyncMessageEvent::RoomMessage( + SyncMessageEvent { + content: + MessageEventContent::Text(TextMessageEventContent { + body: msg_body, .. + }), + sender, + .. + }, + )) = event { println!("{:?} in {:?}: {}", sender, room_id, msg_body); } diff --git a/src/lib.rs b/src/lib.rs index 4ad8fece..49a13e8e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,7 +45,8 @@ //! use std::time::Duration; //! //! # use futures_util::stream::{StreamExt as _, TryStreamExt as _}; -//! # use ruma_client::{api::r0::sync::sync_events::SetPresence, Client}; +//! # use ruma_client::Client; +//! # use ruma_common::presence::PresenceState; //! # let homeserver_url = "https://example.com".parse().unwrap(); //! # let client = Client::https(homeserver_url, None); //! # let next_batch_token = String::new(); @@ -53,7 +54,7 @@ //! let mut sync_stream = Box::pin(client.sync( //! None, //! Some(next_batch_token), -//! SetPresence::Online, +//! PresenceState::Online, //! Some(Duration::from_secs(30)), //! )); //! while let Some(response) = sync_stream.try_next().await? { @@ -219,7 +220,7 @@ where &self, user: String, password: String, - device_id: Option, + device_id: Option>, initial_device_display_name: Option, ) -> Result> { use api::r0::session::login; @@ -329,7 +330,7 @@ where &self, filter: Option, since: Option, - set_presence: api::r0::sync::sync_events::SetPresence, + set_presence: ruma_common::presence::PresenceState, timeout: Option, ) -> impl Stream>> + TryStream> { diff --git a/src/session.rs b/src/session.rs index f66ee982..8a540204 100644 --- a/src/session.rs +++ b/src/session.rs @@ -1,6 +1,6 @@ //! User sessions. -use ruma_identifiers::UserId; +use ruma_identifiers::{DeviceId, UserId}; /// A user session, containing an access token and information about the associated user account. #[derive(Clone, Debug, serde::Deserialize, Eq, Hash, PartialEq, serde::Serialize)] @@ -18,13 +18,13 @@ pub struct Identification { /// The user the access token was issued for. pub user_id: UserId, /// The ID of the client device - pub device_id: String, + pub device_id: Box, } impl Session { /// Create a new user session from an access token and a user ID. #[deprecated] - pub fn new(access_token: String, user_id: UserId, device_id: String) -> Self { + pub fn new(access_token: String, user_id: UserId, device_id: Box) -> Self { Self { access_token, identification: Some(Identification { user_id, device_id }), @@ -48,7 +48,7 @@ impl Session { /// Get ID of the device the session belongs to. #[deprecated] - pub fn device_id(&self) -> Option<&str> { + pub fn device_id(&self) -> Option<&DeviceId> { if let Some(identification) = &self.identification { return Some(&identification.device_id); }