1use serde::de::DeserializeOwned;
2use reqwest::Response;
3use crate::error::Error;
4use crate::{CCUnit, CCAPIEndpoint};
5use crate::schemas::data_api::spot::CCSpotInstrumentStatus;
6use crate::schemas::data_api::news::{CCNewsLang, CCNewsSourceID, CCNewsSourceType, CCNewsStatus};
7
8
9#[cfg(feature = "debug")]
10fn debug() -> Result<bool, Error> {
13 dotenv::dotenv()?;
14 let debug: bool = serde_json::from_str(&std::env::var("CCDATA_API_DEBUG")?)?;
15 Ok(debug)
16}
17
18
19pub trait Market {
21 fn to_string(&self) -> String;
23}
24
25
26fn vec_to_str(vec: &Vec<String>) -> String {
28 let mut s: String = String::from("");
29 for v in vec {
30 s.push_str(&v);
31 s.push_str(&",");
32 }
33 s.pop();
34 s
35}
36
37
38fn optional_vec_arguments(o: Option<Vec<String>>, api_argument: String) -> String {
40 let mut s: String = String::from("");
41 match o {
42 Some(v) => {
43 s.push_str(&api_argument);
44 s.push_str(&vec_to_str(&v));
45 },
46 None => (),
47 }
48 s
49}
50
51
52pub enum Param<'a> {
54 Symbol { v: &'a str },
57 Instrument { v: &'a str },
59 Instruments { v: &'a Vec<String> },
61 ChainAsset { v: &'a str },
63 Asset {v: &'a str},
65 Assets {v: Vec<String>},
67 ToTs {v: Option<i64>},
70 ToTimestamp { v: Option<i64> },
72 Limit { v: Option<usize> },
74 Market {v: String},
77 InstrumentStatus { v: CCSpotInstrumentStatus },
79 OCCoreBlockNumber { v: i64 },
81 OCCoreAddress { v: &'a str },
83 OCCoreQuoteAsset { v: &'a str },
85 NewsLanguage { v: CCNewsLang },
87 NewsSourceID { v: CCNewsSourceID },
89 NewsCategories { v: Option<Vec<String>> },
91 NewsExcludeCategories { v: Option<Vec<String>> },
93 NewsSourceType { v: CCNewsSourceType },
95 NewsStatus { v: CCNewsStatus },
97}
98
99impl<'a> Param<'a> {
100 fn add_param_to_url(&self, url: &mut String) -> () {
101 let url_param: String = match self {
102 Self::Symbol { v } => format!("&fsym={}", v),
104 Self::Instrument { v } => format!("&instrument={}", v),
105 Self::Instruments { v } => format!("&instruments={}", vec_to_str(v.to_owned())),
106 Self::ChainAsset { v } => format!("&chain_asset={}", v),
107 Self::Asset { v } => format!("&asset={}", v),
108 Self::Assets { v } => format!("&assets={}", v.join(",")),
109 Self::ToTs { v } => match v {
111 Some(v_) => format!("&toTs={}", v_),
112 None => String::from(""),
113 },
114 Self::ToTimestamp { v } => match v {
115 Some(v_) => format!("&to_ts={}", v_),
116 None => String::from(""),
117 },
118 Self::Limit { v } => match v {
119 Some(v_) => format!("&limit={}", v_),
120 None => String::from("&limit=2000"),
121 },
122 Self::Market { v } => format!("&market={}", v),
124 Self::InstrumentStatus { v } => format!("&instrument_status={}", v.to_string()),
125 Self::OCCoreBlockNumber { v } => format!("&block_number={}", v),
126 Self::OCCoreAddress { v } => format!("&address={}", v),
127 Self::OCCoreQuoteAsset { v } => format!(""e_asset={}", v),
128 Self::NewsLanguage { v } => format!("&lang={}", v.to_string()),
129 Self::NewsSourceID { v } => format!("&source_ids={}", v.to_string()),
130 Self::NewsCategories { v } => optional_vec_arguments(v.to_owned(), String::from("&categories=")),
131 Self::NewsExcludeCategories { v } => optional_vec_arguments(v.to_owned(), String::from("&exclude_categories=")),
132 Self::NewsSourceType { v } => format!("&source_type={}", v.to_string()),
133 Self::NewsStatus { v } => format!("&status={}", v.to_string()),
134 };
135 url.push_str(&url_param);
136 }
137}
138
139
140async fn process_request<T: DeserializeOwned>(url: String) -> Result<T, Error> {
142 let response: Response = reqwest::get(url).await?;
143 let response_body: String = response.text().await?;
144 #[cfg(feature = "debug")]
146 if debug()? { println!("{:?}", response_body) }
147 let response_body: String = response_body.replace("{}", "null");
149 let data: T = serde_json::from_str(&response_body)?;
151 Ok(data)
152}
153
154
155pub async fn call_api_endpoint<'a, R: DeserializeOwned>(
164 api_key: &str, endpoint: CCAPIEndpoint, unit: CCUnit, params: Vec<Param<'a>>, additional_params: Option<String>) -> Result<R, Error>
165{
166 let mut url: String = endpoint.url(&unit);
168 url.push_str(&format!("?api_key={}", api_key));
170 for param in params {
171 param.add_param_to_url(&mut url);
172 }
173 match additional_params {
175 Some(v) => url.push_str(&v),
176 None => (),
177 }
178 process_request::<R>(url).await
180}