1use web_time::{Duration, Instant};
2
3use reqwest::Client;
4use tokio::time::sleep;
5
6use crate::get_code_version;
7use crate::model::account::Account;
8use crate::model::api::*;
9use crate::model::clock::{Timestamp, get_time};
10use crate::model::errors::LbErr;
11use crate::model::pubkey;
12
13impl<E> From<ErrorWrapper<E>> for ApiError<E> {
14 fn from(err: ErrorWrapper<E>) -> Self {
15 match err {
16 ErrorWrapper::Endpoint(e) => ApiError::Endpoint(e),
17 ErrorWrapper::ClientUpdateRequired => ApiError::ClientUpdateRequired,
18 ErrorWrapper::InvalidAuth => ApiError::InvalidAuth,
19 ErrorWrapper::ExpiredAuth => ApiError::ExpiredAuth,
20 ErrorWrapper::InternalError => ApiError::InternalError,
21 ErrorWrapper::BadRequest => ApiError::BadRequest,
22 }
23 }
24}
25
26#[derive(Debug)]
28pub enum ApiError<E> {
29 Endpoint(E),
30 ClientUpdateRequired,
31 InvalidAuth,
32 ExpiredAuth,
33 InternalError,
34 BadRequest,
35 Sign(LbErr),
36 Serialize(String),
37 SendFailed(String),
38 ReceiveFailed(String),
39 Deserialize(String),
40}
41
42#[derive(Debug, Clone)]
43#[repr(C)]
44pub struct Network {
45 pub client: Client,
46 pub get_code_version: fn() -> &'static str,
47 pub get_time: fn() -> Timestamp,
48}
49
50impl Default for Network {
51 fn default() -> Self {
52 Self { client: Default::default(), get_code_version, get_time }
53 }
54}
55
56impl Network {
57 #[instrument(level = "debug", skip(self, account, request), fields(route=T::ROUTE), err(Debug))]
58 pub async fn request<T: Request>(
59 &self, account: &Account, request: T,
60 ) -> Result<T::Response, ApiError<T::Error>> {
61 let signed_request =
62 pubkey::sign(&account.private_key, &account.public_key(), request, self.get_time)
63 .map_err(ApiError::Sign)?;
64
65 let client_version = String::from((self.get_code_version)());
66
67 let serialized_request = serde_json::to_vec(&RequestWrapper {
68 signed_request,
69 client_version: client_version.clone(),
70 })
71 .map_err(|err| ApiError::Serialize(err.to_string()))?;
72
73 if serialized_request.len() > 10 * 1024 * 1024 {
74 warn!("making network request with {} bytes", serialized_request.len());
75 }
76
77 let mut retries = 0;
78 let start = Instant::now();
79 let sent = loop {
80 let url = &account.api_url;
81 debug!("url {url}");
82 match self
83 .client
84 .request(T::METHOD, format!("{}{}", url, T::ROUTE).as_str())
85 .body(serialized_request.clone())
86 .header("Accept-Version", client_version.clone())
87 .send()
88 .await
89 {
90 Ok(o) => {
91 if start.elapsed() > Duration::from_millis(1000) {
92 warn!("network request took {:?}", start.elapsed());
93 }
94 break o;
95 }
96 Err(e) => {
97 if retries < 3 {
98 warn!(
99 "network request send failed; retrying after {}ms; error = {:?}",
100 retries * 100,
101 e.to_string()
102 );
103 sleep(Duration::from_millis(retries * 100)).await;
104 retries += 1;
105 continue;
106 } else {
107 return Err(ApiError::SendFailed(e.to_string()));
108 }
109 }
110 }
111 };
112 let serialized_response = sent
113 .bytes()
114 .await
115 .map_err(|err| ApiError::ReceiveFailed(err.to_string()))?;
116 let response: Result<T::Response, ErrorWrapper<T::Error>> =
117 serde_json::from_slice(&serialized_response)
118 .map_err(|err| ApiError::Deserialize(err.to_string()))?;
119 response.map_err(ApiError::from)
120 }
121}