diff --git a/crates/matrix_sdk/README.md b/crates/matrix_sdk/README.md index bc8ec120..9c90a120 100644 --- a/crates/matrix_sdk/README.md +++ b/crates/matrix_sdk/README.md @@ -10,7 +10,7 @@ Connecting and logging in to a homeserver is pretty starightforward: ```rust,no_run use std::convert::TryFrom; use matrix_sdk::{ - Client, SyncSettings, Result, + Client, config::SyncSettings, Result, ruma::{UserId, events::{SyncMessageEvent, room::message::MessageEventContent}}, }; diff --git a/crates/matrix_sdk/examples/autojoin.rs b/crates/matrix_sdk/examples/autojoin.rs index 5db51444..b3e4e223 100644 --- a/crates/matrix_sdk/examples/autojoin.rs +++ b/crates/matrix_sdk/examples/autojoin.rs @@ -1,9 +1,10 @@ use std::{env, process::exit}; use matrix_sdk::{ + config::{ClientConfig, SyncSettings}, room::Room, ruma::events::{room::member::MemberEventContent, StrippedStateEvent}, - Client, ClientConfig, SyncSettings, + Client, }; use tokio::time::{sleep, Duration}; use url::Url; diff --git a/crates/matrix_sdk/examples/command_bot.rs b/crates/matrix_sdk/examples/command_bot.rs index 77fbc34e..c02690ba 100644 --- a/crates/matrix_sdk/examples/command_bot.rs +++ b/crates/matrix_sdk/examples/command_bot.rs @@ -1,12 +1,13 @@ use std::{env, process::exit}; use matrix_sdk::{ + config::{ClientConfig, SyncSettings}, room::Room, ruma::events::{ room::message::{MessageEventContent, MessageType, TextMessageEventContent}, AnyMessageEventContent, SyncMessageEvent, }, - Client, ClientConfig, SyncSettings, + Client, }; use url::Url; diff --git a/crates/matrix_sdk/examples/cross_signing_bootstrap.rs b/crates/matrix_sdk/examples/cross_signing_bootstrap.rs index 35183ea1..1e99ad3f 100644 --- a/crates/matrix_sdk/examples/cross_signing_bootstrap.rs +++ b/crates/matrix_sdk/examples/cross_signing_bootstrap.rs @@ -4,7 +4,7 @@ use std::{ sync::atomic::{AtomicBool, Ordering}, }; -use matrix_sdk::{ruma::UserId, Client, LoopCtrl, SyncSettings}; +use matrix_sdk::{config::SyncSettings, ruma::UserId, Client, LoopCtrl}; use url::Url; async fn bootstrap(client: Client, user_id: UserId, password: String) { diff --git a/crates/matrix_sdk/examples/emoji_verification.rs b/crates/matrix_sdk/examples/emoji_verification.rs index f163b6dd..24be4121 100644 --- a/crates/matrix_sdk/examples/emoji_verification.rs +++ b/crates/matrix_sdk/examples/emoji_verification.rs @@ -9,6 +9,7 @@ use std::{ use matrix_sdk::{ self, + config::SyncSettings, encryption::verification::{SasVerification, Verification}, ruma::{ events::{ @@ -16,7 +17,7 @@ use matrix_sdk::{ }, UserId, }, - Client, LoopCtrl, SyncSettings, + Client, LoopCtrl, }; use url::Url; diff --git a/crates/matrix_sdk/examples/image_bot.rs b/crates/matrix_sdk/examples/image_bot.rs index a895c549..5a5dd0c6 100644 --- a/crates/matrix_sdk/examples/image_bot.rs +++ b/crates/matrix_sdk/examples/image_bot.rs @@ -9,12 +9,13 @@ use std::{ use matrix_sdk::{ self, + config::SyncSettings, room::Room, ruma::events::{ room::message::{MessageEventContent, MessageType, TextMessageEventContent}, SyncMessageEvent, }, - Client, SyncSettings, + Client, }; use tokio::sync::Mutex; use url::Url; diff --git a/crates/matrix_sdk/examples/login.rs b/crates/matrix_sdk/examples/login.rs index b34e6e6f..80f5ad02 100644 --- a/crates/matrix_sdk/examples/login.rs +++ b/crates/matrix_sdk/examples/login.rs @@ -2,12 +2,13 @@ use std::{env, process::exit}; use matrix_sdk::{ self, + config::SyncSettings, room::Room, ruma::events::{ room::message::{MessageEventContent, MessageType, TextMessageEventContent}, SyncMessageEvent, }, - Client, SyncSettings, + Client, }; use url::Url; diff --git a/crates/matrix_sdk/examples/wasm_command_bot/src/lib.rs b/crates/matrix_sdk/examples/wasm_command_bot/src/lib.rs index ddc6744b..f338a19f 100644 --- a/crates/matrix_sdk/examples/wasm_command_bot/src/lib.rs +++ b/crates/matrix_sdk/examples/wasm_command_bot/src/lib.rs @@ -1,4 +1,5 @@ use matrix_sdk::{ + config::SyncSettings, deserialized_responses::SyncResponse, ruma::{ events::{ @@ -7,7 +8,7 @@ use matrix_sdk::{ }, RoomId, }, - Client, LoopCtrl, SyncSettings, + Client, LoopCtrl, }; use url::Url; use wasm_bindgen::prelude::*; diff --git a/crates/matrix_sdk/src/client.rs b/crates/matrix_sdk/src/client.rs index dce6d41c..932ab38b 100644 --- a/crates/matrix_sdk/src/client.rs +++ b/crates/matrix_sdk/src/client.rs @@ -18,7 +18,6 @@ use std::{ fmt::{self, Debug}, future::Future, io::Read, - path::Path, pin::Pin, result::Result as StdResult, sync::Arc, @@ -27,11 +26,10 @@ use std::{ use dashmap::DashMap; use futures::FutureExt; use futures_timer::Delay as sleep; -use http::HeaderValue; use matrix_sdk_base::{ deserialized_responses::{JoinedRoom, LeftRoom, SyncResponse}, media::{MediaEventContent, MediaFormat, MediaRequest, MediaThumbnailSize, MediaType}, - BaseClient, BaseClientConfig, Session, Store, + BaseClient, Session, Store, }; use matrix_sdk_common::{ instant::{Duration, Instant}, @@ -39,7 +37,6 @@ use matrix_sdk_common::{ uuid::Uuid, }; use mime::{self, Mime}; -use reqwest::header::InvalidHeaderValue; use ruma::{ api::{ client::{ @@ -73,14 +70,13 @@ use tracing::{error, info, instrument, warn}; use url::Url; use crate::{ + config::{ClientConfig, RequestConfig}, error::{HttpError, HttpResult}, event_handler::{EventHandler, EventHandlerData, EventHandlerResult, EventKind, SyncEvent}, - http_client::{client_with_config, HttpClient, HttpSend}, + http_client::{client_with_config, HttpClient}, room, Error, Result, }; -const DEFAULT_REQUEST_TIMEOUT: Duration = Duration::from_secs(10); -const DEFAULT_SYNC_TIMEOUT: Duration = Duration::from_secs(30); /// A conservative upload speed of 1Mbps const DEFAULT_UPLOAD_SPEED: u64 = 125_000; /// 5 min minimal upload request timeout, used to clamp the request timeout. @@ -151,333 +147,6 @@ impl Debug for Client { } } -/// Configuration for the creation of the `Client`. -/// -/// When setting the `StateStore` it is up to the user to open/connect -/// the storage backend before client creation. -/// -/// # Example -/// -/// ``` -/// # use matrix_sdk::ClientConfig; -/// // To pass all the request through mitmproxy set the proxy and disable SSL -/// // verification -/// let client_config = ClientConfig::new() -/// .proxy("http://localhost:8080") -/// .unwrap() -/// .disable_ssl_verification(); -/// ``` -#[derive(Default)] -pub struct ClientConfig { - #[cfg(not(target_arch = "wasm32"))] - pub(crate) proxy: Option, - pub(crate) user_agent: Option, - pub(crate) disable_ssl_verification: bool, - pub(crate) base_config: BaseClientConfig, - pub(crate) request_config: RequestConfig, - pub(crate) client: Option>, - pub(crate) appservice_mode: bool, -} - -#[cfg(not(tarpaulin_include))] -impl Debug for ClientConfig { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut res = fmt.debug_struct("ClientConfig"); - - #[cfg(not(target_arch = "wasm32"))] - let res = res.field("proxy", &self.proxy); - - res.field("user_agent", &self.user_agent) - .field("disable_ssl_verification", &self.disable_ssl_verification) - .field("request_config", &self.request_config) - .finish() - } -} - -impl ClientConfig { - /// Create a new default `ClientConfig`. - pub fn new() -> Self { - Default::default() - } - - /// Set the proxy through which all the HTTP requests should go. - /// - /// Note, only HTTP proxies are supported. - /// - /// # Arguments - /// - /// * `proxy` - The HTTP URL of the proxy. - /// - /// # Example - /// - /// ``` - /// use matrix_sdk::ClientConfig; - /// - /// let client_config = ClientConfig::new() - /// .proxy("http://localhost:8080") - /// .unwrap(); - /// ``` - #[cfg(not(target_arch = "wasm32"))] - pub fn proxy(mut self, proxy: &str) -> Result { - self.proxy = Some(reqwest::Proxy::all(proxy)?); - Ok(self) - } - - /// Disable SSL verification for the HTTP requests. - pub fn disable_ssl_verification(mut self) -> Self { - self.disable_ssl_verification = true; - self - } - - /// Set a custom HTTP user agent for the client. - pub fn user_agent(mut self, user_agent: &str) -> StdResult { - self.user_agent = Some(HeaderValue::from_str(user_agent)?); - Ok(self) - } - - ///// Set a custom implementation of a `StateStore`. - ///// - ///// The state store should be opened before being set. - //pub fn state_store(mut self, store: Box) -> Self { - // self.base_config = self.base_config.state_store(store); - // self - //} - - /// Set the path for storage. - /// - /// # Arguments - /// - /// * `path` - The path where the stores should save data in. It is the - /// callers responsibility to make sure that the path exists. - /// - /// In the default configuration the client will open default - /// implementations for the crypto store and the state store. It will use - /// the given path to open the stores. If no path is provided no store will - /// be opened - pub fn store_path(mut self, path: impl AsRef) -> Self { - self.base_config = self.base_config.store_path(path); - self - } - - /// Set the passphrase to encrypt the crypto store. - /// - /// # Argument - /// - /// * `passphrase` - The passphrase that will be used to encrypt the data in - /// the cryptostore. - /// - /// This is only used if no custom cryptostore is set. - pub fn passphrase(mut self, passphrase: String) -> Self { - self.base_config = self.base_config.passphrase(passphrase); - self - } - - /// Set the default timeout, fail and retry behavior for all HTTP requests. - pub fn request_config(mut self, request_config: RequestConfig) -> Self { - self.request_config = request_config; - self - } - - /// Get the [`RequestConfig`] - pub fn get_request_config(&self) -> &RequestConfig { - &self.request_config - } - - /// Specify a client to handle sending requests and receiving responses. - /// - /// Any type that implements the `HttpSend` trait can be used to - /// send/receive `http` types. - pub fn client(mut self, client: Arc) -> Self { - self.client = Some(client); - self - } - - /// Puts the client into application service mode - /// - /// This is low-level functionality. For an high-level API check the - /// `matrix_sdk_appservice` crate. - #[cfg(feature = "appservice")] - pub fn appservice_mode(mut self) -> Self { - self.appservice_mode = true; - self - } -} - -#[derive(Debug, Clone)] -/// Settings for a sync call. -pub struct SyncSettings<'a> { - pub(crate) filter: Option>, - pub(crate) timeout: Option, - pub(crate) token: Option, - pub(crate) full_state: bool, -} - -impl<'a> Default for SyncSettings<'a> { - fn default() -> Self { - Self { - filter: Default::default(), - timeout: Some(DEFAULT_SYNC_TIMEOUT), - token: Default::default(), - full_state: Default::default(), - } - } -} - -impl<'a> SyncSettings<'a> { - /// Create new default sync settings. - pub fn new() -> Self { - Default::default() - } - - /// Set the sync token. - /// - /// # Arguments - /// - /// * `token` - The sync token that should be used for the sync call. - pub fn token(mut self, token: impl Into) -> Self { - self.token = Some(token.into()); - self - } - - /// Set the maximum time the server can wait, in milliseconds, before - /// responding to the sync request. - /// - /// # Arguments - /// - /// * `timeout` - The time the server is allowed to wait. - pub fn timeout(mut self, timeout: Duration) -> Self { - self.timeout = Some(timeout); - self - } - - /// Set the sync filter. - /// It can be either the filter ID, or the definition for the filter. - /// - /// # Arguments - /// - /// * `filter` - The filter configuration that should be used for the sync - /// call. - pub fn filter(mut self, filter: sync_events::Filter<'a>) -> Self { - self.filter = Some(filter); - self - } - - /// Should the server return the full state from the start of the timeline. - /// - /// This does nothing if no sync token is set. - /// - /// # Arguments - /// * `full_state` - A boolean deciding if the server should return the full - /// state or not. - pub fn full_state(mut self, full_state: bool) -> Self { - self.full_state = full_state; - self - } -} - -/// Configuration for requests the `Client` makes. -/// -/// This sets how often and for how long a request should be repeated. As well -/// as how long a successful request is allowed to take. -/// -/// By default requests are retried indefinitely and use no timeout. -/// -/// # Example -/// -/// ``` -/// # use matrix_sdk::RequestConfig; -/// # use std::time::Duration; -/// // This sets makes requests fail after a single send request and sets the timeout to 30s -/// let request_config = RequestConfig::new() -/// .disable_retry() -/// .timeout(Duration::from_secs(30)); -/// ``` -#[derive(Copy, Clone)] -pub struct RequestConfig { - pub(crate) timeout: Duration, - pub(crate) retry_limit: Option, - pub(crate) retry_timeout: Option, - pub(crate) force_auth: bool, - pub(crate) assert_identity: bool, -} - -#[cfg(not(tarpaulin_include))] -impl Debug for RequestConfig { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - let mut res = fmt.debug_struct("RequestConfig"); - - res.field("timeout", &self.timeout) - .field("retry_limit", &self.retry_limit) - .field("retry_timeout", &self.retry_timeout) - .finish() - } -} - -impl Default for RequestConfig { - fn default() -> Self { - Self { - timeout: DEFAULT_REQUEST_TIMEOUT, - retry_limit: Default::default(), - retry_timeout: Default::default(), - force_auth: false, - assert_identity: false, - } - } -} - -impl RequestConfig { - /// Create a new default `RequestConfig`. - pub fn new() -> Self { - Default::default() - } - - /// This is a convince method to disable the retries of a request. Setting - /// the `retry_limit` to `0` has the same effect. - pub fn disable_retry(mut self) -> Self { - self.retry_limit = Some(0); - self - } - - /// The number of times a request should be retried. The default is no limit - pub fn retry_limit(mut self, retry_limit: u64) -> Self { - self.retry_limit = Some(retry_limit); - self - } - - /// Set the timeout duration for all HTTP requests. - pub fn timeout(mut self, timeout: Duration) -> Self { - self.timeout = timeout; - self - } - - /// Set a timeout for how long a request should be retried. The default is - /// no timeout, meaning requests are retried forever. - pub fn retry_timeout(mut self, retry_timeout: Duration) -> Self { - self.retry_timeout = Some(retry_timeout); - self - } - - /// Force sending authorization even if the endpoint does not require it. - /// Default is only sending authorization if it is required. - pub(crate) fn force_auth(mut self) -> Self { - self.force_auth = true; - self - } - - /// All outgoing http requests will have a GET query key-value appended with - /// `user_id` being the key and the `user_id` from the `Session` being - /// the value. Will error if there's no `Session`. This is called - /// [identity assertion] in the Matrix Application Service Spec - /// - /// [identity assertion]: https://spec.matrix.org/unstable/application-service-api/#identity-assertion - #[cfg(feature = "appservice")] - #[cfg_attr(feature = "docs", doc(cfg(appservice)))] - pub fn assert_identity(mut self) -> Self { - self.assert_identity = true; - self - } -} - impl Client { /// Creates a new client for making HTTP requests to the given homeserver. /// @@ -1504,7 +1173,7 @@ impl Client { /// /// ```no_run /// # use matrix_sdk::{ - /// # Client, SyncSettings, + /// # Client, config::SyncSettings, /// # ruma::api::client::r0::{ /// # filter::{ /// # FilterDefinition, LazyLoadOptions, RoomEventFilter, RoomFilter, @@ -1789,7 +1458,7 @@ impl Client { /// # Example /// ```no_run /// # use std::sync::{Arc, RwLock}; - /// # use matrix_sdk::{Client, SyncSettings}; + /// # use matrix_sdk::{Client, config::SyncSettings}; /// # use url::Url; /// # use futures::executor::block_on; /// # use matrix_sdk::ruma::room_id; @@ -1847,7 +1516,7 @@ impl Client { /// # Example /// /// ```no_run - /// # use matrix_sdk::{Client, SyncSettings}; + /// # use matrix_sdk::{Client, config::SyncSettings}; /// # use futures::executor::block_on; /// # use url::Url; /// # use std::convert::TryFrom; @@ -1886,7 +1555,7 @@ impl Client { /// # Examples /// /// ```no_run - /// # use matrix_sdk::{Client, SyncSettings}; + /// # use matrix_sdk::{Client, config::SyncSettings}; /// # use futures::executor::block_on; /// # use url::Url; /// # use std::convert::TryFrom; @@ -1932,7 +1601,7 @@ impl Client { /// # }, /// # assign, /// # }, - /// # Client, Error, SyncSettings, + /// # Client, Error, config::SyncSettings, /// # }; /// # use futures::executor::block_on; /// # use serde_json::json; @@ -1981,7 +1650,10 @@ impl Client { /// /// [`sync`]: #method.sync #[instrument] - pub async fn sync_once(&self, sync_settings: SyncSettings<'_>) -> Result { + pub async fn sync_once( + &self, + sync_settings: crate::config::SyncSettings<'_>, + ) -> Result { let request = assign!(sync_events::Request::new(), { filter: sync_settings.filter.as_ref(), since: sync_settings.token.as_deref(), @@ -2102,7 +1774,7 @@ impl Client { /// will be only used for the first sync call. /// /// [`sync_with_callback`]: #method.sync_with_callback - pub async fn sync(&self, sync_settings: SyncSettings<'_>) { + pub async fn sync(&self, sync_settings: crate::config::SyncSettings<'_>) { self.sync_with_callback(sync_settings, |_| async { LoopCtrl::Continue }).await } @@ -2131,7 +1803,7 @@ impl Client { /// # }; /// # use std::sync::{Arc, RwLock}; /// # use std::time::Duration; - /// # use matrix_sdk::{Client, SyncSettings, LoopCtrl}; + /// # use matrix_sdk::{Client, config::SyncSettings, LoopCtrl}; /// # use url::Url; /// # use futures::executor::block_on; /// # block_on(async { @@ -2164,7 +1836,7 @@ impl Client { #[instrument(skip(callback))] pub async fn sync_with_callback( &self, - mut sync_settings: SyncSettings<'_>, + mut sync_settings: crate::config::SyncSettings<'_>, callback: impl Fn(SyncResponse) -> C, ) where C: Future, @@ -2540,8 +2212,11 @@ pub(crate) mod test { }; use serde_json::json; - use super::{Client, Session, SyncSettings, Url}; - use crate::{ClientConfig, HttpError, RequestConfig, RoomMember}; + use super::{Client, Session, Url}; + use crate::{ + config::{ClientConfig, RequestConfig, SyncSettings}, + HttpError, RoomMember, + }; pub(crate) async fn logged_in_client() -> Client { let session = Session { diff --git a/crates/matrix_sdk/src/config/client.rs b/crates/matrix_sdk/src/config/client.rs new file mode 100644 index 00000000..bfb51033 --- /dev/null +++ b/crates/matrix_sdk/src/config/client.rs @@ -0,0 +1,177 @@ +// Copyright 2021 The Matrix.org Foundation C.I.C. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::{ + fmt::{self, Debug}, + path::Path, + sync::Arc, +}; + +use http::{header::InvalidHeaderValue, HeaderValue}; +use matrix_sdk_base::BaseClientConfig; + +use crate::{config::RequestConfig, HttpSend, Result}; + +/// Configuration for the creation of the `Client`. +/// +/// When setting the `StateStore` it is up to the user to open/connect +/// the storage backend before client creation. +/// +/// # Example +/// +/// ``` +/// use matrix_sdk::config::ClientConfig; +/// // To pass all the request through mitmproxy set the proxy and disable SSL +/// // verification +/// let client_config = ClientConfig::new() +/// .proxy("http://localhost:8080")? +/// .disable_ssl_verification(); +/// # matrix_sdk::Result::<()>::Ok(()) +/// ``` +#[derive(Default)] +pub struct ClientConfig { + #[cfg(not(target_arch = "wasm32"))] + pub(crate) proxy: Option, + pub(crate) user_agent: Option, + pub(crate) disable_ssl_verification: bool, + pub(crate) base_config: BaseClientConfig, + pub(crate) request_config: RequestConfig, + pub(crate) client: Option>, + pub(crate) appservice_mode: bool, +} + +#[cfg(not(tarpaulin_include))] +impl Debug for ClientConfig { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut res = fmt.debug_struct("ClientConfig"); + + #[cfg(not(target_arch = "wasm32"))] + let res = res.field("proxy", &self.proxy); + + res.field("user_agent", &self.user_agent) + .field("disable_ssl_verification", &self.disable_ssl_verification) + .field("request_config", &self.request_config) + .finish() + } +} + +impl ClientConfig { + /// Create a new default `ClientConfig`. + pub fn new() -> Self { + Default::default() + } + + /// Set the proxy through which all the HTTP requests should go. + /// + /// Note, only HTTP proxies are supported. + /// + /// # Arguments + /// + /// * `proxy` - The HTTP URL of the proxy. + /// + /// # Example + /// + /// ``` + /// use matrix_sdk::{Client, config::ClientConfig}; + /// + /// let client_config = ClientConfig::new() + /// .proxy("http://localhost:8080")?; + /// + /// # matrix_sdk::Result::Ok(()) + /// ``` + #[cfg(not(target_arch = "wasm32"))] + pub fn proxy(mut self, proxy: &str) -> Result { + self.proxy = Some(reqwest::Proxy::all(proxy)?); + Ok(self) + } + + /// Disable SSL verification for the HTTP requests. + pub fn disable_ssl_verification(mut self) -> Self { + self.disable_ssl_verification = true; + self + } + + /// Set a custom HTTP user agent for the client. + pub fn user_agent(mut self, user_agent: &str) -> std::result::Result { + self.user_agent = Some(HeaderValue::from_str(user_agent)?); + Ok(self) + } + + ///// Set a custom implementation of a `StateStore`. + ///// + ///// The state store should be opened before being set. + //pub fn state_store(mut self, store: Box) -> Self { + // self.base_config = self.base_config.state_store(store); + // self + //} + + /// Set the path for storage. + /// + /// # Arguments + /// + /// * `path` - The path where the stores should save data in. It is the + /// callers responsibility to make sure that the path exists. + /// + /// In the default configuration the client will open default + /// implementations for the crypto store and the state store. It will use + /// the given path to open the stores. If no path is provided no store will + /// be opened + pub fn store_path(mut self, path: impl AsRef) -> Self { + self.base_config = self.base_config.store_path(path); + self + } + + /// Set the passphrase to encrypt the crypto store. + /// + /// # Argument + /// + /// * `passphrase` - The passphrase that will be used to encrypt the data in + /// the cryptostore. + /// + /// This is only used if no custom cryptostore is set. + pub fn passphrase(mut self, passphrase: String) -> Self { + self.base_config = self.base_config.passphrase(passphrase); + self + } + + /// Set the default timeout, fail and retry behavior for all HTTP requests. + pub fn request_config(mut self, request_config: RequestConfig) -> Self { + self.request_config = request_config; + self + } + + /// Get the [`RequestConfig`] + pub fn get_request_config(&self) -> &RequestConfig { + &self.request_config + } + + /// Specify a client to handle sending requests and receiving responses. + /// + /// Any type that implements the `HttpSend` trait can be used to + /// send/receive `http` types. + pub fn client(mut self, client: Arc) -> Self { + self.client = Some(client); + self + } + + /// Puts the client into application service mode + /// + /// This is low-level functionality. For an high-level API check the + /// `matrix_sdk_appservice` crate. + #[cfg(feature = "appservice")] + pub fn appservice_mode(mut self) -> Self { + self.appservice_mode = true; + self + } +} diff --git a/crates/matrix_sdk/src/config/mod.rs b/crates/matrix_sdk/src/config/mod.rs new file mode 100644 index 00000000..48830e78 --- /dev/null +++ b/crates/matrix_sdk/src/config/mod.rs @@ -0,0 +1,25 @@ +// Copyright 2021 The Matrix.org Foundation C.I.C. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Configuration to change the behaviour of the [`Client`]. +//! +//! [`Client`]: #crate.Client + +mod client; +mod request; +mod sync; + +pub use client::ClientConfig; +pub use request::RequestConfig; +pub use sync::SyncSettings; diff --git a/crates/matrix_sdk/src/config/request.rs b/crates/matrix_sdk/src/config/request.rs new file mode 100644 index 00000000..aea7659b --- /dev/null +++ b/crates/matrix_sdk/src/config/request.rs @@ -0,0 +1,124 @@ +// Copyright 2021 The Matrix.org Foundation C.I.C. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::{ + fmt::{self, Debug}, + time::Duration, +}; + +const DEFAULT_REQUEST_TIMEOUT: Duration = Duration::from_secs(10); + +/// Configuration for requests the `Client` makes. +/// +/// This sets how often and for how long a request should be repeated. As well +/// as how long a successful request is allowed to take. +/// +/// By default requests are retried indefinitely and use no timeout. +/// +/// # Example +/// +/// ``` +/// use matrix_sdk::config::RequestConfig; +/// use std::time::Duration; +/// +/// // This sets makes requests fail after a single send request and sets the timeout to 30s +/// let request_config = RequestConfig::new() +/// .disable_retry() +/// .timeout(Duration::from_secs(30)); +/// ``` +#[derive(Copy, Clone)] +pub struct RequestConfig { + pub(crate) timeout: Duration, + pub(crate) retry_limit: Option, + pub(crate) retry_timeout: Option, + pub(crate) force_auth: bool, + pub(crate) assert_identity: bool, +} + +#[cfg(not(tarpaulin_include))] +impl Debug for RequestConfig { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut res = fmt.debug_struct("RequestConfig"); + + res.field("timeout", &self.timeout) + .field("retry_limit", &self.retry_limit) + .field("retry_timeout", &self.retry_timeout) + .finish() + } +} + +impl Default for RequestConfig { + fn default() -> Self { + Self { + timeout: DEFAULT_REQUEST_TIMEOUT, + retry_limit: Default::default(), + retry_timeout: Default::default(), + force_auth: false, + assert_identity: false, + } + } +} + +impl RequestConfig { + /// Create a new default `RequestConfig`. + pub fn new() -> Self { + Default::default() + } + + /// This is a convince method to disable the retries of a request. Setting + /// the `retry_limit` to `0` has the same effect. + pub fn disable_retry(mut self) -> Self { + self.retry_limit = Some(0); + self + } + + /// The number of times a request should be retried. The default is no limit + pub fn retry_limit(mut self, retry_limit: u64) -> Self { + self.retry_limit = Some(retry_limit); + self + } + + /// Set the timeout duration for all HTTP requests. + pub fn timeout(mut self, timeout: Duration) -> Self { + self.timeout = timeout; + self + } + + /// Set a timeout for how long a request should be retried. The default is + /// no timeout, meaning requests are retried forever. + pub fn retry_timeout(mut self, retry_timeout: Duration) -> Self { + self.retry_timeout = Some(retry_timeout); + self + } + + /// Force sending authorization even if the endpoint does not require it. + /// Default is only sending authorization if it is required. + pub(crate) fn force_auth(mut self) -> Self { + self.force_auth = true; + self + } + + /// All outgoing http requests will have a GET query key-value appended with + /// `user_id` being the key and the `user_id` from the `Session` being + /// the value. Will error if there's no `Session`. This is called + /// [identity assertion] in the Matrix Application Service Spec + /// + /// [identity assertion]: https://spec.matrix.org/unstable/application-service-api/#identity-assertion + #[cfg(feature = "appservice")] + #[cfg_attr(feature = "docs", doc(cfg(appservice)))] + pub fn assert_identity(mut self) -> Self { + self.assert_identity = true; + self + } +} diff --git a/crates/matrix_sdk/src/config/sync.rs b/crates/matrix_sdk/src/config/sync.rs new file mode 100644 index 00000000..939d250a --- /dev/null +++ b/crates/matrix_sdk/src/config/sync.rs @@ -0,0 +1,91 @@ +// Copyright 2021 The Matrix.org Foundation C.I.C. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +use std::time::Duration; + +use ruma::api::client::r0::sync::sync_events; + +const DEFAULT_SYNC_TIMEOUT: Duration = Duration::from_secs(30); + +#[derive(Debug, Clone)] +/// Settings for a sync call. +pub struct SyncSettings<'a> { + pub(crate) filter: Option>, + pub(crate) timeout: Option, + pub(crate) token: Option, + pub(crate) full_state: bool, +} + +impl<'a> Default for SyncSettings<'a> { + fn default() -> Self { + Self { + filter: Default::default(), + timeout: Some(DEFAULT_SYNC_TIMEOUT), + token: Default::default(), + full_state: Default::default(), + } + } +} + +impl<'a> SyncSettings<'a> { + /// Create new default sync settings. + pub fn new() -> Self { + Default::default() + } + + /// Set the sync token. + /// + /// # Arguments + /// + /// * `token` - The sync token that should be used for the sync call. + pub fn token(mut self, token: impl Into) -> Self { + self.token = Some(token.into()); + self + } + + /// Set the maximum time the server can wait, in milliseconds, before + /// responding to the sync request. + /// + /// # Arguments + /// + /// * `timeout` - The time the server is allowed to wait. + pub fn timeout(mut self, timeout: Duration) -> Self { + self.timeout = Some(timeout); + self + } + + /// Set the sync filter. + /// It can be either the filter ID, or the definition for the filter. + /// + /// # Arguments + /// + /// * `filter` - The filter configuration that should be used for the sync + /// call. + pub fn filter(mut self, filter: sync_events::Filter<'a>) -> Self { + self.filter = Some(filter); + self + } + + /// Should the server return the full state from the start of the timeline. + /// + /// This does nothing if no sync token is set. + /// + /// # Arguments + /// * `full_state` - A boolean deciding if the server should return the full + /// state or not. + pub fn full_state(mut self, full_state: bool) -> Self { + self.full_state = full_state; + self + } +} diff --git a/crates/matrix_sdk/src/encryption/mod.rs b/crates/matrix_sdk/src/encryption/mod.rs index cc92dbd1..e541eb19 100644 --- a/crates/matrix_sdk/src/encryption/mod.rs +++ b/crates/matrix_sdk/src/encryption/mod.rs @@ -344,7 +344,7 @@ impl Client { /// ```no_run /// # use std::{path::PathBuf, time::Duration}; /// # use matrix_sdk::{ - /// # Client, SyncSettings, + /// # Client, config::SyncSettings, /// # ruma::room_id, /// # }; /// # use futures::executor::block_on; @@ -414,7 +414,7 @@ impl Client { /// ```no_run /// # use std::{path::PathBuf, time::Duration}; /// # use matrix_sdk::{ - /// # Client, SyncSettings, + /// # Client, config::SyncSettings, /// # ruma::room_id, /// # }; /// # use futures::executor::block_on; diff --git a/crates/matrix_sdk/src/http_client.rs b/crates/matrix_sdk/src/http_client.rs index ed5477a4..ee317343 100644 --- a/crates/matrix_sdk/src/http_client.rs +++ b/crates/matrix_sdk/src/http_client.rs @@ -25,7 +25,11 @@ use ruma::api::{ use tracing::trace; use url::Url; -use crate::{error::HttpError, ClientConfig, RequestConfig, Session}; +use crate::{ + config::{ClientConfig, RequestConfig}, + error::HttpError, + Session, +}; /// Abstraction around the http layer. The allows implementors to use different /// http libraries. @@ -49,7 +53,7 @@ pub trait HttpSend: AsyncTraitDeps { /// /// ``` /// use std::convert::TryFrom; - /// use matrix_sdk::{HttpSend, async_trait, HttpError, RequestConfig, bytes::Bytes}; + /// use matrix_sdk::{HttpSend, async_trait, HttpError, config::RequestConfig, bytes::Bytes}; /// /// #[derive(Debug)] /// struct Client(reqwest::Client); diff --git a/crates/matrix_sdk/src/lib.rs b/crates/matrix_sdk/src/lib.rs index 87972ea2..3ff499e6 100644 --- a/crates/matrix_sdk/src/lib.rs +++ b/crates/matrix_sdk/src/lib.rs @@ -47,6 +47,7 @@ pub use reqwest; pub use ruma; mod client; +pub mod config; mod error; pub mod event_handler; mod http_client; @@ -59,7 +60,7 @@ mod room_member; #[cfg_attr(feature = "docs", doc(cfg(encryption)))] pub mod encryption; -pub use client::{Client, ClientConfig, LoopCtrl, RequestConfig, SyncSettings}; +pub use client::{Client, LoopCtrl}; pub use error::{Error, HttpError, HttpResult, Result}; pub use http_client::HttpSend; pub use room_member::RoomMember; diff --git a/crates/matrix_sdk/src/room/joined.rs b/crates/matrix_sdk/src/room/joined.rs index 048ba7a3..2b590b30 100644 --- a/crates/matrix_sdk/src/room/joined.rs +++ b/crates/matrix_sdk/src/room/joined.rs @@ -162,8 +162,9 @@ impl Joined { /// ```no_run /// use std::time::Duration; /// use matrix_sdk::ruma::api::client::r0::typing::create_typing_event::Typing; + /// /// # use matrix_sdk::{ - /// # Client, SyncSettings, + /// # Client, config::SyncSettings, /// # ruma::room_id, /// # }; /// # use futures::executor::block_on; @@ -348,7 +349,7 @@ impl Joined { /// # Example /// ```no_run /// # use std::sync::{Arc, RwLock}; - /// # use matrix_sdk::{Client, SyncSettings}; + /// # use matrix_sdk::{Client, config::SyncSettings}; /// # use url::Url; /// # use futures::executor::block_on; /// # use matrix_sdk::ruma::room_id; diff --git a/crates/matrix_sdk_appservice/src/lib.rs b/crates/matrix_sdk_appservice/src/lib.rs index 46269c14..ad12cbbe 100644 --- a/crates/matrix_sdk_appservice/src/lib.rs +++ b/crates/matrix_sdk_appservice/src/lib.rs @@ -92,9 +92,10 @@ pub use matrix_sdk; pub use matrix_sdk::ruma; use matrix_sdk::{ bytes::Bytes, + config::ClientConfig, event_handler::{EventHandler, EventHandlerResult, SyncEvent}, reqwest::Url, - Client, ClientConfig, Session, + Client, Session, }; use regex::Regex; use ruma::{ diff --git a/crates/matrix_sdk_appservice/tests/tests.rs b/crates/matrix_sdk_appservice/tests/tests.rs index 8551c65d..b4f315af 100644 --- a/crates/matrix_sdk_appservice/tests/tests.rs +++ b/crates/matrix_sdk_appservice/tests/tests.rs @@ -4,11 +4,11 @@ use std::{ }; use matrix_sdk::{ + config::{ClientConfig, RequestConfig}, ruma::{ api::appservice::Registration, events::{room::member::MemberEventContent, SyncStateEvent}, }, - ClientConfig, RequestConfig, }; use matrix_sdk_appservice::*; use matrix_sdk_test::{appservice::TransactionBuilder, async_test, EventsJson};