ruma_client/
http_client.rs1use std::{future::Future, pin::Pin};
5
6use bytes::BufMut;
7use ruma::api::{
8 AppserviceUserIdentity, OutgoingRequest,
9 auth_scheme::{AuthScheme, SendAccessToken},
10 path_builder::PathBuilder,
11};
12
13use crate::{ResponseError, ResponseResult};
14
15#[cfg(feature = "hyper")]
16mod hyper;
17#[cfg(feature = "reqwest")]
18mod reqwest;
19
20#[cfg(feature = "hyper")]
21pub use self::hyper::Hyper;
22#[cfg(feature = "hyper-native-tls")]
23pub use self::hyper::HyperNativeTls;
24#[cfg(feature = "hyper-rustls")]
25pub use self::hyper::HyperRustls;
26#[cfg(feature = "reqwest")]
27pub use self::reqwest::Reqwest;
28
29pub trait HttpClient: Sync {
31 type RequestBody: AsRef<[u8]> + Default + BufMut + Send;
33
34 type ResponseBody: AsRef<[u8]>;
36
37 type Error: Send + Unpin;
39
40 fn send_http_request(
42 &self,
43 req: http::Request<Self::RequestBody>,
44 ) -> impl Future<Output = Result<http::Response<Self::ResponseBody>, Self::Error>> + Send;
45}
46
47pub trait DefaultConstructibleHttpClient: HttpClient {
49 fn default() -> Self;
51}
52
53pub trait HttpClientExt: HttpClient {
58 fn send_matrix_request<'a, R>(
61 &'a self,
62 homeserver_url: &str,
63 access_token: SendAccessToken<'a>,
64 path_builder_input: <R::PathBuilder as PathBuilder>::Input<'_>,
65 request: R,
66 ) -> Pin<Box<dyn Future<Output = ResponseResult<Self, R>> + 'a + Send>>
67 where
68 R: OutgoingRequest,
69 R::Authentication: AuthScheme<Input<'a> = SendAccessToken<'a>>,
70 {
71 self.send_customized_matrix_request(
72 homeserver_url,
73 access_token,
74 path_builder_input,
75 request,
76 |_| Ok(()),
77 )
78 }
79
80 fn send_customized_matrix_request<'a, R, F>(
84 &'a self,
85 homeserver_url: &str,
86 access_token: SendAccessToken<'a>,
87 path_builder_input: <R::PathBuilder as PathBuilder>::Input<'_>,
88 request: R,
89 customize: F,
90 ) -> Pin<Box<dyn Future<Output = ResponseResult<Self, R>> + 'a + Send>>
91 where
92 R: OutgoingRequest,
93 R::Authentication: AuthScheme<Input<'a> = SendAccessToken<'a>>,
94 F: FnOnce(&mut http::Request<Self::RequestBody>) -> Result<(), ResponseError<Self, R>>,
95 {
96 Box::pin(crate::send_customized_request(
97 self,
98 homeserver_url,
99 access_token,
100 path_builder_input,
101 request,
102 customize,
103 ))
104 }
105
106 fn send_matrix_request_as<'a, R>(
112 &'a self,
113 homeserver_url: &str,
114 access_token: SendAccessToken<'a>,
115 path_builder_input: <R::PathBuilder as PathBuilder>::Input<'_>,
116 identity: AppserviceUserIdentity<'a>,
117 request: R,
118 ) -> Pin<Box<dyn Future<Output = ResponseResult<Self, R>> + 'a>>
119 where
120 R: OutgoingRequest,
121 R::Authentication: AuthScheme<Input<'a> = SendAccessToken<'a>>,
122 {
123 self.send_customized_matrix_request(
124 homeserver_url,
125 access_token,
126 path_builder_input,
127 request,
128 |request| Ok(identity.maybe_add_to_uri(request.uri_mut())?),
129 )
130 }
131}
132
133impl<T: HttpClient> HttpClientExt for T {}
134
135#[doc(hidden)]
136#[derive(Debug)]
137#[allow(clippy::exhaustive_structs)]
138pub struct Dummy;
139
140impl HttpClient for Dummy {
141 type RequestBody = Vec<u8>;
142 type ResponseBody = Vec<u8>;
143 type Error = ();
144
145 #[allow(clippy::diverging_sub_expression)]
146 async fn send_http_request(
147 &self,
148 _req: http::Request<Self::RequestBody>,
149 ) -> Result<http::Response<Self::ResponseBody>, Self::Error> {
150 unimplemented!("this client only exists to allow doctests to compile")
151 }
152}
153
154impl DefaultConstructibleHttpClient for Dummy {
155 fn default() -> Self {
156 Dummy
157 }
158}