feat(sdk): Fetch supported matrix versions from server in initialization

This commit is contained in:
Jonas Platte
2022-03-14 15:23:13 +01:00
committed by GitHub
5 changed files with 64 additions and 60 deletions

View File

@@ -10,7 +10,7 @@ use matrix_sdk::{
};
use matrix_sdk_appservice::*;
use matrix_sdk_test::{appservice::TransactionBuilder, async_test, EventsJson};
use ruma::room_id;
use ruma::{api::MatrixVersion, room_id};
use serde_json::json;
use warp::{Filter, Reply};
@@ -35,7 +35,7 @@ async fn appservice(registration: Option<Registration>) -> Result<AppService> {
let client_builder = Client::builder()
.request_config(RequestConfig::default().disable_retry())
.check_supported_versions(false);
.server_versions([MatrixVersion::V1_0]);
AppService::with_client_builder(
homeserver_url.as_ref(),

View File

@@ -3,7 +3,7 @@ use quote::{format_ident, quote, ToTokens};
use syn::{self, parse_macro_input};
/// Attribute to use `wasm_bindgen_test` for wasm32 targets and `tokio::test`
/// for everything else with async-support and custom result-tyupes
/// for everything else with async-support and custom result-types
#[proc_macro_attribute]
pub fn async_test(_attr: TokenStream, item: TokenStream) -> TokenStream {
let fun = parse_macro_input!(item as syn::ItemFn);

View File

@@ -1,7 +1,13 @@
use std::sync::Arc;
use matrix_sdk_base::{locks::RwLock, store::StoreConfig, BaseClient, StateStore};
use ruma::{api::client::discover::discover_homeserver, ServerName, UserId};
use ruma::{
api::{
client::discover::{discover_homeserver, get_supported_versions},
MatrixVersion,
},
ServerName, UserId,
};
use thiserror::Error;
use url::Url;
@@ -58,7 +64,7 @@ pub struct ClientBuilder {
request_config: RequestConfig,
respect_login_well_known: bool,
appservice_mode: bool,
check_supported_versions: bool,
server_versions: Option<Arc<[MatrixVersion]>>,
}
impl ClientBuilder {
@@ -70,7 +76,7 @@ impl ClientBuilder {
request_config: Default::default(),
respect_login_well_known: true,
appservice_mode: false,
check_supported_versions: true,
server_versions: None,
}
}
@@ -242,13 +248,12 @@ impl ClientBuilder {
self
}
/// Specify whether the homeserver functionality should be checked through a
/// get_supported_versions request.
/// Specify the Matrix versions supported by the homeserver manually, rather
/// than `build()` doing it using a `get_supported_versions` request.
///
/// This is helpful for test code that doesn't care to mock that endpoint.
#[doc(hidden)]
pub fn check_supported_versions(mut self, value: bool) -> Self {
self.check_supported_versions = value;
pub fn server_versions(mut self, value: impl IntoIterator<Item = MatrixVersion>) -> Self {
self.server_versions = Some(value.into_iter().collect());
self
}
@@ -267,8 +272,8 @@ impl ClientBuilder {
/// URL
/// * HTTP error: If you supplied a user ID instead of a homeserver URL, a
/// server discovery request is made which can fail; if you didn't set
/// [`check_supported_versions(false)`][Self::check_supported_versions],
/// that amounts to another request that can fail
/// [`server_versions(false)`][Self::server_versions], that amounts to
/// another request that can fail
pub async fn build(self) -> Result<Client, ClientBuildError> {
let homeserver_cfg = self.homeserver_cfg.ok_or(ClientBuildError::MissingHomeserver)?;
@@ -301,8 +306,13 @@ impl ClientBuilder {
HomeserverConfig::ServerName(server_name) => {
let homeserver = homeserver_from_name(&server_name)?;
let http_client = mk_http_client(Arc::new(RwLock::new(homeserver)));
let well_known =
http_client.send(discover_homeserver::Request::new(), None).await?;
let well_known = http_client
.send(
discover_homeserver::Request::new(),
None,
[MatrixVersion::V1_0].into_iter().collect(),
)
.await?;
well_known.homeserver.base_url
}
@@ -311,10 +321,24 @@ impl ClientBuilder {
let homeserver = Arc::new(RwLock::new(Url::parse(&homeserver)?));
let http_client = mk_http_client(homeserver.clone());
let server_versions = match self.server_versions {
Some(vs) => vs,
None => http_client
.send(
get_supported_versions::Request::new(),
Some(RequestConfig::short_retry()),
[MatrixVersion::V1_0].into_iter().collect(),
)
.await?
.known_versions()
.collect(),
};
let inner = Arc::new(ClientInner {
homeserver,
http_client,
base_client,
server_versions,
#[cfg(feature = "encryption")]
group_session_locks: Default::default(),
#[cfg(feature = "encryption")]
@@ -328,13 +352,8 @@ impl ClientBuilder {
respect_login_well_known: self.respect_login_well_known,
sync_beat: event_listener::Event::new(),
});
let client = Client { inner };
if self.check_supported_versions {
client.get_supported_versions().await?;
}
Ok(client)
Ok(Client { inner })
}
}

View File

@@ -44,7 +44,6 @@ use ruma::{
capabilities::{get_capabilities, Capabilities},
device::{delete_devices, get_devices},
directory::{get_public_rooms, get_public_rooms_filtered},
discover::get_supported_versions,
filter::{create_filter::v3::Request as FilterUploadRequest, FilterDefinition},
media::{create_content, get_content, get_content_thumbnail},
membership::{join_room_by_id, join_room_by_id_or_alias},
@@ -124,6 +123,8 @@ pub(crate) struct ClientInner {
http_client: HttpClient,
/// User session data.
base_client: BaseClient,
/// The Matrix versions the server supports (well-known ones only)
server_versions: Arc<[MatrixVersion]>,
/// Locks making sure we only have one group session sharing request in
/// flight per room.
#[cfg(feature = "encryption")]
@@ -208,29 +209,6 @@ impl Client {
*homeserver = homeserver_url;
}
/// Get the versions supported by the homeserver.
///
/// This method should be used to check that a server is a valid Matrix
/// homeserver.
///
/// # Example
/// ```no_run
/// # use futures::executor::block_on;
/// # block_on(async {
/// use matrix_sdk::{Client};
/// use url::Url;
///
/// let homeserver = Url::parse("http://example.com")?;
/// let client = Client::new(homeserver).await?;
///
/// // Check that it is a valid homeserver.
/// client.get_supported_versions().await?;
/// # Result::<_, anyhow::Error>::Ok(()) });
/// ```
pub async fn get_supported_versions(&self) -> HttpResult<get_supported_versions::Response> {
self.send(get_supported_versions::Request::new(), Some(RequestConfig::short_retry())).await
}
/// Get the capabilities of the homeserver.
///
/// This method should be used to check what features are supported by the
@@ -371,7 +349,7 @@ impl Client {
/// # block_on(async {
/// # let client = matrix_sdk::Client::builder()
/// # .homeserver_url(homeserver)
/// # .check_supported_versions(false)
/// # .server_versions([ruma::api::MatrixVersion::V1_0])
/// # .build()
/// # .await
/// # .unwrap();
@@ -490,7 +468,7 @@ impl Client {
/// # block_on(async {
/// # let client = matrix_sdk::Client::builder()
/// # .homeserver_url(homeserver)
/// # .check_supported_versions(false)
/// # .server_versions([ruma::api::MatrixVersion::V1_0])
/// # .build()
/// # .await
/// # .unwrap();
@@ -658,15 +636,13 @@ impl Client {
.try_into_http_request::<Vec<u8>>(
homeserver.as_str(),
SendAccessToken::None,
// FIXME: Use versions reported by server
&[MatrixVersion::V1_0],
&self.inner.server_versions,
)
} else {
sso_login::v3::Request::new(redirect_url).try_into_http_request::<Vec<u8>>(
homeserver.as_str(),
SendAccessToken::None,
// FIXME: Use versions reported by server
&[MatrixVersion::V1_0],
&self.inner.server_versions,
)
};
@@ -1306,6 +1282,7 @@ impl Client {
/// client.public_rooms(limit, since, server).await;
/// # });
/// ```
#[cfg_attr(not(target_arch = "wasm32"), deny(clippy::future_not_send))]
pub async fn public_rooms(
&self,
limit: Option<u32>,
@@ -1449,7 +1426,11 @@ impl Client {
});
let request_config = self.inner.http_client.request_config.timeout(timeout);
Ok(self.inner.http_client.upload(request, Some(request_config)).await?)
Ok(self
.inner
.http_client
.upload(request, Some(request_config), self.inner.server_versions.clone())
.await?)
}
/// Send an arbitrary request to the server, without updating client state.
@@ -1501,7 +1482,7 @@ impl Client {
Request: OutgoingRequest + Debug,
HttpError: From<FromHttpResponseError<Request::EndpointError>>,
{
self.inner.http_client.send(request, config).await
self.inner.http_client.send(request, config, self.inner.server_versions.clone()).await
}
/// Get information of all our own devices.
@@ -2261,6 +2242,7 @@ pub(crate) mod test {
uiaa::{self, UiaaResponse},
},
error::{FromHttpResponseError, ServerError},
MatrixVersion,
},
assign, device_id,
directory::Filter,
@@ -2289,7 +2271,7 @@ pub(crate) mod test {
fn test_client_builder() -> ClientBuilder {
let homeserver = Url::parse(&mockito::server_url()).unwrap();
Client::builder().homeserver_url(homeserver).check_supported_versions(false)
Client::builder().homeserver_url(homeserver).server_versions([MatrixVersion::V1_0])
}
async fn no_retry_test_client() -> Client {

View File

@@ -113,6 +113,7 @@ impl HttpClient {
request: Request,
session: Arc<RwLock<Option<Session>>>,
config: Option<RequestConfig>,
server_versions: Arc<[MatrixVersion]>,
) -> Result<http::Response<Bytes>, HttpError> {
let config = match config {
Some(config) => config,
@@ -148,8 +149,7 @@ impl HttpClient {
request.try_into_http_request::<BytesMut>(
&self.homeserver.read().await.to_string(),
send_access_token,
// FIXME: Use versions reported by server
&[MatrixVersion::V1_0],
&server_versions,
)?
} else {
let (send_access_token, user_id) = {
@@ -164,8 +164,7 @@ impl HttpClient {
&self.homeserver.read().await.to_string(),
send_access_token,
&user_id,
// FIXME: Use versions reported by server
&[MatrixVersion::V1_0],
&server_versions,
)?
};
@@ -177,8 +176,10 @@ impl HttpClient {
&self,
request: create_content::v3::Request<'_>,
config: Option<RequestConfig>,
server_versions: Arc<[MatrixVersion]>,
) -> Result<create_content::v3::Response, HttpError> {
let response = self.send_request(request, self.session.clone(), config).await?;
let response =
self.send_request(request, self.session.clone(), config, server_versions).await?;
Ok(create_content::v3::Response::try_from_http_response(response)?)
}
@@ -186,12 +187,14 @@ impl HttpClient {
&self,
request: Request,
config: Option<RequestConfig>,
server_versions: Arc<[MatrixVersion]>,
) -> Result<Request::IncomingResponse, HttpError>
where
Request: OutgoingRequest + Debug,
HttpError: From<FromHttpResponseError<Request::EndpointError>>,
{
let response = self.send_request(request, self.session.clone(), config).await?;
let response =
self.send_request(request, self.session.clone(), config, server_versions).await?;
trace!("Got response: {:?}", response);