Merge branch 'http-send-trait' into master

master
Damir Jelić 2020-08-11 17:07:34 +02:00
commit fe572017b1
6 changed files with 161 additions and 56 deletions

View File

@ -17,6 +17,7 @@ encryption = ["matrix-sdk-base/encryption"]
sqlite-cryptostore = ["matrix-sdk-base/sqlite-cryptostore"]
[dependencies]
async-trait = "0.1.36"
http = "0.2.1"
# FIXME: Revert to regular dependency once 0.10.8 or 0.11.0 is released
reqwest = { git = "https://github.com/seanmonstar/reqwest", rev = "dd8441fd23dae6ffb79b4cea2862e5bca0c59743" }

View File

@ -47,15 +47,14 @@ use url::Url;
use crate::{
events::{room::message::MessageEventContent, EventType},
http_client::DefaultHttpClient,
identifiers::{EventId, RoomId, RoomIdOrAliasId, UserId},
Endpoint,
Endpoint, HttpSend,
};
#[cfg(feature = "encryption")]
use crate::{identifiers::DeviceId, sas::Sas};
#[cfg(not(target_arch = "wasm32"))]
use crate::VERSION;
use crate::{api, http_client::HttpClient, EventEmitter, Result};
use matrix_sdk_base::{BaseClient, BaseClientConfig, Room, Session, StateStore};
@ -108,11 +107,12 @@ impl Debug for Client {
#[derive(Default)]
pub struct ClientConfig {
#[cfg(not(target_arch = "wasm32"))]
proxy: Option<reqwest::Proxy>,
user_agent: Option<HeaderValue>,
disable_ssl_verification: bool,
base_config: BaseClientConfig,
timeout: Option<Duration>,
pub(crate) proxy: Option<reqwest::Proxy>,
pub(crate) user_agent: Option<HeaderValue>,
pub(crate) disable_ssl_verification: bool,
pub(crate) base_config: BaseClientConfig,
pub(crate) timeout: Option<Duration>,
pub(crate) client: Option<Arc<dyn HttpSend>>,
}
// #[cfg_attr(tarpaulin, skip)]
@ -212,6 +212,15 @@ impl ClientConfig {
self.timeout = Some(timeout);
self
}
/// 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<dyn HttpSend>) -> Self {
self.client = Some(client);
self
}
}
#[derive(Debug, Default, Clone)]
@ -322,48 +331,21 @@ impl Client {
config: ClientConfig,
) -> Result<Self> {
let homeserver = if let Ok(u) = homeserver_url.try_into() {
u
Arc::new(u)
} else {
panic!("Error parsing homeserver url")
};
let http_client = reqwest::Client::builder();
#[cfg(not(target_arch = "wasm32"))]
let http_client = {
let http_client = match config.timeout {
Some(x) => http_client.timeout(x),
None => http_client,
};
let http_client = if config.disable_ssl_verification {
http_client.danger_accept_invalid_certs(true)
} else {
http_client
};
let http_client = match config.proxy {
Some(p) => http_client.proxy(p),
None => http_client,
};
let mut headers = reqwest::header::HeaderMap::new();
let user_agent = match config.user_agent {
Some(a) => a,
None => HeaderValue::from_str(&format!("matrix-rust-sdk {}", VERSION)).unwrap(),
};
headers.insert(reqwest::header::USER_AGENT, user_agent);
http_client.default_headers(headers)
};
let homeserver = Arc::new(homeserver);
let http_client = HttpClient {
homeserver: homeserver.clone(),
inner: http_client.build()?,
let http_client = if let Some(client) = config.client {
HttpClient {
homeserver: homeserver.clone(),
inner: client,
}
} else {
HttpClient {
homeserver: homeserver.clone(),
inner: Arc::new(DefaultHttpClient::with_config(&config)?),
}
};
let base_client = BaseClient::new_with_config(config.base_config)?;

View File

@ -12,23 +12,20 @@
// See the License for the specific language governing permissions and
// limitations under the License.
use std::{
convert::{TryFrom, TryInto},
sync::Arc,
};
use std::{convert::TryFrom, sync::Arc};
use http::{HeaderValue, Method as HttpMethod, Response as HttpResponse};
use matrix_sdk_common::{locks::RwLock, FromHttpResponseError};
use matrix_sdk_common_macros::async_trait;
use reqwest::{Client, Response};
use tracing::trace;
use url::Url;
use matrix_sdk_common::{locks::RwLock, FromHttpResponseError};
use crate::{Endpoint, Error, Result, Session};
use crate::{ClientConfig, Endpoint, Error, HttpSend, Result, Session};
#[derive(Clone, Debug)]
pub(crate) struct HttpClient {
pub(crate) inner: Client,
pub(crate) inner: Arc<dyn HttpSend>,
pub(crate) homeserver: Arc<Url>,
}
@ -62,7 +59,7 @@ impl HttpClient {
);
}
Ok(self.inner.execute(request.try_into()?).await?)
self.inner.send_request(request).await
}
async fn response_to_http_response(
@ -100,3 +97,66 @@ impl HttpClient {
Ok(Request::IncomingResponse::try_from(response)?)
}
}
/// Default http client used if none is specified using `Client::with_client`.
#[derive(Clone, Debug)]
pub struct DefaultHttpClient {
inner: Client,
}
impl DefaultHttpClient {
/// Build a client with the specified configuration.
pub fn with_config(config: &ClientConfig) -> Result<Self> {
let http_client = reqwest::Client::builder();
#[cfg(not(target_arch = "wasm32"))]
let http_client = {
let http_client = match config.timeout {
Some(x) => http_client.timeout(x),
None => http_client,
};
let http_client = if config.disable_ssl_verification {
http_client.danger_accept_invalid_certs(true)
} else {
http_client
};
let http_client = match &config.proxy {
Some(p) => http_client.proxy(p.clone()),
None => http_client,
};
let mut headers = reqwest::header::HeaderMap::new();
let user_agent = match &config.user_agent {
Some(a) => a.clone(),
None => {
HeaderValue::from_str(&format!("matrix-rust-sdk {}", crate::VERSION)).unwrap()
}
};
headers.insert(reqwest::header::USER_AGENT, user_agent);
http_client.default_headers(headers)
};
#[cfg(target_arch = "wasm32")]
#[allow(unused)]
let _ = config;
Ok(Self {
inner: http_client.build()?,
})
}
}
#[async_trait]
impl HttpSend for DefaultHttpClient {
async fn send_request(&self, request: http::Request<Vec<u8>>) -> Result<Response> {
Ok(self
.inner
.execute(reqwest::Request::try_from(request)?)
.await?)
}
}

