Remove ruma-client

It now lives in its own repository at
<https://github.com/ruma/ruma-client>.
This commit is contained in:
Kévin Commaille 2025-03-04 14:25:59 +01:00 committed by June Clementine Strawberry
parent 8347cc08ef
commit 0d58964877
17 changed files with 55 additions and 946 deletions

View file

@ -120,9 +120,6 @@ jobs:
- name: Check All Features
cmd: stable-all
- name: Check Client
cmd: stable-client
- name: Check Common
cmd: stable-common

View file

@ -18,19 +18,18 @@ http = "1.1.0"
js_int = "0.2.2"
maplit = "1.0.2"
rand = "0.8.5"
ruma-appservice-api = { version = "0.10.0", path = "crates/ruma-appservice-api" }
ruma-common = { version = "0.13.0", path = "crates/ruma-common" }
ruma-client = { version = "0.13.0", path = "crates/ruma-client" }
ruma-client-api = { version = "0.18.0", path = "crates/ruma-client-api" }
ruma-events = { version = "0.28.1", path = "crates/ruma-events" }
ruma-federation-api = { version = "0.9.0", path = "crates/ruma-federation-api" }
ruma-html = { version = "0.2.0", path = "crates/ruma-html" }
ruma-identifiers-validation = { version = "0.9.5", path = "crates/ruma-identifiers-validation" }
ruma-identity-service-api = { version = "0.9.0", path = "crates/ruma-identity-service-api" }
ruma-macros = { version = "=0.13.0", path = "crates/ruma-macros" }
ruma-push-gateway-api = { version = "0.9.0", path = "crates/ruma-push-gateway-api" }
ruma-signatures = { version = "0.15.0", path = "crates/ruma-signatures" }
ruma-server-util = { version = "0.3.0", path = "crates/ruma-server-util" }
ruma-appservice-api = { version = "0.12.1", path = "crates/ruma-appservice-api" }
ruma-client-api = { version = "0.20.1", path = "crates/ruma-client-api" }
ruma-common = { version = "0.15.1", path = "crates/ruma-common" }
ruma-events = { version = "0.30.1", path = "crates/ruma-events" }
ruma-federation-api = { version = "0.11.0", path = "crates/ruma-federation-api" }
ruma-html = { version = "0.4.0", path = "crates/ruma-html" }
ruma-identifiers-validation = { version = "0.10.1", path = "crates/ruma-identifiers-validation" }
ruma-identity-service-api = { version = "0.11.0", path = "crates/ruma-identity-service-api" }
ruma-macros = { version = "=0.15.1", path = "crates/ruma-macros" }
ruma-push-gateway-api = { version = "0.11.0", path = "crates/ruma-push-gateway-api" }
ruma-server-util = { version = "0.5.0", path = "crates/ruma-server-util" }
ruma-signatures = { version = "0.17.0", path = "crates/ruma-signatures" }
#ruma-state-res = { version = "0.11.0", path = "crates/ruma-state-res" }
serde = { version = "1.0.164", features = ["derive"] }
serde_html_form = "0.2.0"

View file

