Skip to content

Commit 8acf4eb

Browse files
committed
Refactor Client to support AppserviceUserIdentity
1 parent 1caeac2 commit 8acf4eb

4 files changed

Lines changed: 149 additions & 93 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ Breaking changes:
88
compatible with all requests from ruma-client-api and ruma-appservice-api.
99
- `HttpRequest::RequestBuilder` has an extra `AsRef<[u8]>` bound.
1010
- Bump MSRV to 1.88
11+
- `Client::send_request_as()` now takes `AppserviceUserIdentity` instead of `&UserId`.
1112

1213
Improvements:
1314

src/client.rs

Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,9 @@ use assign::assign;
88
use async_stream::try_stream;
99
use futures_core::stream::Stream;
1010
use ruma::{
11-
DeviceId, UserId,
11+
DeviceId,
1212
api::{
13-
OutgoingRequest, SupportedVersions,
13+
AppserviceUserIdentity, OutgoingRequest, OutgoingRequestAppserviceExt, SupportedVersions,
1414
auth_scheme::{AuthScheme, SendAccessToken},
1515
client::{
1616
account::register::{self, RegistrationKind},
@@ -24,7 +24,8 @@ use ruma::{
2424
};
2525

2626
use crate::{
27-
Error, HttpClient, ResponseError, ResponseResult, add_user_id_to_query, send_customized_request,
27+
Error, HttpClient, ResponseError, ResponseResult, send_customized_request, send_request,
28+
send_request_as,
2829
};
2930

3031
mod builder;
@@ -83,6 +84,18 @@ impl<C> Client<C> {
8384
pub fn access_token(&self) -> Option<String> {
8485
self.0.access_token.lock().expect("session mutex was poisoned").clone()
8586
}
87+
88+
/// Get the `SendAccessToken` according to the client's `TokenMode`.
89+
fn send_access_token<'a>(&self, access_token: &'a Option<String>) -> SendAccessToken<'a> {
90+
let token_mode = self.0.token_mode;
91+
92+
match (token_mode, access_token.as_deref()) {
93+
(TokenMode::AppService, Some(at)) => SendAccessToken::Appservice(at),
94+
(TokenMode::SendIfRequired, Some(at)) => SendAccessToken::IfRequired(at),
95+
(TokenMode::SendAlways, Some(at)) => SendAccessToken::Always(at),
96+
(_, None) => SendAccessToken::None,
97+
}
98+
}
8699
}
87100

88101
impl<C: HttpClient> Client<C> {
@@ -93,7 +106,16 @@ impl<C: HttpClient> Client<C> {
93106
for<'a> R::Authentication: AuthScheme<Input<'a> = SendAccessToken<'a>>,
94107
R::PathBuilder: SupportedPathBuilder,
95108
{
96-
self.send_customized_request(request, |_| Ok(())).await
109+
let access_token = self.access_token();
110+
111+
send_request(
112+
&self.0.http_client,
113+
&self.0.homeserver_url,
114+
self.send_access_token(&access_token),
115+
R::PathBuilder::get_path_builder_input(self),
116+
request,
117+
)
118+
.await
97119
}
98120

99121
/// Makes a request to a Matrix API endpoint including additional URL parameters.
@@ -108,20 +130,12 @@ impl<C: HttpClient> Client<C> {
108130
R::PathBuilder: SupportedPathBuilder,
109131
F: FnOnce(&mut http::Request<C::RequestBody>) -> Result<(), ResponseError<C, R>>,
110132
{
111-
let token_mode = self.0.token_mode;
112133
let access_token = self.access_token();
113134

114-
let send_access_token = match (token_mode, access_token.as_deref()) {
115-
(TokenMode::AppService, Some(at)) => SendAccessToken::Appservice(at),
116-
(TokenMode::SendIfRequired, Some(at)) => SendAccessToken::IfRequired(at),
117-
(TokenMode::SendAlways, Some(at)) => SendAccessToken::Always(at),
118-
(_, None) => SendAccessToken::None,
119-
};
120-
121135
send_customized_request(
122136
&self.0.http_client,
123137
&self.0.homeserver_url,
124-
send_access_token,
138+
self.send_access_token(&access_token),
125139
R::PathBuilder::get_path_builder_input(self),
126140
request,
127141
customize,
@@ -133,13 +147,27 @@ impl<C: HttpClient> Client<C> {
133147
///
134148
/// This method is meant to be used by application services when interacting with the
135149
/// client-server API.
136-
pub async fn send_request_as<R>(&self, user_id: &UserId, request: R) -> ResponseResult<C, R>
150+
pub async fn send_request_as<R>(
151+
&self,
152+
identity: AppserviceUserIdentity<'_>,
153+
request: R,
154+
) -> ResponseResult<C, R>
137155
where
138-
R: OutgoingRequest,
156+
R: OutgoingRequestAppserviceExt,
139157
for<'a> R::Authentication: AuthScheme<Input<'a> = SendAccessToken<'a>>,
140158
R::PathBuilder: SupportedPathBuilder,
141159
{
142-
self.send_customized_request(request, add_user_id_to_query::<C, R>(user_id)).await
160+
let access_token = self.access_token();
161+
162+
send_request_as(
163+
&self.0.http_client,
164+
&self.0.homeserver_url,
165+
self.send_access_token(&access_token),
166+
identity,
167+
R::PathBuilder::get_path_builder_input(self),
168+
request,
169+
)
170+
.await
143171
}
144172

145173
/// Log in with a username and password.

src/http_client.rs

Lines changed: 21 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,13 @@
44
use std::{future::Future, pin::Pin};
55

66
use bytes::BufMut;
7-
use ruma::{
8-
UserId,
9-
api::{
10-
OutgoingRequest,
11-
auth_scheme::{AuthScheme, SendAccessToken},
12-
path_builder::PathBuilder,
13-
},
7+
use ruma::api::{
8+
AppserviceUserIdentity, OutgoingRequest,
9+
auth_scheme::{AuthScheme, SendAccessToken},
10+
path_builder::PathBuilder,
1411
};
1512

16-
use crate::{ResponseError, ResponseResult, add_user_id_to_query};
13+
use crate::{ResponseError, ResponseResult};
1714

1815
#[cfg(feature = "hyper")]
1916
mod hyper;
@@ -59,25 +56,18 @@ pub trait DefaultConstructibleHttpClient: HttpClient {
5956
/// trait should make that relatively easy.
6057
pub trait HttpClientExt: HttpClient {
6158
/// Send a strongly-typed matrix request to get back a strongly-typed response.
62-
// TODO: `R: 'a` bound should not be needed
6359
fn send_matrix_request<'a, R>(
6460
&'a self,
6561
homeserver_url: &str,
66-
access_token: SendAccessToken<'a>,
67-
path_builder_input: <R::PathBuilder as PathBuilder>::Input<'_>,
62+
access_token: SendAccessToken<'_>,
63+
for_versions: <R::PathBuilder as PathBuilder>::Input<'_>,
6864
request: R,
6965
) -> Pin<Box<dyn Future<Output = ResponseResult<Self, R>> + 'a + Send>>
7066
where
7167
R: OutgoingRequest,
72-
R::Authentication: AuthScheme<Input<'a> = SendAccessToken<'a>>,
68+
for<'b> R::Authentication: AuthScheme<Input<'b> = SendAccessToken<'b>>,
7369
{
74-
self.send_customized_matrix_request(
75-
homeserver_url,
76-
access_token,
77-
path_builder_input,
78-
request,
79-
|_| Ok(()),
80-
)
70+
Box::pin(crate::send_request(self, homeserver_url, access_token, for_versions, request))
8171
}
8272

8373
/// Turn a strongly-typed matrix request into an `http::Request`, customize it and send it to
@@ -106,30 +96,31 @@ pub trait HttpClientExt: HttpClient {
10696
))
10797
}
10898

109-
/// Turn a strongly-typed matrix request into an `http::Request`, add a `user_id` query
110-
/// parameter to it and send it to get back a strongly-typed response.
99+
/// Turn a strongly-typed matrix request into an `http::Request`, add `user_id` and/or
100+
/// `device_id` query parameters to it and send it to get back a strongly-typed response.
111101
///
112102
/// This method is meant to be used by application services when interacting with the
113103
/// client-server API.
114104
fn send_matrix_request_as<'a, R>(
115105
&'a self,
116106
homeserver_url: &str,
117-
access_token: SendAccessToken<'a>,
118-
path_builder_input: <R::PathBuilder as PathBuilder>::Input<'_>,
119-
user_id: &'a UserId,
107+
access_token: SendAccessToken<'_>,
108+
identity: AppserviceUserIdentity<'_>,
109+
for_versions: <R::PathBuilder as PathBuilder>::Input<'_>,
120110
request: R,
121-
) -> Pin<Box<dyn Future<Output = ResponseResult<Self, R>> + 'a>>
111+
) -> Pin<Box<dyn Future<Output = ResponseResult<Self, R>> + 'a + Send>>
122112
where
123113
R: OutgoingRequest,
124-
R::Authentication: AuthScheme<Input<'a> = SendAccessToken<'a>>,
114+
for<'b> R::Authentication: AuthScheme<Input<'b> = SendAccessToken<'b>>,
125115
{
126-
self.send_customized_matrix_request(
116+
Box::pin(crate::send_request_as(
117+
self,
127118
homeserver_url,
128119
access_token,
129-
path_builder_input,
120+
identity,
121+
for_versions,
130122
request,
131-
add_user_id_to_query::<Self, R>(user_id),
132-
)
123+
))
133124
}
134125
}
135126

src/lib.rs

Lines changed: 83 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
//! # .await?;
6565
//!
6666
//! use ruma::{
67-
//! api::{MatrixVersion, client::alias::get_alias},
67+
//! api::{client::alias::get_alias, MatrixVersion},
6868
//! owned_room_alias_id, room_id,
6969
//! };
7070
//!
@@ -101,13 +101,10 @@ use std::{any::type_name, future::Future};
101101

102102
#[doc(no_inline)]
103103
pub use ruma;
104-
use ruma::{
105-
UserId,
106-
api::{
107-
OutgoingRequest,
108-
auth_scheme::{AuthScheme, SendAccessToken},
109-
path_builder::PathBuilder,
110-
},
104+
use ruma::api::{
105+
AppserviceUserIdentity, OutgoingRequest, OutgoingRequestAppserviceExt,
106+
auth_scheme::{AuthScheme, SendAccessToken},
107+
path_builder::PathBuilder,
111108
};
112109
use tracing::{Instrument, info_span};
113110

@@ -117,7 +114,7 @@ mod error;
117114
pub mod http_client;
118115

119116
#[cfg(feature = "client-api")]
120-
pub use self::client::{Client, ClientBuilder, SupportedPathBuilder, TokenMode};
117+
pub use self::client::{Client, ClientBuilder, TokenMode};
121118
pub use self::{
122119
error::Error,
123120
http_client::{DefaultConstructibleHttpClient, HttpClient, HttpClientExt},
@@ -131,31 +128,15 @@ pub type ResponseError<C, R> =
131128
pub type ResponseResult<C, R> =
132129
Result<<R as OutgoingRequest>::IncomingResponse, ResponseError<C, R>>;
133130

134-
fn send_customized_request<'a, C, R, F>(
131+
fn send_prepared_request<'a, C, R>(
135132
http_client: &'a C,
136133
homeserver_url: &str,
137-
send_access_token: SendAccessToken<'a>,
138-
path_builder_input: <R::PathBuilder as PathBuilder>::Input<'_>,
139-
request: R,
140-
customize: F,
141-
) -> impl Future<Output = ResponseResult<C, R>> + Send + 'a + use<'a, C, R, F>
134+
http_req: Result<http::Request<C::RequestBody>, ResponseError<C, R>>,
135+
) -> impl Future<Output = ResponseResult<C, R>> + Send + 'a + use<'a, C, R>
142136
where
143137
C: HttpClient + ?Sized,
144138
R: OutgoingRequest,
145-
R::Authentication: AuthScheme<Input<'a> = SendAccessToken<'a>>,
146-
F: FnOnce(&mut http::Request<C::RequestBody>) -> Result<(), ResponseError<C, R>>,
147139
{
148-
let http_req =
149-
info_span!("serialize_request", request_type = type_name::<R>()).in_scope(move || {
150-
request
151-
.try_into_http_request(homeserver_url, send_access_token, path_builder_input)
152-
.map_err(ResponseError::<C, R>::from)
153-
.and_then(|mut req| {
154-
customize(&mut req)?;
155-
Ok(req)
156-
})
157-
});
158-
159140
let send_span = info_span!(
160141
"send_request",
161142
request_type = type_name::<R>(),
@@ -178,23 +159,78 @@ where
178159
}
179160
}
180161

181-
fn add_user_id_to_query<C: HttpClient + ?Sized, R: OutgoingRequest>(
182-
user_id: &UserId,
183-
) -> impl FnOnce(&mut http::Request<C::RequestBody>) -> Result<(), ResponseError<C, R>> + '_ {
184-
use assign::assign;
185-
use http::uri::Uri;
186-
187-
move |http_request| {
188-
let extra_params = serde_html_form::to_string([("user_id", user_id)]).unwrap();
189-
let uri = http_request.uri_mut();
190-
let new_path_and_query = match uri.query() {
191-
Some(params) => format!("{}?{params}&{extra_params}", uri.path()),
192-
None => format!("{}?{extra_params}", uri.path()),
193-
};
194-
*uri = Uri::from_parts(assign!(uri.clone().into_parts(), {
195-
path_and_query: Some(new_path_and_query.parse()?),
196-
}))?;
197-
198-
Ok(())
199-
}
162+
fn send_request<'a, C, R>(
163+
http_client: &'a C,
164+
homeserver_url: &str,
165+
authentication_input: <R::Authentication as AuthScheme>::Input<'_>,
166+
path_builder_input: <R::PathBuilder as PathBuilder>::Input<'_>,
167+
request: R,
168+
) -> impl Future<Output = ResponseResult<C, R>> + Send + 'a + use<'a, C, R>
169+
where
170+
C: HttpClient + ?Sized,
171+
R: OutgoingRequest,
172+
{
173+
let http_req =
174+
info_span!("serialize_request", request_type = type_name::<R>()).in_scope(move || {
175+
request
176+
.try_into_http_request(homeserver_url, authentication_input, path_builder_input)
177+
.map_err(ResponseError::<C, R>::from)
178+
});
179+
180+
send_prepared_request::<C, R>(http_client, homeserver_url, http_req)
181+
}
182+
183+
fn send_request_as<'a, C, R>(
184+
http_client: &'a C,
185+
homeserver_url: &str,
186+
authentication_input: <R::Authentication as AuthScheme>::Input<'_>,
187+
identity: AppserviceUserIdentity<'_>,
188+
path_builder_input: <R::PathBuilder as PathBuilder>::Input<'_>,
189+
request: R,
190+
) -> impl Future<Output = ResponseResult<C, R>> + Send + 'a + use<'a, C, R>
191+
where
192+
C: HttpClient + ?Sized,
193+
R: OutgoingRequestAppserviceExt,
194+
for<'b> R::Authentication: AuthScheme<Input<'b> = SendAccessToken<'b>>,
195+
{
196+
let http_req =
197+
info_span!("serialize_request", request_type = type_name::<R>()).in_scope(move || {
198+
request
199+
.try_into_http_request_with_identity(
200+
homeserver_url,
201+
authentication_input,
202+
identity,
203+
path_builder_input,
204+
)
205+
.map_err(ResponseError::<C, R>::from)
206+
});
207+
208+
send_prepared_request::<C, R>(http_client, homeserver_url, http_req)
209+
}
210+
211+
fn send_customized_request<'a, C, R, F>(
212+
http_client: &'a C,
213+
homeserver_url: &str,
214+
authentication_input: <R::Authentication as AuthScheme>::Input<'_>,
215+
path_builder_input: <R::PathBuilder as PathBuilder>::Input<'_>,
216+
request: R,
217+
customize: F,
218+
) -> impl Future<Output = ResponseResult<C, R>> + Send + 'a + use<'a, C, R, F>
219+
where
220+
C: HttpClient + ?Sized,
221+
R: OutgoingRequest,
222+
F: FnOnce(&mut http::Request<C::RequestBody>) -> Result<(), ResponseError<C, R>>,
223+
{
224+
let http_req =
225+
info_span!("serialize_request", request_type = type_name::<R>()).in_scope(move || {
226+
request
227+
.try_into_http_request(homeserver_url, authentication_input, path_builder_input)
228+
.map_err(ResponseError::<C, R>::from)
229+
.and_then(|mut req| {
230+
customize(&mut req)?;
231+
Ok(req)
232+
})
233+
});
234+
235+
send_prepared_request::<C, R>(http_client, homeserver_url, http_req)
200236
}

0 commit comments

Comments
 (0)