1use std::error::Error;
6use std::future::Future;
7
8pub static TWITCH_OAUTH2_USER_AGENT: &str =
10 concat!(env!("CARGO_PKG_NAME"), "/", env!("CARGO_PKG_VERSION"),);
11
12type BoxedFuture<'a, T> = std::pin::Pin<Box<dyn Future<Output = T> + Send + 'a>>;
14
15pub trait Client: Sync + Send {
17 type Error: Error + Send + Sync + 'static;
19 fn req(
21 &self,
22 request: http::Request<Vec<u8>>,
23 ) -> BoxedFuture<'_, Result<http::Response<Vec<u8>>, <Self as Client>::Error>>;
24}
25
26#[doc(hidden)]
27#[derive(Debug, thiserror::Error, Clone)]
28#[error("this client does not do anything, only used for documentation test that only checks code integrity")]
29pub struct DummyClient;
30
31#[cfg(feature = "reqwest")]
32impl Client for DummyClient {
33 type Error = DummyClient;
34
35 fn req(
36 &self,
37 _: http::Request<Vec<u8>>,
38 ) -> BoxedFuture<'_, Result<http::Response<Vec<u8>>, Self::Error>> {
39 Box::pin(async move { Err(self.clone()) })
40 }
41}
42#[cfg(feature = "reqwest")]
43use reqwest::Client as ReqwestClient;
44
45#[cfg(feature = "reqwest")]
46impl Client for ReqwestClient {
47 type Error = reqwest::Error;
48
49 fn req(
50 &self,
51 request: http::Request<Vec<u8>>,
52 ) -> BoxedFuture<'_, Result<http::Response<Vec<u8>>, Self::Error>> {
53 let req = match reqwest::Request::try_from(request) {
55 Ok(req) => req,
56 Err(e) => return Box::pin(async { Err(e) }),
57 };
58 let fut = self.execute(req);
60 Box::pin(async move {
61 let mut response = fut.await?;
63 let mut result = http::Response::builder().status(response.status());
64 let headers = result
65 .headers_mut()
66 .expect("expected to get headers mut when building response");
68 std::mem::swap(headers, response.headers_mut());
69 let result = result.version(response.version());
70 Ok(result
71 .body(response.bytes().await?.as_ref().to_vec())
72 .expect("mismatch reqwest -> http conversion should not fail"))
73 })
74 }
75}