client: Add send_request_as for application services

This commit is contained in:
Jonas Platte 2021-04-28 14:44:36 +02:00
parent 20dfd7c328
commit cee6e2e365
No known key found for this signature in database
GPG Key ID: CC154DE0E30B7C67
2 changed files with 63 additions and 1 deletions

View File

@ -6,8 +6,9 @@ use std::{future::Future, pin::Pin};
use async_trait::async_trait; use async_trait::async_trait;
use bytes::BufMut; use bytes::BufMut;
use ruma_api::{OutgoingRequest, SendAccessToken}; use ruma_api::{OutgoingRequest, SendAccessToken};
use ruma_identifiers::UserId;
use crate::{ResponseError, ResponseResult}; use crate::{add_user_id_to_query, ResponseError, ResponseResult};
#[cfg(feature = "hyper")] #[cfg(feature = "hyper")]
mod hyper; mod hyper;
@ -90,6 +91,29 @@ pub trait HttpClientExt: HttpClient {
customize, 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_request_as<'a, R: OutgoingRequest + 'a>(
&'a self,
homeserver_url: &str,
access_token: SendAccessToken<'_>,
user_id: &'a UserId,
request: R,
) -> Pin<Box<dyn Future<Output = ResponseResult<Self, R>> + 'a>>
where
<R as OutgoingRequest>::EndpointError: Send,
{
self.send_customized_request(
homeserver_url,
access_token,
request,
add_user_id_to_query::<Self, R>(user_id),
)
}
} }
#[async_trait] #[async_trait]

View File

@ -79,6 +79,7 @@ use std::{
}; };
use ruma_api::{OutgoingRequest, SendAccessToken}; use ruma_api::{OutgoingRequest, SendAccessToken};
use ruma_identifiers::UserId;
// "Undo" rename from `Cargo.toml` that only serves to make `hyper-rustls` available as a Cargo // "Undo" rename from `Cargo.toml` that only serves to make `hyper-rustls` available as a Cargo
// feature name. // feature name.
@ -190,6 +191,21 @@ impl<C: HttpClient> Client<C> {
) )
.await .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>
where
<R as OutgoingRequest>::EndpointError: Send,
{
self.send_customized_request(request, add_user_id_to_query::<C, R>(user_id)).await
}
} }
fn send_customized_request<'a, C, R, F>( fn send_customized_request<'a, C, R, F>(
@ -218,3 +234,25 @@ where
Ok(ruma_api::IncomingResponse::try_from_http_response(http_res)?) Ok(ruma_api::IncomingResponse::try_from_http_response(http_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;
use ruma_serde::urlencoded;
move |http_request| {
let extra_params = urlencoded::to_string(&[("user_id", user_id)]).unwrap();
let uri = http_request.uri_mut();
let new_path_and_query = match uri.query() {
Some(params) => format!("{}?{}&{}", uri.path(), params, extra_params),
None => format!("{}?{}", uri.path(), extra_params),
};
*uri = Uri::from_parts(assign!(uri.clone().into_parts(), {
path_and_query: Some(new_path_and_query.parse()?),
}))?;
Ok(())
}
}