use anyhow::{Result, anyhow};
use reqwest::blocking::{Client, Response};
use reqwest::header::{HeaderMap, HeaderName, HeaderValue};
use std::collections::BTreeMap;
use std::str::FromStr;
use tracing::{debug, error};
use crate::consts;
use crate::utils;
#[derive(Debug, Clone)]
pub struct BitgetClient {
pub api_key: String,
pub api_secret_key: String,
pub passphrase: String,
pub use_server_time: bool,
pub first: bool,
http_client: Client,
base_url: String,
}
impl BitgetClient {
pub fn new(
api_key: String,
api_secret_key: String,
passphrase: String,
use_server_time: bool,
first: bool,
) -> Self {
Self {
api_key,
api_secret_key,
passphrase,
use_server_time,
first,
http_client: Client::new(),
base_url: consts::API_URL.to_string(),
}
}
pub fn request(
&self,
method: &str,
request_path: &str,
params: &BTreeMap<String, String>,
cursor: bool,
) -> Result<String> {
let _cursor = cursor;
let mut full_path = request_path.to_string();
if method == consts::GET {
full_path.push('?');
full_path.push_str(&utils::build_query(params));
}
let url = format!("{}{}", self.base_url, full_path);
let headers = self.build_headers(method, &full_path, params)?;
let body = if method == consts::POST {
Some(serde_json::to_string(params)?)
} else {
None
};
let response = match method {
consts::GET => self.http_client.get(&url).headers(headers).send()?,
consts::POST => self
.http_client
.post(&url)
.headers(headers)
.body(body.unwrap())
.send()?,
_ => return Err(anyhow!("不支持的 HTTP 方法: {}", method)),
};
let status = response.status();
let text = response.text()?;
if !status.is_success() {
return Err(anyhow!("请求失败,状态码: {}, 响应: {}", status, text));
}
Ok(text)
}
fn build_headers(
&self,
method: &str,
full_path: &str,
params: &BTreeMap<String, String>,
) -> Result<HeaderMap> {
let timestamp = if self.use_server_time {
utils::get_timestamp()
} else {
utils::get_timestamp()
};
let body = if method == consts::POST {
serde_json::to_string(params).map_err(|e| anyhow!("序列化参数失败: {}", e))?
} else {
String::new()
};
let pre_hash = utils::pre_hash(×tamp, method, full_path, &body);
let sign = match consts::SIGN_TYPE {
"RSA" => {
return Err(anyhow!("RSA 签名暂未实现"));
}
_ => utils::sign(&pre_hash, &self.api_secret_key)?,
};
let headers = utils::get_header(&self.api_key, &sign, ×tamp, &self.passphrase);
let mut header_map = HeaderMap::new();
for (k, v) in headers {
header_map.insert(
HeaderName::from_str(&k).map_err(|e| anyhow!("无效的 header 名称: {}", e))?,
HeaderValue::from_str(&v).map_err(|e| anyhow!("无效的 header 值: {}", e))?,
);
}
Ok(header_map)
}
}