View File

@ -0,0 +1,60 @@
// Copyright 2020 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::Debug;
use matrix_sdk_common_macros::async_trait;
use reqwest::Response;
use crate::Result;
/// Abstraction around the http layer. The allows implementors to use different
/// http libraries.
#[async_trait]
pub trait HttpSend: Sync + Send + Debug {
/// The method abstracting sending request types and receiving response types.
///
/// This is called by the client every time it wants to send anything to a homeserver.
///
/// # Arguments
///
/// * `request` - The http request that has been converted from a ruma `Request`.
///
/// # Returns
///
/// A `reqwest::Response` that will be converted to a ruma `Response` in the `Client`.
///
/// # Examples
///
/// ```ignore
/// use matrix_sdk::HttpSend;
/// use matrix_sdk_common_macros::async_trait;
/// use reqwest::Response;
///
/// #[derive(Debug)]
/// struct TestSend;
///
/// impl HttpSend for TestSend {
/// async fn send_request(&self, request: http::Request<Vec<u8>>) -> Result<Response>
/// // send the request somehow
/// let response = send(request, method, homeserver).await?;
///
/// // reqwest can convert to and from `http::Response` types.
/// Ok(reqwest::Response::from(response))
/// }
/// }
///
/// ```
async fn send_request(&self, request: http::Request<Vec<u8>>) -> Result<Response>;
}

View File

@ -51,6 +51,7 @@ pub use reqwest::header::InvalidHeaderValue;
mod client;
mod error;
mod http_client;
mod http_send;
mod request_builder;
#[cfg(feature = "encryption")]
@ -58,6 +59,7 @@ mod sas;
pub use client::{Client, ClientConfig, SyncSettings};
pub use error::{Error, Result};
pub use http_send::HttpSend;
pub use request_builder::{
MessagesRequestBuilder, RegistrationBuilder, RoomBuilder, RoomListFilterBuilder,
};

View File

@ -14,5 +14,5 @@ version = "0.1.0"
proc-macro = true
[dependencies]
syn = "1.0.34"
syn = "1.0.38"
quote = "1.0.7"