use crate::client::OkxClient;
use anyhow::Result;
use http::{HeaderMap, HeaderValue};
use ring::hmac;
use serde::de::DeserializeOwned;
use std::collections::BTreeMap;
impl OkxClient {
pub async fn get<T>(
&self,
request_path: &str,
parameters: &BTreeMap<String, String>,
) -> Result<T>
where
T: DeserializeOwned + std::fmt::Debug,
{
let timestamp = self.get_timestamp();
let mut get_url_params: String = String::from(request_path);
if parameters.len() != 0 {
get_url_params = format!("{}?{}", request_path, self.parse_params_to_str(parameters));
}
let message = format!("{}GET{}", timestamp, get_url_params);
let sign = self.sign(&message);
let headers = self.create_header(&sign, ×tamp);
let client = reqwest::Client::new();
if self.debug {
println!(
"[*] Debug:\nUrl:{}\nparameters:{:?}",
format!("{}{}", self.domain, request_path),
parameters
);
}
let res = client
.get(format!("{}{}", self.domain, get_url_params))
.headers(headers)
.send()
.await?
.text()
.await?;
if self.debug {
println!("[*] Response {:#?}", res);
}
Ok(serde_json::from_str::<T>(&res)?)
}
pub async fn post<T>(
&self,
request_path: &str,
parameters: &BTreeMap<String, String>,
) -> Result<T>
where
T: DeserializeOwned + std::fmt::Debug,
{
let timestamp = self.get_timestamp();
let data = serde_json::to_string(¶meters).unwrap();
let message = format!("{}POST{}{}", timestamp, request_path, &data);
let sign = self.sign(&message);
let headers = self.create_header(&sign, ×tamp);
let client = reqwest::Client::new();
if self.debug {
println!("[*] Debug:parameters {:?}", parameters);
}
if self.debug {
println!(
"[*] Debug:\nUrl:{}\nparameters:{:?}",
format!("{}{}", self.domain, request_path),
parameters
);
}
let res = client
.post(format!("{}{}", self.domain, request_path))
.headers(headers)
.json(¶meters)
.send()
.await?
.text()
.await?;
if self.debug {
println!("[*] Response {:#?}", res);
}
Ok(serde_json::from_str::<T>(&res)?)
}
pub async fn post_vec<T>(
&self,
request_path: &str,
parameters: &Vec<BTreeMap<String, String>>,
) -> Result<T>
where
T: DeserializeOwned + std::fmt::Debug,
{
let timestamp = self.get_timestamp();
let data = serde_json::to_string(parameters).unwrap();
let message = format!("{}POST{}{}", timestamp, request_path, &data);
let sign = self.sign(&message);
let headers = self.create_header(&sign, ×tamp);
let client = reqwest::Client::new();
if self.debug {
println!(
"[*] Debug:\nUrl:{}\nparameters:{:?}",
format!("{}{}", self.domain, request_path),
parameters
);
}
let res = client
.post(format!("{}{}", self.domain, request_path))
.headers(headers)
.json(¶meters)
.send()
.await?
.text()
.await?;
if self.debug {
println!("[*] Response {:#?}", res);
}
Ok(serde_json::from_str::<T>(&res)?)
}
fn create_header(&self, sign: &str, timestamp: &str) -> HeaderMap {
let mut header_map = HeaderMap::new();
header_map.insert(
"OK-ACCESS-KEY",
HeaderValue::from_str(&self.api_key).unwrap(),
);
header_map.insert("OK-ACCESS-SIGN", HeaderValue::from_str(&sign).unwrap());
header_map.insert(
"OK-ACCESS-TIMESTAMP",
HeaderValue::from_str(×tamp).unwrap(),
);
header_map.insert(
"OK-ACCESS-PASSPHRASE",
HeaderValue::from_str(&self.passphrase).unwrap(),
);
header_map.insert(
"CONTENT_TYPE",
HeaderValue::from_static("application/json; charset=UTF-8"),
);
if self.testnet {
header_map.insert("x-simulated-trading", HeaderValue::from_static("1"));
}
header_map
}
fn parse_params_to_str(&self, parameters: &BTreeMap<String, String>) -> String {
parameters
.into_iter()
.map(|(key, value)| format!("{}={}", key, value))
.collect::<Vec<String>>()
.join("&")
}
fn sign(&self, message: &String) -> String {
let hmac_key = ring::hmac::Key::new(hmac::HMAC_SHA256, &self.secret_key.as_bytes());
let result = ring::hmac::sign(&hmac_key, &message.as_bytes());
base64::encode(result)
}
pub fn get_timestamp(&self) -> String {
chrono::Utc::now()
.format("%Y-%m-%dT%H:%M:%S%.3fZ")
.to_string()
}
}