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 String },
57 Instrument { v: &'a String },
59 Instruments { v: &'a Vec<String> },
61 ChainAsset { v: &'a String },
63 Asset {v: &'a String},
65 ToTs {v: Option<i64>},
68 ToTimestamp { v: Option<i64> },
70 Limit { v: Option<usize> },
72 Market {v: String},
75 InstrumentStatus { v: CCSpotInstrumentStatus },
77 OCCoreBlockNumber { v: i64 },
79 OCCoreAddress { v: &'a String },
81 OCCoreQuoteAsset { v: &'a String },
83 NewsLanguage { v: CCNewsLang },
85 NewsSourceID { v: CCNewsSourceID },
87 NewsCategories { v: Option<Vec<String>> },
89 NewsExcludeCategories { v: Option<Vec<String>> },
91 NewsSourceType { v: CCNewsSourceType },
93 NewsStatus { v: CCNewsStatus },
95}
96
97impl<'a> Param<'a> {
98 fn add_param_to_url(&self, url: &mut String) -> () {
99 let url_param: String = match self {
100 Param::Symbol { v } => format!("&fsym={}", v),
102 Param::Instrument { v } => format!("&instrument={}", v),
103 Param::Instruments { v } => format!("&instruments={}", vec_to_str(v.to_owned())),
104 Param::ChainAsset { v } => format!("&chain_asset={}", v),
105 Param::Asset { v } => format!("&asset={}", v),
106 Param::ToTs { v } => match v {
108 Some(v_) => format!("&toTs={}", v_),
109 None => String::from(""),
110 },
111 Param::ToTimestamp { v } => match v {
112 Some(v_) => format!("&to_ts={}", v_),
113 None => String::from(""),
114 },
115 Param::Limit { v } => match v {
116 Some(v_) => format!("&limit={}", v_),
117 None => String::from("&limit=2000"),
118 },
119 Param::Market { v } => format!("&market={}", v),
121 Param::InstrumentStatus { v } => format!("&instrument_status={}", v.to_string()),
122 Param::OCCoreBlockNumber { v } => format!("&block_number={}", v),
123 Param::OCCoreAddress { v } => format!("&address={}", v),
124 Param::OCCoreQuoteAsset { v } => format!(""e_asset={}", v),
125 Param::NewsLanguage { v } => format!("&lang={}", v.to_string()),
126 Param::NewsSourceID { v } => format!("&source_ids={}", v.to_string()),
127 Param::NewsCategories { v } => optional_vec_arguments(v.to_owned(), String::from("&categories=")),
128 Param::NewsExcludeCategories { v } => optional_vec_arguments(v.to_owned(), String::from("&exclude_categories=")),
129 Param::NewsSourceType { v } => format!("&source_type={}", v.to_string()),
130 Param::NewsStatus { v } => format!("&status={}", v.to_string()),
131 };
132 url.push_str(&url_param);
133 }
134}
135
136
137async fn process_request<T: DeserializeOwned>(url: String) -> Result<T, Error> {
139 let response: Response = reqwest::get(url).await?;
140 let response_body: String = response.text().await?;
141 #[cfg(feature = "debug")]
143 if debug()? { println!("{:?}", response_body) }
144 let response_body: String = response_body.replace("{}", "null");
146 let data: T = serde_json::from_str(&response_body)?;
148 Ok(data)
149}
150
151
152pub async fn call_api_endpoint<'a, R: DeserializeOwned>(
161 api_key: &String, endpoint: CCAPIEndpoint, unit: CCUnit, params: Vec<Param<'a>>, additional_params: Option<String>) -> Result<R, Error>
162{
163 let mut url: String = endpoint.url(&unit);
165 url.push_str(&format!("?api_key={}", api_key));
167 for param in params {
168 param.add_param_to_url(&mut url);
169 }
170 match additional_params {
172 Some(v) => url.push_str(&v),
173 None => (),
174 }
175 process_request::<R>(url).await
177}