@ -33,6 +33,8 @@ ruma = { git = "https://github.com/ruma/ruma", branch = "main", features = ["...
them as a user. Check out the documentation [on docs.rs][docs] (or on
[docs.ruma.dev][unstable-docs] if you use use the git dependency).
You can find a low level Matrix client in the [ruma-client repository](https://github.com/ruma/ruma-client).
You can also find a small number of examples in our dedicated
[examples repository](https://github.com/ruma/examples).

View file

@ -1,2 +0,0 @@
/Cargo.lock
/target

View file

@ -1,16 +0,0 @@
# 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/)
![license: MIT](https://img.shields.io/crates/l/ruma-client.svg)
**ruma-client** is a low-level [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. If you are looking to
build a client application or a bot, you are likely going to have a better time using the Matrix
Rust SDK, which also builds on the other Ruma crates but provides a higher-level API.

View file

@ -1,22 +0,0 @@
use std::{env, process};
fn main() {
// Prevent unnecessary rerunning of this build script
println!("cargo:rerun-if-changed=build.rs");
let tls_features = [
("tls-native", env::var_os("CARGO_FEATURE_TLS_NATIVE").is_some()),
("tls-rustls-native-roots", env::var_os("CARGO_FEATURE_TLS_RUSTLS_NATIVE_ROOTS").is_some()),
("tls-rustls-webpki-roots", env::var_os("CARGO_FEATURE_TLS_RUSTLS_WEBPKI_ROOTS").is_some()),
];
if tls_features.iter().filter(|(_, a)| *a).count() > 1 {
eprintln!("error: Only one tls features can be enabled.");
for (f, a) in &tls_features {
eprintln!(" {f}: {}", if *a { "enabled" } else { "disabled" });
}
process::exit(1);
}
}

View file

@ -1,229 +0,0 @@
use std::{
sync::{Arc, Mutex},
time::Duration,
};
use assign::assign;
use async_stream::try_stream;
use futures_core::stream::Stream;
use ruma_client_api::{
account::register::{self, RegistrationKind},
session::login::{self, v3::LoginInfo},
sync::sync_events,
uiaa::UserIdentifier,
};
use ruma_common::{
api::{MatrixVersion, OutgoingRequest, SendAccessToken},
presence::PresenceState,
DeviceId, UserId,
};
use crate::{
add_user_id_to_query, send_customized_request, Error, HttpClient, ResponseError, ResponseResult,
};
mod builder;
pub use self::builder::ClientBuilder;
/// A client for the Matrix client-server API.
#[derive(Clone, Debug)]
pub struct Client<C>(Arc<ClientData<C>>);
/// Data contained in Client's Rc
#[derive(Debug)]
struct ClientData<C> {
/// The URL of the homeserver to connect to.
homeserver_url: String,
/// The underlying HTTP client.
http_client: C,
/// The access token, if logged in.
access_token: Mutex<Option<String>>,
/// The (known) Matrix versions the homeserver supports.
supported_matrix_versions: Vec<MatrixVersion>,
}
impl Client<()> {
/// Creates a new client builder.
pub fn builder() -> ClientBuilder {
ClientBuilder::new()
}
}
impl<C> Client<C> {
/// Get a copy of the current `access_token`, if any.
///
/// Useful for serializing and persisting the session to be restored later.
pub fn access_token(&self) -> Option<String> {
self.0.access_token.lock().expect("session mutex was poisoned").clone()
}
}
impl<C: HttpClient> Client<C> {
/// Makes a request to a Matrix API endpoint.
pub async fn send_request<R: OutgoingRequest>(&self, request: R) -> ResponseResult<C, R> {
self.send_customized_request(request, |_| Ok(())).await
}
/// Makes a request to a Matrix API endpoint including additional URL parameters.
pub async fn send_customized_request<R, F>(
&self,
request: R,
customize: F,
) -> ResponseResult<C, R>
where
R: OutgoingRequest,
F: FnOnce(&mut http::Request<C::RequestBody>) -> Result<(), ResponseError<C, R>>,
{
let access_token = self.access_token();
let send_access_token = match access_token.as_deref() {
Some(at) => SendAccessToken::IfRequired(at),
None => SendAccessToken::None,
};
send_customized_request(
&self.0.http_client,
&self.0.homeserver_url,
send_access_token,
&self.0.supported_matrix_versions,
request,
customize,
)
.await
}
/// Makes a request to a Matrix API endpoint as a virtual user.
///
/// This method is meant to be used by application services when interacting with the
/// client-server API.
pub async fn send_request_as<R: OutgoingRequest>(
&self,
user_id: &UserId,
request: R,
) -> ResponseResult<C, R> {
self.send_customized_request(request, add_user_id_to_query::<C, R>(user_id)).await
}
/// Log in with a username and password.
///
/// In contrast to [`send_request`][Self::send_request], this method stores the access token
/// returned by the endpoint in this client, in addition to returning it.
pub async fn log_in(
&self,
user: &str,
password: &str,
device_id: Option<&DeviceId>,
initial_device_display_name: Option<&str>,
) -> Result<login::v3::Response, Error<C::Error, ruma_client_api::Error>> {
let login_info = LoginInfo::Password(login::v3::Password::new(
UserIdentifier::UserIdOrLocalpart(user.to_owned()),
password.to_owned(),
));
let response = self
.send_request(assign!(login::v3::Request::new(login_info), {
device_id: device_id.map(ToOwned::to_owned),
initial_device_display_name: initial_device_display_name.map(ToOwned::to_owned),
}))
.await?;
*self.0.access_token.lock().unwrap() = Some(response.access_token.clone());
Ok(response)
}
/// Register as a guest.
///
/// In contrast to [`send_request`][Self::send_request], this method stores the access token
/// returned by the endpoint in this client, in addition to returning it.
pub async fn register_guest(
&self,
) -> Result<register::v3::Response, Error<C::Error, ruma_client_api::uiaa::UiaaResponse>> {
let response = self
.send_request(assign!(register::v3::Request::new(), { kind: RegistrationKind::Guest }))
.await?;
self.0.access_token.lock().unwrap().clone_from(&response.access_token);
Ok(response)
}
/// Register as a new user on this server.
///
/// In contrast to [`send_request`][Self::send_request], this method stores the access token
/// returned by the endpoint in this client, in addition to 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 async fn register_user(
&self,
username: Option<&str>,
password: &str,
) -> Result<register::v3::Response, Error<C::Error, ruma_client_api::uiaa::UiaaResponse>> {
let response = self
.send_request(assign!(register::v3::Request::new(), {
username: username.map(ToOwned::to_owned),
password: Some(password.to_owned())
}))
.await?;
self.0.access_token.lock().unwrap().clone_from(&response.access_token);
Ok(response)
}
/// Convenience method that represents repeated calls to the sync_events endpoint as a stream.
///
/// # Example:
///
/// ```no_run
/// use std::time::Duration;
///
/// # use ruma_common::presence::PresenceState;
/// # use tokio_stream::{StreamExt as _};
/// # let homeserver_url = "https://example.com".to_owned();
/// # async {
/// # let client = ruma_client::Client::builder()
/// # .homeserver_url(homeserver_url)
/// # .build::<ruma_client::http_client::Dummy>()
/// # .await?;
/// # let next_batch_token = String::new();
/// let mut sync_stream = Box::pin(client.sync(
/// None,
/// next_batch_token,
/// PresenceState::Online,
/// Some(Duration::from_secs(30)),
/// ));
/// while let Some(response) = sync_stream.try_next().await? {
/// // Do something with the data in the response...
/// }
/// # Result::<(), ruma_client::Error<_, _>>::Ok(())
/// # };
/// ```
pub fn sync(
&self,
filter: Option<sync_events::v3::Filter>,
mut since: String,
set_presence: PresenceState,
timeout: Option<Duration>,
) -> impl Stream<Item = Result<sync_events::v3::Response, Error<C::Error, ruma_client_api::Error>>>
+ '_ {
try_stream! {
loop {
let response = self
.send_request(assign!(sync_events::v3::Request::new(), {
filter: filter.clone(),
since: Some(since.clone()),
set_presence: set_presence.clone(),
timeout,
}))
.await?;
since.clone_from(&response.next_batch);
yield response;
}
}
}
}

View file

@ -1,96 +0,0 @@
use std::sync::{Arc, Mutex};
use ruma_client_api::discovery::get_supported_versions;
use ruma_common::api::{MatrixVersion, SendAccessToken};
use super::{Client, ClientData};
use crate::{DefaultConstructibleHttpClient, Error, HttpClient, HttpClientExt};
/// A [`Client`] builder.
///
/// This type can be used to construct a `Client` through a few method calls.
pub struct ClientBuilder {
homeserver_url: Option<String>,
access_token: Option<String>,
supported_matrix_versions: Option<Vec<MatrixVersion>>,
}
impl ClientBuilder {
pub(super) fn new() -> Self {
Self { homeserver_url: None, access_token: None, supported_matrix_versions: None }
}
/// Set the homeserver URL.
///
/// The homeserver URL must be set before calling [`build()`][Self::build] or
/// [`http_client()`][Self::http_client].
pub fn homeserver_url(self, url: String) -> Self {
Self { homeserver_url: Some(url), ..self }
}
/// Set the access token.
pub fn access_token(self, access_token: Option<String>) -> Self {
Self { access_token, ..self }
}
/// Set the supported Matrix versions.
///
/// This method generally *shouldn't* be called. The [`build()`][Self::build] or
/// [`http_client()`][Self::http_client] method will take care of doing a
/// [`get_supported_versions`] request to find out about the supported versions.
pub fn supported_matrix_versions(self, versions: Vec<MatrixVersion>) -> Self {
Self { supported_matrix_versions: Some(versions), ..self }
}
/// Finish building the [`Client`].
///
/// Uses [`DefaultConstructibleHttpClient::default()`] to create an HTTP client instance.
/// Unless the supported Matrix versions were manually set via
/// [`supported_matrix_versions`][Self::supported_matrix_versions], this will do a
/// [`get_supported_versions`] request to find out about the supported versions.
pub async fn build<C>(self) -> Result<Client<C>, Error<C::Error, ruma_client_api::Error>>
where
C: DefaultConstructibleHttpClient,
{
self.http_client(C::default()).await
}
/// Set the HTTP client to finish building the [`Client`].
///
/// Unless the supported Matrix versions were manually set via
/// [`supported_matrix_versions`][Self::supported_matrix_versions], this will do a
/// [`get_supported_versions`] request to find out about the supported versions.
pub async fn http_client<C>(
self,
http_client: C,
) -> Result<Client<C>, Error<C::Error, ruma_client_api::Error>>
where
C: HttpClient,
{
let homeserver_url = self
.homeserver_url
.expect("homeserver URL has to be set prior to calling .build() or .http_client()");
let supported_matrix_versions = match self.supported_matrix_versions {
Some(versions) => versions,
None => http_client
.send_matrix_request(
&homeserver_url,
SendAccessToken::None,
&[MatrixVersion::V1_0],
get_supported_versions::Request::new(),
)
.await?
.known_versions()
.into_iter()
.collect(),
};
Ok(Client(Arc::new(ClientData {
homeserver_url,
http_client,
access_token: Mutex::new(self.access_token),
supported_matrix_versions,
})))
}
}

View file

@ -1,79 +0,0 @@
//! Error conditions.
use std::fmt::{self, Debug, Display, Formatter};
use ruma_common::api::error::{FromHttpResponseError, IntoHttpError};
/// An error that can occur during client operations.
#[derive(Debug)]
#[non_exhaustive]
pub enum Error<E, F> {
/// 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(http::Error),
/// Couldn't obtain an HTTP response (e.g. due to network or DNS issues).
Response(E),
/// Converting the HTTP response to one of ruma's types failed.
FromHttpResponse(FromHttpResponseError<F>),
}
#[cfg(feature = "client-api")]
impl<E> Error<E, ruma_client_api::Error> {
/// If `self` is a server error in the `errcode` + `error` format expected
/// for client-server API endpoints, returns the error kind (`errcode`).
pub fn error_kind(&self) -> Option<&ruma_client_api::error::ErrorKind> {
use as_variant::as_variant;
use ruma_client_api::error::FromHttpResponseErrorExt as _;
as_variant!(self, Self::FromHttpResponse)?.error_kind()
}
}
impl<E: Display, F: Display> Display for Error<E, F> {
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.")
}
Self::IntoHttp(err) => write!(f, "HTTP request construction failed: {err}"),
Self::Url(err) => write!(f, "Invalid URL: {err}"),
Self::Response(err) => write!(f, "Couldn't obtain a response: {err}"),
Self::FromHttpResponse(err) => write!(f, "HTTP response conversion failed: {err}"),
}
}
}
impl<E, F> From<IntoHttpError> for Error<E, F> {
fn from(err: IntoHttpError) -> Self {
Error::IntoHttp(err)
}
}
#[doc(hidden)]
impl<E, F> From<http::uri::InvalidUri> for Error<E, F> {
fn from(err: http::uri::InvalidUri) -> Self {
Error::Url(err.into())
}
}
#[doc(hidden)]
impl<E, F> From<http::uri::InvalidUriParts> for Error<E, F> {
fn from(err: http::uri::InvalidUriParts) -> Self {
Error::Url(err.into())
}
}
impl<E, F> From<FromHttpResponseError<F>> for Error<E, F> {
fn from(err: FromHttpResponseError<F>) -> Self {
Error::FromHttpResponse(err)
}
}
impl<E: Debug + Display, F: Debug + Display> std::error::Error for Error<E, F> {}

View file

@ -1,148 +0,0 @@
//! This module contains an abstraction for HTTP clients as well as friendly-named re-exports of
//! client types that implement this trait.
use std::{future::Future, pin::Pin};
use bytes::BufMut;
use ruma_common::{
api::{MatrixVersion, OutgoingRequest, SendAccessToken},
UserId,
};
use crate::{add_user_id_to_query, ResponseError, ResponseResult};
#[cfg(feature = "hyper")]
mod hyper;
#[cfg(feature = "reqwest")]
mod reqwest;
#[cfg(feature = "hyper")]
pub use self::hyper::Hyper;
#[cfg(feature = "hyper-native-tls")]
pub use self::hyper::HyperNativeTls;
#[cfg(feature = "hyper-rustls")]
pub use self::hyper::HyperRustls;
#[cfg(feature = "reqwest")]
pub use self::reqwest::Reqwest;
/// An HTTP client that can be used to send requests to a Matrix homeserver.
pub trait HttpClient: Sync {
/// The type to use for `try_into_http_request`.
type RequestBody: Default + BufMut + Send;
/// The type to use for `try_from_http_response`.
type ResponseBody: AsRef<[u8]>;
/// The error type for the `send_request` function.
type Error: Send + Unpin;
/// Send an `http::Request` to get back an `http::Response`.
fn send_http_request(
&self,
req: http::Request<Self::RequestBody>,
) -> impl Future<Output = Result<http::Response<Self::ResponseBody>, Self::Error>> + Send;
}
/// An HTTP client that has a default configuration.
pub trait DefaultConstructibleHttpClient: HttpClient {
/// Creates a new HTTP client with default configuration.
fn default() -> Self;
}
/// Convenience functionality on top of `HttpClient`.
///
/// If you want to build your own matrix client type instead of using `ruma_client::Client`, this
/// trait should make that relatively easy.
pub trait HttpClientExt: HttpClient {
/// Send a strongly-typed matrix request to get back a strongly-typed response.
// TODO: `R: 'a` bound should not be needed
fn send_matrix_request<'a, R: OutgoingRequest + 'a>(
&'a self,
homeserver_url: &str,
access_token: SendAccessToken<'_>,
for_versions: &[MatrixVersion],
request: R,
) -> Pin<Box<dyn Future<Output = ResponseResult<Self, R>> + 'a + Send>> {
self.send_customized_matrix_request(
homeserver_url,
access_token,
for_versions,
request,
|_| Ok(()),
)
}
/// Turn a strongly-typed matrix request into an `http::Request`, customize it and send it to
/// get back a strongly-typed response.
// TODO: `R: 'a` and `F: 'a` should not be needed
fn send_customized_matrix_request<'a, R, F>(
&'a self,
homeserver_url: &str,
access_token: SendAccessToken<'_>,
for_versions: &[MatrixVersion],
request: R,
customize: F,
) -> Pin<Box<dyn Future<Output = ResponseResult<Self, R>> + 'a + Send>>
where
R: OutgoingRequest + 'a,
F: FnOnce(&mut http::Request<Self::RequestBody>) -> Result<(), ResponseError<Self, R>> + 'a,
{
Box::pin(crate::send_customized_request(
self,
homeserver_url,
access_token,
for_versions,
request,
customize,
))
}
/// Turn a strongly-typed matrix request into an `http::Request`, add a `user_id` query
/// parameter to it and send it to get back a strongly-typed response.
///
/// This method is meant to be used by application services when interacting with the
/// client-server API.
fn send_matrix_request_as<'a, R: OutgoingRequest + 'a>(
&'a self,
homeserver_url: &str,
access_token: SendAccessToken<'_>,
for_versions: &[MatrixVersion],
user_id: &'a UserId,
request: R,
) -> Pin<Box<dyn Future<Output = ResponseResult<Self, R>> + 'a>> {
self.send_customized_matrix_request(
homeserver_url,
access_token,
for_versions,
request,
add_user_id_to_query::<Self, R>(user_id),
)
}
}
impl<T: HttpClient> HttpClientExt for T {}
#[doc(hidden)]
#[derive(Debug)]
#[allow(clippy::exhaustive_structs)]
pub struct Dummy;
impl HttpClient for Dummy {
type RequestBody = Vec<u8>;
type ResponseBody = Vec<u8>;
type Error = ();
#[allow(clippy::diverging_sub_expression)]
async fn send_http_request(
&self,
_req: http::Request<Self::RequestBody>,
) -> Result<http::Response<Self::ResponseBody>, Self::Error> {
unimplemented!("this client only exists to allow doctests to compile")
}
}
impl DefaultConstructibleHttpClient for Dummy {
fn default() -> Self {
Dummy
}
}

