Skip to content

Commit 34d4459

Browse files
committed
Refactor Client to support AppserviceUserIdentity
1 parent 1caeac2 commit 34d4459

4 files changed

Lines changed: 90 additions & 57 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: 33 additions & 15 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,7 @@ 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_as,
2828
};
2929

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

88100
impl<C: HttpClient> Client<C> {
@@ -108,20 +120,12 @@ impl<C: HttpClient> Client<C> {
108120
R::PathBuilder: SupportedPathBuilder,
109121
F: FnOnce(&mut http::Request<C::RequestBody>) -> Result<(), ResponseError<C, R>>,
110122
{
111-
let token_mode = self.0.token_mode;
112123
let access_token = self.access_token();
113124

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-
121125
send_customized_request(
122126
&self.0.http_client,
123127
&self.0.homeserver_url,
124-
send_access_token,
128+
self.send_access_token(&access_token),
125129
R::PathBuilder::get_path_builder_input(self),
126130
request,
127131
customize,
@@ -133,13 +137,27 @@ impl<C: HttpClient> Client<C> {
133137
///
134138
/// This method is meant to be used by application services when interacting with the
135139
/// client-server API.
136-
pub async fn send_request_as<R>(&self, user_id: &UserId, request: R) -> ResponseResult<C, R>
140+
pub async fn send_request_as<R>(
141+
&self,
142+
identity: AppserviceUserIdentity<'_>,
143+
request: R,
144+
) -> ResponseResult<C, R>
137145
where
138-
R: OutgoingRequest,
146+
R: OutgoingRequestAppserviceExt,
139147
for<'a> R::Authentication: AuthScheme<Input<'a> = SendAccessToken<'a>>,
140148
R::PathBuilder: SupportedPathBuilder,
141149
{
142-
self.send_customized_request(request, add_user_id_to_query::<C, R>(user_id)).await
150+
let access_token = self.access_token();
151+
152+
send_request_as(
153+
&self.0.http_client,
154+
&self.0.homeserver_url,
155+
self.send_access_token(&access_token),
156+
R::PathBuilder::get_path_builder_input(self),
157+
identity,
158+
request,
159+
)
160+
.await
143161
}
144162

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

src/http_client.rs

Lines changed: 14 additions & 16 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, OutgoingRequestAppserviceExt,
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;
@@ -106,8 +103,8 @@ pub trait HttpClientExt: HttpClient {
106103
))
107104
}
108105

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.
106+
/// Turn a strongly-typed matrix request into an `http::Request`, add `user_id` and/or
107+
/// `device_id` query parameters to it and send it to get back a strongly-typed response.
111108
///
112109
/// This method is meant to be used by application services when interacting with the
113110
/// client-server API.
@@ -116,20 +113,21 @@ pub trait HttpClientExt: HttpClient {
116113
homeserver_url: &str,
117114
access_token: SendAccessToken<'a>,
118115
path_builder_input: <R::PathBuilder as PathBuilder>::Input<'_>,
119-
user_id: &'a UserId,
116+
identity: AppserviceUserIdentity<'a>,
120117
request: R,
121118
) -> Pin<Box<dyn Future<Output = ResponseResult<Self, R>> + 'a>>
122119
where
123-
R: OutgoingRequest,
124-
R::Authentication: AuthScheme<Input<'a> = SendAccessToken<'a>>,
120+
R: OutgoingRequestAppserviceExt,
121+
for<'b> R::Authentication: AuthScheme<Input<'b> = SendAccessToken<'b>>,
125122
{
126-
self.send_customized_matrix_request(
123+
Box::pin(crate::send_request_as(
124+
self,
127125
homeserver_url,
128126
access_token,
129127
path_builder_input,
128+
identity,
130129
request,
131-
add_user_id_to_query::<Self, R>(user_id),
132-
)
130+
))
133131
}
134132
}
135133

src/lib.rs

Lines changed: 42 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -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},
@@ -156,6 +153,18 @@ where
156153
})
157154
});
158155

156+
send_http_request::<C, R>(http_client, homeserver_url, http_req)
157+
}
158+
159+
fn send_http_request<'a, C, R>(
160+
http_client: &'a C,
161+
homeserver_url: &str,
162+
http_req: Result<http::Request<C::RequestBody>, ResponseError<C, R>>,
163+
) -> impl Future<Output = ResponseResult<C, R>> + Send + 'a + use<'a, C, R>
164+
where
165+
C: HttpClient + ?Sized,
166+
R: OutgoingRequest,
167+
{
159168
let send_span = info_span!(
160169
"send_request",
161170
request_type = type_name::<R>(),
@@ -178,23 +187,30 @@ where
178187
}
179188
}
180189

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-
}))?;
190+
fn send_request_as<'a, C, R>(
191+
http_client: &'a C,
192+
homeserver_url: &str,
193+
authentication_input: <R::Authentication as AuthScheme>::Input<'_>,
194+
path_builder_input: <R::PathBuilder as PathBuilder>::Input<'_>,
195+
identity: AppserviceUserIdentity<'_>,
196+
request: R,
197+
) -> impl Future<Output = ResponseResult<C, R>> + Send + 'a + use<'a, C, R>
198+
where
199+
C: HttpClient + ?Sized,
200+
R: OutgoingRequestAppserviceExt,
201+
for<'b> R::Authentication: AuthScheme<Input<'b> = SendAccessToken<'b>>,
202+
{
203+
let http_req =
204+
info_span!("serialize_request_as", request_type = type_name::<R>()).in_scope(move || {
205+
request
206+
.try_into_http_request_with_identity(
207+
homeserver_url,
208+
authentication_input,
209+
identity,
210+
path_builder_input,
211+
)
212+
.map_err(ResponseError::<C, R>::from)
213+
});
197214

198-
Ok(())
199-
}
215+
send_http_request::<C, R>(http_client, homeserver_url, http_req)
200216
}

0 commit comments

Comments
 (0)