| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313 |
- use std::collections::BTreeMap;
- use hex;
- use hmac::{Hmac, Mac, NewMac};
- use ring::digest;
- use rust_decimal::Decimal;
- use rust_decimal_macros::dec;
- use serde_json::Value;
- use sha2::Sha512;
- use tracing::info;
- use crate::http::request::Response;
- use crate::utils::utils::parse_params_to_str;
- #[derive(Clone)]
- #[allow(dead_code)]
- pub struct GateSwapRest {
- label: String,
- base_url: String,
- client: reqwest::Client,
- /*******参数*/
- //登陆所需参数
- login_param: BTreeMap<String, String>,
- delays: Vec<i64>,
- max_delay: i64,
- avg_delay: Decimal,
- }
- impl GateSwapRest {
- /*******************************************************************************************************/
- /*****************************************获取一个对象****************************************************/
- /*******************************************************************************************************/
- pub fn new(is_colo: bool, login_param: BTreeMap<String, String>) -> GateSwapRest
- {
- return GateSwapRest::new_label("default-GateSwapRest".to_string(), is_colo, login_param);
- }
- pub fn new_label(label: String, is_colo: bool, login_param: BTreeMap<String, String>) -> GateSwapRest
- {
- let base_url = if is_colo {
- let url = "https://apiv4-private.gateapi.io".to_string();
- info!("开启高速通道:{:?}",url);
- url
- } else {
- let url = "https://api.gateio.ws".to_string();
- info!("走普通通道:{}",url);
- url
- };
- if is_colo {} else {}
- /*****返回结构体*******/
- GateSwapRest {
- label,
- base_url: base_url.to_string(),
- client: reqwest::Client::new(),
- login_param,
- delays: vec![],
- max_delay: 0,
- avg_delay: dec!(0.0),
- }
- }
- /*******************************************************************************************************/
- /*****************************************rest请求函数********************************************************/
- //查询个人成交记录
- pub async fn my_trades(&mut self, settle: String, contract: String, limit: i64) -> Response {
- let mut params = serde_json::json!({
- "contract":contract,
- "limit":1000
- });
- if limit > 0 {
- params["limit"] = serde_json::json!(limit);
- }
- let data = self.request("GET".to_string(),
- "/api/v4".to_string(),
- format!("/futures/{}/my_trades", settle),
- true,
- params.to_string(),
- ).await;
- data
- }
- //查询合约账户变更历史
- pub async fn account_book(&mut self, settle: String, start_time: i64, end_time: i64) -> Response {
- let params = serde_json::json!({
- "limit":1000,
- "from":start_time-60*60*24*5,
- "to":end_time
- });
- let data = self.request("GET".to_string(),
- "/api/v4".to_string(),
- format!("/futures/{}/account_book", settle),
- true,
- params.to_string(),
- ).await;
- data
- }
- pub async fn fill_account_book(&mut self, settle: String, _start_time: i64, end_time: i64) -> Response {
- let params = serde_json::json!({
- "limit":1,
- "from":end_time-60*60*24*30,
- "to":end_time
- });
- let data = self.request("GET".to_string(),
- "/api/v4".to_string(),
- format!("/futures/{}/account_book", settle),
- true,
- params.to_string(),
- ).await;
- data
- }
- //调用请求
- async fn request(&mut self,
- request_type: String,
- prefix_url: String,
- request_url: String,
- is_login: bool,
- params: String) -> Response
- {
- // trace!("login_param:{:?}", self.login_param);
- //解析账号信息
- let mut access_key = "".to_string();
- let mut secret_key = "".to_string();
- if self.login_param.contains_key("access_key") {
- access_key = self.login_param.get("access_key").unwrap().to_string();
- }
- if self.login_param.contains_key("secret_key") {
- secret_key = self.login_param.get("secret_key").unwrap().to_string();
- }
- let mut is_login_param = true;
- if access_key == "" || secret_key == "" {
- is_login_param = false
- }
- //请求头配置-如果需要登陆则存在额外配置
- let mut body = "".to_string();
- let timestamp = chrono::Utc::now().timestamp().to_string();
- let mut headers = reqwest::header::HeaderMap::new();
- if request_type == "GET" {
- headers.insert("Content-type", "application/x-www-form-urlencoded".parse().unwrap());
- headers.insert("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) ".parse().unwrap());
- } else {
- headers.insert("Accept", "application/json".parse().unwrap());
- headers.insert("Content-Type", "application/json".parse().unwrap());
- }
- if request_type == "POST" {
- body = params.clone();
- }
- //是否需要登陆-- 组装sing
- if is_login {
- if !is_login_param {
- let mut res = Response::new();
- res.code = "-1".to_string();
- res.msg = "登陆参数错误".to_string();
- return res;
- } else {//需要登陆-且登陆参数齐全
- //组装sing
- let sing = Self::sign(secret_key.clone(),
- request_type.clone(),
- prefix_url.clone(),
- request_url.clone(),
- params.clone(),
- body.clone(),
- timestamp.clone(),
- );
- // trace!("sing:{}", sing);
- //组装header
- headers.extend(Self::headers(access_key, timestamp, sing));
- }
- }
- // trace!("headers:{:?}", headers);
- let base_url = format!("{}{}", prefix_url.clone(), request_url.clone());
- let get_response = self.http_toll(
- base_url.clone(),
- request_type.to_string(),
- params.clone(),
- headers,
- ).await;
- let res_data = Self::res_data_analysis(get_response, base_url, params);
- res_data
- }
- pub fn headers(access_key: String, timestamp: String, sign: String) -> reqwest::header::HeaderMap {
- let mut headers = reqwest::header::HeaderMap::new();
- headers.insert("KEY", access_key.clone().parse().unwrap());
- headers.insert("Timestamp", timestamp.clone().parse().unwrap());
- headers.insert("SIGN", sign.clone().parse().unwrap());
- headers
- }
- pub fn sign(secret_key: String,
- request_type: String, prefix_url: String, request_url: String,
- params: String, body_data: String, timestamp: String) -> String
- {
- let url = format!("{}{}", prefix_url, request_url);
- let params_str = parse_params_to_str(params);
- let body = Some(body_data);
- let hashed_payload = if let Some(body) = body {
- let mut m = digest::Context::new(&digest::SHA512);
- m.update(body.as_bytes());
- hex::encode(m.finish().as_ref())
- } else {
- String::new()
- };
- // trace!("hashed_payload:{}", hashed_payload);
- let message = format!("{}\n{}\n{}\n{}\n{}",
- request_type,
- url,
- params_str,
- hashed_payload,
- timestamp);
- // trace!("**********", );
- // trace!("组装数据:{}", message);
- // trace!("**********", );
- let mut mac = Hmac::<Sha512>::new_varkey(secret_key.as_bytes()).expect("Failed to create HMAC");
- mac.update(message.as_bytes());
- let result = mac.finalize().into_bytes();
- let sign = hex::encode(result);
- sign
- }
- async fn http_toll(&mut self, request_path: String, request_type: String, params: String, headers: reqwest::header::HeaderMap) -> Result<Response, reqwest::Error> {
- /****请求接口与 地址*/
- let url = format!("{}{}", self.base_url.to_string(), request_path);
- let request_type = request_type.clone().to_uppercase();
- let addrs_url = format!("{}?{}", url.clone(), parse_params_to_str(params.clone()));
- // let params_json: serde_json::Value = serde_json::from_str(¶ms).unwrap();
- // trace!("url:{}",url);
- // trace!("addrs_url:{}",url);
- // trace!("params_json:{}",params_json);
- // trace!("headers:{:?}",headers);
- let req = match request_type.as_str() {
- "GET" => self.client.get(addrs_url.clone()).headers(headers),
- "POST" => self.client.post(addrs_url.clone()).body(params).headers(headers),
- "DELETE" => self.client.delete(addrs_url.clone()).headers(headers),
- // "PUT" => self.client.put(url.clone()).json(¶ms),
- _ => {
- let mut res = Response::new();
- res.code = "-1".to_string();
- res.msg = "请求类型错误".to_string();
- res.data = "".to_string();
- return Ok(res);
- }
- };
- let response = req.send().await?;
- let mut res = Response::new();
- if response.status().is_success() {
- // 读取响应的内容
- let body = response.text().await?;
- res.code = "200".to_string();
- res.msg = "success".to_string();
- res.data = body;
- // trace!("ok-----{}", body);
- } else {
- let body = response.text().await?;
- res.code = "-1".to_string();
- res.msg = body;
- res.data = "".to_string();
- }
- Ok(res)
- }
- //res_data 解析
- pub fn res_data_analysis(result: Result<Response, reqwest::Error>, base_url: String, params: String) -> Response {
- let res = Response::new();
- match result {
- Ok(res_data) => {
- // info!("原数据:{:?}",res_data);
- if res_data.code != "200" {
- let message = res_data.msg;
- // let json_value: serde_json::Value = serde_json::from_str(&message).unwrap();//这种方式会触发 解析错误
- let json_value = serde_json::from_str::<Value>(&message);
- match json_value {
- Ok(_data) => {
- let mut error = Response::new();
- error.code = "-1".to_string();
- error.msg = format!("请求错误{:?}", res.msg);
- error.data = format!("请求地址:{},请求参数:{}", base_url, params);
- error
- }
- Err(e) => {
- // error!("解析错误:{:?}",e);
- let mut error = Response::new();
- error.code = "-1".to_string();
- error.msg = format!("json 解析失败:{},相关参数:{}", e, message);
- error.data = "".to_string();
- error
- }
- }
- } else {
- res_data
- }
- }
- Err(err) => {
- let mut error = Response::new();
- error.code = "-1".to_string();
- error.msg = format!("json 解析失败:{},相关参数:{}", err, params);
- error.data = "".to_string();
- error
- }
- }
- }
- }
|