View file

@ -1,62 +0,0 @@
use bytes::{Bytes, BytesMut};
use http_body_util::{BodyExt as _, Full};
use hyper_util::{
client::legacy::connect::{Connect, HttpConnector},
rt::TokioExecutor,
};
use super::{DefaultConstructibleHttpClient, HttpClient};
/// A hyper HTTP client.
///
/// The default connector is rarely useful, since it doesn't support `https`.
pub type Hyper<C = HttpConnector> = hyper_util::client::legacy::Client<C, Full<Bytes>>;
/// A hyper HTTP client using native-tls for TLS support.
#[cfg(feature = "hyper-native-tls")]
pub type HyperNativeTls = Hyper<hyper_tls::HttpsConnector<HttpConnector>>;
/// A hyper HTTP client using rustls for TLS support.
///
/// This client does not implement `DefaultConstructibleHttpClient`.
/// To use it, you need to manually create an instance.
#[cfg(feature = "hyper-rustls")]
pub type HyperRustls = Hyper<hyper_rustls::HttpsConnector<HttpConnector>>;
impl<C> HttpClient for Hyper<C>
where
C: Connect + Clone + Send + Sync + 'static,
{
type RequestBody = BytesMut;
type ResponseBody = Bytes;
type Error = Box<dyn std::error::Error + Send + Sync>;
async fn send_http_request(
&self,
req: http::Request<BytesMut>,
) -> Result<http::Response<Bytes>, Self::Error> {
let (head, body) =
self.request(req.map(|body| Full::new(body.freeze()))).await?.into_parts();
// FIXME: Use aggregate instead of to_bytes once serde_json can parse from a reader at a
// comparable speed as reading from a slice: https://github.com/serde-rs/json/issues/160
let body = body.collect().await?.to_bytes();
Ok(http::Response::from_parts(head, body))
}
}
#[cfg(feature = "hyper")]
impl DefaultConstructibleHttpClient for Hyper {
fn default() -> Self {
hyper_util::client::legacy::Client::builder(TokioExecutor::new())
.build(HttpConnector::new())
}
}
#[cfg(feature = "hyper-native-tls")]
impl DefaultConstructibleHttpClient for HyperNativeTls {
fn default() -> Self {
hyper_util::client::legacy::Client::builder(TokioExecutor::new())
.build(hyper_tls::HttpsConnector::new())
}
}

