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); } } }