rusty_feeder/common/
rest_utils.rs1use reqwest::Client;
4use rusty_common::error::CommonError;
5use serde::de::DeserializeOwned;
6use smartstring::alias::String;
7use std::time::{Duration, SystemTime, UNIX_EPOCH};
8
9#[derive(Debug, Clone)]
11pub struct RestConfig {
12 pub base_url: String,
14 pub timeout_secs: u64,
16 pub max_retries: u32,
18}
19
20impl Default for RestConfig {
21 fn default() -> Self {
22 Self {
23 base_url: String::new(),
24 timeout_secs: 30,
25 max_retries: 3,
26 }
27 }
28}
29
30pub fn create_client(timeout_secs: u64) -> Result<Client, CommonError> {
32 Client::builder()
33 .timeout(Duration::from_secs(timeout_secs))
34 .build()
35 .map_err(|e| CommonError::Network(String::from(e.to_string())))
36}
37
38#[must_use]
40pub fn current_timestamp_ms() -> u64 {
41 SystemTime::now()
42 .duration_since(UNIX_EPOCH)
43 .expect("Time went backwards")
44 .as_millis() as u64
45}
46
47pub async fn get_request<T: DeserializeOwned>(
49 client: &Client,
50 url: &str,
51) -> Result<T, CommonError> {
52 let response = client
53 .get(url)
54 .send()
55 .await
56 .map_err(|e| CommonError::Network(String::from(e.to_string())))?;
57
58 if !response.status().is_success() {
59 let status = response.status();
60 let error_text = response.text().await.unwrap_or_default();
61 let mut error_msg = String::new();
62 use std::fmt::Write;
63 write!(error_msg, "HTTP error: {status} - {error_text}")
64 .expect("write to String should not fail");
65 return Err(CommonError::Api(error_msg));
66 }
67
68 let bytes = response
69 .bytes()
70 .await
71 .map_err(|e| CommonError::Network(String::from(e.to_string())))?;
72 let mut bytes_vec = bytes.to_vec();
73 simd_json::from_slice::<T>(&mut bytes_vec)
74 .map_err(|e| CommonError::Parse(String::from(e.to_string())))
75}
76
77pub async fn post_request<T: DeserializeOwned, B: serde::Serialize>(
79 client: &Client,
80 url: &str,
81 body: &B,
82) -> Result<T, CommonError> {
83 let json_body =
85 simd_json::to_string(body).map_err(|e| CommonError::Parse(String::from(e.to_string())))?;
86
87 let response = client
88 .post(url)
89 .header("Content-Type", "application/json")
90 .body(json_body)
91 .send()
92 .await
93 .map_err(|e| CommonError::Network(String::from(e.to_string())))?;
94
95 if !response.status().is_success() {
96 let status = response.status();
97 let error_text = response.text().await.unwrap_or_default();
98 let mut error_msg = String::new();
99 use std::fmt::Write;
100 write!(error_msg, "HTTP error: {status} - {error_text}")
101 .expect("write to String should not fail");
102 return Err(CommonError::Api(error_msg));
103 }
104
105 let bytes = response
106 .bytes()
107 .await
108 .map_err(|e| CommonError::Network(String::from(e.to_string())))?;
109 let mut bytes_vec = bytes.to_vec();
110 simd_json::from_slice::<T>(&mut bytes_vec)
111 .map_err(|e| CommonError::Parse(String::from(e.to_string())))
112}
113
114pub fn parse_json<T: DeserializeOwned>(text: &str) -> Result<T, CommonError> {
116 rusty_common::json::parse(text)
117}
118
119#[cfg(test)]
120mod tests {
121 use super::*;
122
123 #[test]
124 fn test_timestamp() {
125 let ts1 = current_timestamp_ms();
126 std::thread::sleep(Duration::from_millis(10));
127 let ts2 = current_timestamp_ms();
128 assert!(ts2 > ts1);
129 }
130
131 #[test]
132 fn test_rest_config_default() {
133 let config = RestConfig::default();
134 assert_eq!(config.timeout_secs, 30);
135 assert_eq!(config.max_retries, 3);
136 }
137}