View file

@ -1,37 +0,0 @@
use std::mem;
use bytes::{Bytes, BytesMut};
use super::{DefaultConstructibleHttpClient, HttpClient};
/// The `reqwest` crate's `Client`.
pub type Reqwest = reqwest::Client;
impl HttpClient for Reqwest {
type RequestBody = BytesMut;
type ResponseBody = Bytes;
type Error = reqwest::Error;
async fn send_http_request(
&self,
req: http::Request<BytesMut>,
) -> Result<http::Response<Bytes>, reqwest::Error> {
let req = req.map(|body| body.freeze()).try_into()?;
let mut res = self.execute(req).await?;
let mut http_builder =
http::Response::builder().status(res.status()).version(res.version());
mem::swap(
http_builder.headers_mut().expect("http::response::Builder to be usable"),
res.headers_mut(),
);
Ok(http_builder.body(res.bytes().await?).expect("http::Response construction to work"))
}
}
impl DefaultConstructibleHttpClient for Reqwest {
fn default() -> Self {
reqwest::Client::new()
}
}

View file

@ -1,197 +0,0 @@
#![doc(html_favicon_url = "https://ruma.dev/favicon.ico")]
#![doc(html_logo_url = "https://ruma.dev/images/logo.png")]
//! A minimal [Matrix](https://matrix.org/) client library.
//!
//! # Usage
//!
//! Begin by creating a `Client`, selecting one of the type aliases from `ruma_client::http_client`
//! for the generic parameter. For the client API, there are login and registration methods
//! provided for the client (feature `client-api`):
//!
//! ```ignore
//! # // HACK: "ignore" the doctest here because client.log_in needs client-api feature.
//! // type HttpClient = ruma_client::http_client::_;
//! # type HttpClient = ruma_client::http_client::Dummy;
//! # let work = async {
//! let homeserver_url = "https://example.com".to_owned();
//! let client = ruma::Client::builder()
//! .homeserver_url(homeserver_url)
//! .build::<ruma_client::http_client::Dummy>()
//! .await?;
//!
//! let session = client
//! .log_in("@alice:example.com", "secret", None, 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!
//! # Result::<(), ruma_client::Error<_, _>>::Ok(())
//! # };
//! ```
//!
//! You can also pass an existing access token to the `Client` constructor to restore a previous
//! session 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
//! # #[cfg(feature = "client-api")]
//! # async {
//! # type HttpClient = ruma_client::http_client::Dummy;
//! let homeserver_url = "https://example.com".to_owned();
//! let client = ruma_client::Client::builder()
//! .homeserver_url(homeserver_url)
//! .access_token(Some("as_access_token".into()))
//! .build::<HttpClient>()
//! .await?;
//!
//! // make calls to the API
//! # Result::<(), ruma_client::Error<_, _>>::Ok(())
//! # };
//! ```
//!
//! 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 `request` method. You can pass it any of the `Request` types found in
//! `ruma::api::*` and get back a corresponding response from the homeserver.
//!
//! For example:
//!
//! ```no_run
//! # #[cfg(feature = "client-api")]
//! # async {
//! # let homeserver_url = "https://example.com".to_owned();
//! # let client = ruma_client::Client::builder()
//! # .homeserver_url(homeserver_url)
//! # .build::<ruma_client::http_client::Dummy>()
//! # .await?;
//!
//! use ruma_client_api::alias::get_alias;
//! use ruma_common::{api::MatrixVersion, owned_room_alias_id, room_id};
//!
//! let alias = owned_room_alias_id!("#example_room:example.com");
//! let response = client.send_request(get_alias::v3::Request::new(alias)).await?;
//!
//! assert_eq!(response.room_id, room_id!("!n8f893n9:example.com"));
//! # Result::<(), ruma_client::Error<_, _>>::Ok(())
//! # };
//! ```
//!
//! # Crate features
//!
//! The following features activate http client types in the [`http_client`] module:
//!
//! * `hyper`
//! * `hyper-native-tls`
//! * `hyper-rustls`
//! * `reqwest` if you use the `reqwest` library already, activate this feature and configure the
//! TLS backend on `reqwest` directly. If you want to use `reqwest` but don't depend on it
//! already, use one of the sub-features instead. For details on the meaning of these, see
//! [reqwest's documentation](https://docs.rs/reqwest/0.11/reqwest/#optional-features):
//! * `reqwest-native-tls`
//! * `reqwest-native-tls-alpn`
//! * `reqwest-native-tls-vendored`
//! * `reqwest-rustls-manual-roots`
//! * `reqwest-rustls-webpki-roots`
//! * `reqwest-rustls-native-roots`
#![warn(missing_docs)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
use std::{any::type_name, future::Future};
use ruma_common::{
api::{MatrixVersion, OutgoingRequest, SendAccessToken},
UserId,
};
use tracing::{info_span, Instrument};
#[cfg(feature = "client-api")]
mod client;
mod error;
pub mod http_client;
#[cfg(feature = "client-api")]
pub use self::client::{Client, ClientBuilder};
pub use self::{
error::Error,
http_client::{DefaultConstructibleHttpClient, HttpClient, HttpClientExt},
};
/// The error type for sending the request `R` with the http client `C`.
pub type ResponseError<C, R> =
Error<<C as HttpClient>::Error, <R as OutgoingRequest>::EndpointError>;
/// The result of sending the request `R` with the http client `C`.
pub type ResponseResult<C, R> =
Result<<R as OutgoingRequest>::IncomingResponse, ResponseError<C, R>>;
fn send_customized_request<'a, C, R, F>(
http_client: &'a C,
homeserver_url: &str,
send_access_token: SendAccessToken<'_>,
for_versions: &[MatrixVersion],
request: R,
customize: F,
) -> impl Future<Output = ResponseResult<C, R>> + Send + 'a
where
C: HttpClient + ?Sized,
R: OutgoingRequest,
F: FnOnce(&mut http::Request<C::RequestBody>) -> Result<(), ResponseError<C, R>>,
{
let http_req =
info_span!("serialize_request", request_type = type_name::<R>()).in_scope(move || {
request
.try_into_http_request(homeserver_url, send_access_token, for_versions)
.map_err(ResponseError::<C, R>::from)
.and_then(|mut req| {
customize(&mut req)?;
Ok(req)
})
});
let send_span = info_span!(
"send_request",
request_type = type_name::<R>(),
http_client = type_name::<C>(),
homeserver_url,
);
async move {
let http_res = http_client
.send_http_request(http_req?)
.instrument(send_span)
.await
.map_err(Error::Response)?;
let res =
info_span!("deserialize_response", response_type = type_name::<R::IncomingResponse>())
.in_scope(move || {
ruma_common::api::IncomingResponse::try_from_http_response(http_res)
})?;
Ok(res)
}
}
fn add_user_id_to_query<C: HttpClient + ?Sized, R: OutgoingRequest>(
user_id: &UserId,
) -> impl FnOnce(&mut http::Request<C::RequestBody>) -> Result<(), ResponseError<C, R>> + '_ {
use assign::assign;
use http::uri::Uri;
move |http_request| {
let extra_params = serde_html_form::to_string([("user_id", user_id)]).unwrap();
let uri = http_request.uri_mut();
let new_path_and_query = match uri.query() {
Some(params) => format!("{}?{params}&{extra_params}", uri.path()),
None => format!("{}?{extra_params}", uri.path()),
};
*uri = Uri::from_parts(assign!(uri.clone().into_parts(), {
path_and_query: Some(new_path_and_query.parse()?),
}))?;
Ok(())
}
}

