1use crate::{
2 ratelimiter::SharedRatelimiterTrait,
3 rest::{
4 error::{SharedRestClientErrorTrait, SharedRestError},
5 payload::SharedRestPayloadTrait,
6 response::SharedRestResponseTrait,
7 },
8 signer::SharedSignerTrait,
9};
10use http::Method;
11use reqwest::Url;
12use std::{num::NonZeroU32, sync::Arc};
13
14pub mod error;
15pub mod payload;
16pub mod response;
17
18#[async_trait::async_trait]
19pub trait SharedRestClientTrait<RateLimitType: Sync> {
20 fn get_client(&self) -> &reqwest::Client;
21 fn get_signer(&self) -> &dyn SharedSignerTrait;
22 fn get_ratelimiter(&self) -> Arc<dyn SharedRatelimiterTrait<RateLimitType> + Sync + Send>;
23
24 async fn call_with_no_payload<
25 ResponseType: SharedRestResponseTrait,
26 Err: SharedRestClientErrorTrait,
27 >(
28 &self,
29 limits: &[(RateLimitType, NonZeroU32)],
30 signed: bool,
31 method: Method,
32 url: Url,
33 ) -> Result<ResponseType, SharedRestError<Err>> {
34 self.call::<(), ResponseType, Err>(limits, signed, method, url, None)
35 .await
36 }
37
38 async fn call_with_no_response<
39 PayloadType: Sync + Send + SharedRestPayloadTrait,
40 Err: SharedRestClientErrorTrait,
41 >(
42 &self,
43 limits: &[(RateLimitType, NonZeroU32)],
44 signed: bool,
45 method: Method,
46 url: Url,
47 payload: Option<&PayloadType>,
48 ) -> Result<(), SharedRestError<Err>> {
49 self.call::<PayloadType, (), Err>(limits, signed, method, url, payload)
50 .await
51 }
52
53 async fn call_with_no_payload_and_response<Err: SharedRestClientErrorTrait>(
54 &self,
55 limits: &[(RateLimitType, NonZeroU32)],
56 signed: bool,
57 method: Method,
58 url: Url,
59 ) -> Result<(), SharedRestError<Err>> {
60 self.call::<(), (), Err>(limits, signed, method, url, None)
61 .await
62 }
63
64 async fn call<
65 PayloadType: Sync + Send + SharedRestPayloadTrait,
66 ResponseType: SharedRestResponseTrait,
67 Err: SharedRestClientErrorTrait,
68 >(
69 &self,
70 limits: &[(RateLimitType, NonZeroU32)],
71 signed: bool,
72 method: Method,
73 url: Url,
74 payload: Option<&PayloadType>,
75 ) -> Result<ResponseType, SharedRestError<Err>> {
76 for (rate_limit_type, limit) in limits.iter() {
77 self.get_ratelimiter()
78 .limit_on(rate_limit_type, *limit)
79 .await?;
80 }
81
82 let mut request = self
83 .get_client()
84 .request(method, url)
85 .build()
86 .expect("failed to build request");
87
88 if let Some(payload) = payload {
89 payload.build_request(&mut request);
90 }
91
92 if signed {
93 self.get_signer().sign_request(&mut request);
94 }
95
96 let response = self.get_client().execute(request).await?;
97
98 let status = response.status();
99 let body = response
100 .text()
101 .await
102 .inspect_err(|err| tracing::error!("failed to get response body: {err}"))?;
103
104 if status.is_success() {
105 return ResponseType::from_body(&body);
106 }
107
108 if status.is_client_error() {
109 tracing::error!("client error: {status} - {body}");
110 return Err(SharedRestError::ClientError(Err::from_body(&body)));
111 }
112
113 if status.is_server_error() {
114 tracing::error!("server error: {status} - {body}");
115 return Err(SharedRestError::ServerError(body));
116 }
117
118 tracing::error!("uncaught response status: {status} - {body}");
119 panic!("uncaught response status: {status} - {body}");
120 }
121}