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, delays: Vec, max_delay: i64, avg_delay: Decimal, } impl GateSwapRest { /*******************************************************************************************************/ /*****************************************获取一个对象****************************************************/ /*******************************************************************************************************/ pub fn new(is_colo: bool, login_param: BTreeMap) -> 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) -> 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::::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 { /****请求接口与 地址*/ 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, 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::(&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 } } } }