View file

@ -1,5 +1,46 @@
# [unreleased]
- The deprecated global `compat` cargo feature was removed. The `compat-*` cargo
features need to be enabled individually.
- The `unstable-unspecified` cargo feature was removed.
- ruma-client is not reexported by ruma anymore, it lives as its own separate
crate. All the corresponding features were removed.
- Bump MSRV to 1.81
# 0.12.1
Please refer to the changelogs of:
- ruma-common 0.15.1
- ruma-events 0.30.1
- ruma-client-api 0.20.1
- ruma-appservice-api 0.12.1
# 0.12.0
- The `unstable-exhaustive-types` cargo feature was replaced by the
`ruma_unstable_exhaustive_types` compile-time `cfg` setting. Like all `cfg`
settings, it can be enabled at compile-time with the `RUSTFLAGS` environment
variable, or inside `.cargo/config.toml`. It can also be enabled by setting
the `RUMA_UNSTABLE_EXHAUSTIVE_TYPES` environment variable.
Please refer to the changelogs of:
- ruma-common 0.15.0
- ruma-events 0.30.0
- ruma-client-api 0.20.0
- ruma-push-gateway-api 0.11.0
- ruma-state-res 0.13.0
# 0.11.1
Please refer to the changelogs of:
* ruma-common 0.14.1
* ruma-events 0.29.1
# 0.11.0
- The `compat-key-id` cargo feature was renamed to
`compat-server-signing-key-version`.

View file

@ -17,24 +17,11 @@ all-features = true
[features]
api = ["ruma-common/api"]
canonical-json = ["ruma-common/canonical-json", "ruma-events?/canonical-json"]
client = ["dep:ruma-client"]
events = ["dep:ruma-events"]
server-util = ["dep:ruma-server-util"]
signatures = ["dep:ruma-signatures", "canonical-json"]
#state-res = ["dep:ruma-state-res"]
# ruma-client feature flags
client-ext-client-api = ["client", "ruma-client?/client-api"]
client-hyper = ["client", "ruma-client?/hyper"]
client-hyper-native-tls = ["client", "ruma-client?/hyper-native-tls"]
client-reqwest = ["client", "ruma-client?/reqwest"]
client-reqwest-native-tls = ["client", "ruma-client?/reqwest-native-tls"]
client-reqwest-native-tls-alpn = ["client", "ruma-client?/reqwest-native-tls-alpn"]
client-reqwest-native-tls-vendored = ["client", "ruma-client?/reqwest-native-tls-vendored"]
client-reqwest-rustls-manual-roots = ["client", "ruma-client?/reqwest-rustls-manual-roots"]
client-reqwest-rustls-webpki-roots = ["client", "ruma-client?/reqwest-rustls-webpki-roots"]
client-reqwest-rustls-native-roots = ["client", "ruma-client?/reqwest-rustls-native-roots"]
appservice-api-c = [
"api",
"events",
@ -115,8 +102,6 @@ html-matrix = ["html", "ruma-html/matrix"]
# Everything except compat, js and unstable features
full = [
"api",
"client",
"client-ext-client-api",
"events",
"signatures",
#"state-res",
@ -339,7 +324,6 @@ web-time = { workspace = true }
ruma-common = { workspace = true }
ruma-client = { workspace = true, optional = true }
ruma-events = { workspace = true, optional = true }
ruma-html = { workspace = true, optional = true }
ruma-server-util = { workspace = true, optional = true }

View file

@ -64,16 +64,6 @@
//! * `events`
//! * `signatures`
//!
//! # `ruma-client` features
//!
//! The `client` feature activates [`ruma::client`][client], and `client-ext-client-api` activates
//! `ruma-client`s `client-api` feature. All other `client-*` features activate the same feature
//! without the `client-` prefix on `ruma-client`. See the crate's documentation for the effect of
//! these features.
//!
//! If you are viewing this on `docs.rs`, you can have a look at the feature dependencies by
//! clicking **Feature flags** in the toolbar at the top.
//!
//! # Compile-time `cfg` settings
//!
//! These settings are accepted at compile time to configure the generated code. They can be set as
@ -90,9 +80,6 @@
#![warn(missing_docs)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#[cfg(feature = "client")]
#[doc(inline)]
pub use ruma_client as client;
#[cfg(feature = "events")]
#[doc(inline)]
pub use ruma_events as events;
@ -147,7 +134,5 @@ pub use js_int::{
};
#[doc(no_inline)]
pub use js_option::JsOption;
#[cfg(feature = "client-ext-client-api")]
pub use ruma_client::Client;
pub use ruma_common::*;
pub use web_time as time;

View file

@ -40,8 +40,6 @@ pub enum CiCmd {
Stable,
/// Check all crates with all features (stable)
StableAll,
/// Check ruma-client without default features (stable)
StableClient,
/// Check ruma-common with only the required features (stable)
StableCommon,
/// Run all tests with almost all features (stable)
@ -112,7 +110,6 @@ impl CiTask {
Some(CiCmd::MsrvOwnedIdArc) => self.msrv_owned_id_arc()?,
Some(CiCmd::Stable) => self.stable()?,
Some(CiCmd::StableAll) => self.stable_all()?,
Some(CiCmd::StableClient) => self.stable_client()?,
Some(CiCmd::StableCommon) => self.stable_common()?,
Some(CiCmd::TestAll) => self.test_all()?,
Some(CiCmd::TestCompat) => self.test_compat()?,
@ -175,7 +172,6 @@ impl CiTask {
/// Run all the tasks that use the stable version.
fn stable(&self) -> Result<()> {
self.stable_all()?;
self.stable_client()?;
self.stable_common()?;
self.test_all()?;
self.test_doc()?;
@ -195,13 +191,6 @@ impl CiTask {
.map_err(Into::into)
}
/// Check ruma-client without default features with the stable version.
fn stable_client(&self) -> Result<()> {
cmd!(&self.sh, "rustup run stable cargo check -p ruma-client --no-default-features")
.run()
.map_err(Into::into)
}
/// Check ruma-common with onjy the required features with the stable version.
fn stable_common(&self) -> Result<()> {
cmd!(