|
@@ -1,17 +1,34 @@
|
|
|
use std::collections::BTreeMap;
|
|
use std::collections::BTreeMap;
|
|
|
-use reqwest::header::HeaderMap;
|
|
|
|
|
-use ring::{digest};
|
|
|
|
|
|
|
+use base64::encode;
|
|
|
|
|
+
|
|
|
|
|
+use chrono::Utc;
|
|
|
use hex;
|
|
use hex;
|
|
|
-use hmac::{Hmac, Mac, NewMac};
|
|
|
|
|
|
|
+use percent_encoding::{AsciiSet, CONTROLS, utf8_percent_encode};
|
|
|
use reqwest::Client;
|
|
use reqwest::Client;
|
|
|
|
|
+use reqwest::header::HeaderMap;
|
|
|
|
|
+use ring::hmac;
|
|
|
use rust_decimal::Decimal;
|
|
use rust_decimal::Decimal;
|
|
|
use rust_decimal::prelude::FromPrimitive;
|
|
use rust_decimal::prelude::FromPrimitive;
|
|
|
use rust_decimal_macros::dec;
|
|
use rust_decimal_macros::dec;
|
|
|
-use serde_json::Value;
|
|
|
|
|
|
|
+use serde_json::{Map, Value};
|
|
|
|
|
+use sha2::Sha256;
|
|
|
|
|
+use tracing::{error, info, trace};
|
|
|
|
|
+
|
|
|
use crate::http_tool::RestTool;
|
|
use crate::http_tool::RestTool;
|
|
|
use crate::response_base::ResponseData;
|
|
use crate::response_base::ResponseData;
|
|
|
-use sha2::Sha512;
|
|
|
|
|
-use tracing::{error, info, trace};
|
|
|
|
|
|
|
+
|
|
|
|
|
+// 定义用于 URL 编码的字符集
|
|
|
|
|
+const FRAGMENT: &AsciiSet = &CONTROLS
|
|
|
|
|
+ .add(b' ')
|
|
|
|
|
+ .add(b':')
|
|
|
|
|
+ .add(b'=')
|
|
|
|
|
+ .add(b'+')
|
|
|
|
|
+// .add(b'/').add(b'?').add(b'#')
|
|
|
|
|
+// .add(b'[').add(b']').add(b'@').add(b'!').add(b'$').add(b'&')
|
|
|
|
|
+// .add(b'\'').add(b'(').add(b')').add(b'*').add(b',')
|
|
|
|
|
+// .add(b';').add(b'"').add(b'%')
|
|
|
|
|
+;
|
|
|
|
|
+
|
|
|
|
|
|
|
|
#[derive(Clone)]
|
|
#[derive(Clone)]
|
|
|
pub struct HtxSwapRest {
|
|
pub struct HtxSwapRest {
|
|
@@ -62,110 +79,70 @@ impl HtxSwapRest {
|
|
|
let data = self.request("GET".to_string(),
|
|
let data = self.request("GET".to_string(),
|
|
|
"/api/v1".to_string(),
|
|
"/api/v1".to_string(),
|
|
|
format!("/timestamp"),
|
|
format!("/timestamp"),
|
|
|
|
|
+ false,
|
|
|
|
|
+ params,
|
|
|
|
|
+ ).await;
|
|
|
|
|
+ data
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ //查询合约账户(【全仓】获取用户账户信息)
|
|
|
|
|
+ pub async fn get_account(&mut self) -> ResponseData {
|
|
|
|
|
+ let params = serde_json::json!({
|
|
|
|
|
+ "valuation_asset":"USDT"
|
|
|
|
|
+ });
|
|
|
|
|
+ let data = self.request("POST".to_string(),
|
|
|
|
|
+ "/linear-swap-api/v1".to_string(),
|
|
|
|
|
+ format!("/swap_balance_valuation"),
|
|
|
true,
|
|
true,
|
|
|
- params.to_string(),
|
|
|
|
|
|
|
+ params,
|
|
|
).await;
|
|
).await;
|
|
|
data
|
|
data
|
|
|
}
|
|
}
|
|
|
- //
|
|
|
|
|
- // //查询个人交易费率
|
|
|
|
|
- // pub async fn wallet_fee(&mut self) -> ResponseData {
|
|
|
|
|
- // let params = serde_json::json!({
|
|
|
|
|
- // });
|
|
|
|
|
- // let data = self.request("GET".to_string(),
|
|
|
|
|
- // "/api/v4".to_string(),
|
|
|
|
|
- // format!("/wallet/fee"),
|
|
|
|
|
- // true,
|
|
|
|
|
- // params.to_string(),
|
|
|
|
|
- // ).await;
|
|
|
|
|
- // data
|
|
|
|
|
- // }
|
|
|
|
|
- // //查询合约账户
|
|
|
|
|
- // pub async fn get_account(&mut self, settle: String) -> ResponseData {
|
|
|
|
|
- // let params = serde_json::json!({
|
|
|
|
|
- // });
|
|
|
|
|
- // let data = self.request("GET".to_string(),
|
|
|
|
|
- // "/api/v4".to_string(),
|
|
|
|
|
- // format!("/futures/{}/accounts", settle),
|
|
|
|
|
- // true,
|
|
|
|
|
- // params.to_string(),
|
|
|
|
|
- // ).await;
|
|
|
|
|
- // data
|
|
|
|
|
- // }
|
|
|
|
|
- // //用户仓位列表
|
|
|
|
|
- // pub async fn get_user_position(&mut self, settle: String) -> ResponseData {
|
|
|
|
|
- // let params = serde_json::json!({
|
|
|
|
|
- // });
|
|
|
|
|
- // let data = self.request("GET".to_string(),
|
|
|
|
|
- // "/api/v4".to_string(),
|
|
|
|
|
- // format!("/futures/{}/positions", settle),
|
|
|
|
|
- // true,
|
|
|
|
|
- // params.to_string(),
|
|
|
|
|
- // ).await;
|
|
|
|
|
- // data
|
|
|
|
|
- // }
|
|
|
|
|
- // //双仓模式下的持仓信息
|
|
|
|
|
- // pub async fn get_position(&mut self, settle: String, contract: String) -> ResponseData {
|
|
|
|
|
- // let params = serde_json::json!({
|
|
|
|
|
- // });
|
|
|
|
|
- // let data = self.request("GET".to_string(),
|
|
|
|
|
- // "/api/v4".to_string(),
|
|
|
|
|
- // format!("/futures/{}/dual_comp/positions/{}", settle, contract),
|
|
|
|
|
- // true,
|
|
|
|
|
- // params.to_string(),
|
|
|
|
|
- // ).await;
|
|
|
|
|
- // data
|
|
|
|
|
- // }
|
|
|
|
|
- // //获取所有合约交易行情统计
|
|
|
|
|
- // pub async fn get_ticker(&mut self, settle: String) -> ResponseData {
|
|
|
|
|
- // let params = serde_json::json!({
|
|
|
|
|
- // });
|
|
|
|
|
- // let data = self.request("GET".to_string(),
|
|
|
|
|
- // "/api/v4".to_string(),
|
|
|
|
|
- // format!("/futures/{}/tickers", settle),
|
|
|
|
|
- // true,
|
|
|
|
|
- // params.to_string(),
|
|
|
|
|
- // ).await;
|
|
|
|
|
- // data
|
|
|
|
|
- // }
|
|
|
|
|
- // //查询所有的合约信息
|
|
|
|
|
- // pub async fn get_market_details(&mut self, settle: String) -> ResponseData {
|
|
|
|
|
- // let params = serde_json::json!({
|
|
|
|
|
- // });
|
|
|
|
|
- // let data = self.request("GET".to_string(),
|
|
|
|
|
- // "/api/v4".to_string(),
|
|
|
|
|
- // format!("/futures/{}/contracts", settle),
|
|
|
|
|
- // true,
|
|
|
|
|
- // params.to_string(),
|
|
|
|
|
- // ).await;
|
|
|
|
|
- // data
|
|
|
|
|
- // }
|
|
|
|
|
- // //查询单个订单详情
|
|
|
|
|
- // pub async fn get_order_details(&mut self, settle: String, order_id: String) -> ResponseData {
|
|
|
|
|
- // let params = serde_json::json!({
|
|
|
|
|
- // });
|
|
|
|
|
- // let data = self.request("GET".to_string(),
|
|
|
|
|
- // "/api/v4".to_string(),
|
|
|
|
|
- // format!("/futures/{}/orders/{}", settle, order_id),
|
|
|
|
|
- // true,
|
|
|
|
|
- // params.to_string(),
|
|
|
|
|
- // ).await;
|
|
|
|
|
- // data
|
|
|
|
|
- // }
|
|
|
|
|
- // //查询合约订单列表
|
|
|
|
|
- // pub async fn get_orders(&mut self, settle: String, status: String) -> ResponseData {
|
|
|
|
|
- // let params = serde_json::json!({
|
|
|
|
|
- // "status":status
|
|
|
|
|
- // });
|
|
|
|
|
- // let data = self.request("GET".to_string(),
|
|
|
|
|
- // "/api/v4".to_string(),
|
|
|
|
|
- // format!("/futures/{}/orders", settle),
|
|
|
|
|
- // true,
|
|
|
|
|
- // params.to_string(),
|
|
|
|
|
- // ).await;
|
|
|
|
|
- // data
|
|
|
|
|
- // }
|
|
|
|
|
- //
|
|
|
|
|
|
|
+
|
|
|
|
|
+ //用户仓位列表(【全仓】获取用户持仓信息)
|
|
|
|
|
+ pub async fn get_user_position(&mut self) -> ResponseData {
|
|
|
|
|
+ let params = serde_json::json!({
|
|
|
|
|
+ "contract_type":"swap"
|
|
|
|
|
+ });
|
|
|
|
|
+ let data = self.request("POST".to_string(),
|
|
|
|
|
+ "/linear-swap-api/v1".to_string(),
|
|
|
|
|
+ format!("/swap_cross_position_info"),
|
|
|
|
|
+ true,
|
|
|
|
|
+ params,
|
|
|
|
|
+ ).await;
|
|
|
|
|
+ data
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ //查询合约订单列表 (【全仓】获取合约订单信息)
|
|
|
|
|
+ pub async fn get_orders(&mut self, order_id: String) -> ResponseData {
|
|
|
|
|
+ let mut params = serde_json::json!({
|
|
|
|
|
+ });
|
|
|
|
|
+ if order_id.len() > 0 {
|
|
|
|
|
+ params.as_object_mut().unwrap().insert("order_id".to_string(), Value::from(order_id.clone()));
|
|
|
|
|
+ }
|
|
|
|
|
+ let data = self.request("POST".to_string(),
|
|
|
|
|
+ "/linear-swap-api/v1".to_string(),
|
|
|
|
|
+ format!("/swap_cross_order_info"),
|
|
|
|
|
+ true,
|
|
|
|
|
+ params,
|
|
|
|
|
+ ).await;
|
|
|
|
|
+ data
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ //查询单个订单详情 (【全仓】获取订单明细信息)
|
|
|
|
|
+ pub async fn get_order_details(&mut self,order_id: String) -> ResponseData {
|
|
|
|
|
+ let params = serde_json::json!({
|
|
|
|
|
+ });
|
|
|
|
|
+ let data = self.request("POST".to_string(),
|
|
|
|
|
+ "/linear-swap-api/v1".to_string(),
|
|
|
|
|
+ format!("/swap_cross_order_detail"),
|
|
|
|
|
+ true,
|
|
|
|
|
+ params,
|
|
|
|
|
+ ).await;
|
|
|
|
|
+ data
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
// //下单:side-下单方向,pos_side-持仓方向
|
|
// //下单:side-下单方向,pos_side-持仓方向
|
|
|
// pub async fn order(&mut self,
|
|
// pub async fn order(&mut self,
|
|
|
// settle: String,
|
|
// settle: String,
|
|
@@ -426,14 +403,13 @@ impl HtxSwapRest {
|
|
|
self.avg_delay = (sum_v / len_v).round_dp(1);
|
|
self.avg_delay = (sum_v / len_v).round_dp(1);
|
|
|
self.delays = last_100.clone().into_iter().collect();
|
|
self.delays = last_100.clone().into_iter().collect();
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
//调用请求
|
|
//调用请求
|
|
|
async fn request(&mut self,
|
|
async fn request(&mut self,
|
|
|
requesst_type: String,
|
|
requesst_type: String,
|
|
|
prefix_url: String,
|
|
prefix_url: String,
|
|
|
request_url: String,
|
|
request_url: String,
|
|
|
is_login: bool,
|
|
is_login: bool,
|
|
|
- params: String) -> ResponseData
|
|
|
|
|
|
|
+ params: Value) -> ResponseData
|
|
|
{
|
|
{
|
|
|
// trace!("login_param:{:?}", self.login_param);
|
|
// trace!("login_param:{:?}", self.login_param);
|
|
|
//解析账号信息
|
|
//解析账号信息
|
|
@@ -452,7 +428,6 @@ impl HtxSwapRest {
|
|
|
|
|
|
|
|
//请求头配置-如果需要登录则存在额外配置
|
|
//请求头配置-如果需要登录则存在额外配置
|
|
|
let mut body = "".to_string();
|
|
let mut body = "".to_string();
|
|
|
- let timestamp = chrono::Utc::now().timestamp().to_string();
|
|
|
|
|
|
|
|
|
|
let mut headers = HeaderMap::new();
|
|
let mut headers = HeaderMap::new();
|
|
|
if requesst_type == "GET" {
|
|
if requesst_type == "GET" {
|
|
@@ -463,28 +438,56 @@ impl HtxSwapRest {
|
|
|
headers.insert("Content-Type", "application/json".parse().unwrap());
|
|
headers.insert("Content-Type", "application/json".parse().unwrap());
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if requesst_type == "POST" {
|
|
|
|
|
- body = params.clone();
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
|
|
+ let utc_now = Utc::now();
|
|
|
|
|
+ let mut timestamp = utc_now.format("%Y-%m-%dT%H:%M:%S").to_string();
|
|
|
|
|
+ let mut params_str = "".to_string();
|
|
|
//是否需要登录-- 组装sing
|
|
//是否需要登录-- 组装sing
|
|
|
|
|
+ let mut sing = "".to_string();
|
|
|
if is_login {
|
|
if is_login {
|
|
|
if !is_login_param {
|
|
if !is_login_param {
|
|
|
let e = ResponseData::error(self.label.clone(), "登录参数错误!".to_string());
|
|
let e = ResponseData::error(self.label.clone(), "登录参数错误!".to_string());
|
|
|
return e;
|
|
return e;
|
|
|
} else {//需要登录-且登录参数齐全
|
|
} else {//需要登录-且登录参数齐全
|
|
|
|
|
+ let mut login_param = serde_json::json!({});
|
|
|
|
|
+ login_param["AccessKeyId"] = Value::from(access_key);
|
|
|
|
|
+ login_param["SignatureMethod"] = Value::from("HmacSHA256");
|
|
|
|
|
+ login_param["SignatureVersion"] = Value::from("2");
|
|
|
|
|
+ login_param["Timestamp"] = Value::from(timestamp);
|
|
|
|
|
+
|
|
|
|
|
+ //如果是get 所有参所也要参与校验,如果是post 只有校验参数需要校验
|
|
|
|
|
+ let mut verify_param = serde_json::json!({});
|
|
|
|
|
+ if requesst_type == "GET" {
|
|
|
|
|
+ merge_json(&mut verify_param, ¶ms);
|
|
|
|
|
+ merge_json(&mut verify_param, &login_param);
|
|
|
|
|
+ body = "{}".to_string();
|
|
|
|
|
+ } else if (requesst_type == "POST") {
|
|
|
|
|
+ merge_json(&mut verify_param, &login_param);
|
|
|
|
|
+ body = params.to_string();
|
|
|
|
|
+ }
|
|
|
|
|
+ trace!("需要校验参数:\n{}", verify_param.to_string());
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+ //4. ASCII码的顺序对参数名进行排序
|
|
|
|
|
+ // let sorted_params = sort_json_keys(params);
|
|
|
|
|
+ // let params_str_sort = format!("{}", serde_json::to_string_pretty(&sorted_params).unwrap());
|
|
|
|
|
+ // trace!("排序后的参数:\n{}", params_str_sort);
|
|
|
|
|
+ let verify_param_str = json_to_query_string(verify_param);
|
|
|
|
|
+ trace!("排序后的拼接参数:\n{}", verify_param_str);
|
|
|
|
|
+ params_str = verify_param_str.to_string().clone();
|
|
|
|
|
+
|
|
|
//组装sing
|
|
//组装sing
|
|
|
- let sing = Self::sign(secret_key.clone(),
|
|
|
|
|
- requesst_type.clone(),
|
|
|
|
|
- prefix_url.clone(),
|
|
|
|
|
- request_url.clone(),
|
|
|
|
|
- params.clone(),
|
|
|
|
|
- body.clone(),
|
|
|
|
|
- timestamp.clone(),
|
|
|
|
|
|
|
+ sing = Self::sign(secret_key.clone(),
|
|
|
|
|
+ requesst_type.clone(),
|
|
|
|
|
+ prefix_url.clone(),
|
|
|
|
|
+ request_url.clone(),
|
|
|
|
|
+ verify_param_str.clone(),
|
|
|
);
|
|
);
|
|
|
- // trace!("sing:{}", sing);
|
|
|
|
|
- //组装header
|
|
|
|
|
- headers.extend(Self::headers(access_key, timestamp, sing));
|
|
|
|
|
|
|
+ // sing = utf8_percent_encode(sing.as_str(), FRAGMENT).to_string();
|
|
|
|
|
+ // sing = sing.to_uppercase();
|
|
|
|
|
+ trace!("sing:{}", sing);
|
|
|
|
|
+ // ?AccessKeyId=e2xxxxxx-99xxxxxx-84xxxxxx-7xxxx&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2017-05-11T15%3A19%3A30&Signature= 4F65x5A2bLyMWVQj3Aqp%2BB4w%2BivaA7n5Oi2SuYtCJ9o%3D
|
|
|
|
|
+ // ?AccessKeyId=58edb6bb-qz5c4v5b6n-24498508-c5919&SignatureMethod=HmacSHA256&SignatureVersion=2&Timestamp=2024-04-29T07%3A26%3A39&Signature= R0SAEWSEC+A6HS5URSHZIFOZBYQBRCLH0DTDSAL0HLS=
|
|
|
|
|
+ // 4F65x5A2bLyMWVQj3Aqp+B4w+ivaA7n5Oi2SuYtCJ9o=
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -494,7 +497,9 @@ impl HtxSwapRest {
|
|
|
let response = self.http_tool(
|
|
let response = self.http_tool(
|
|
|
base_url.clone(),
|
|
base_url.clone(),
|
|
|
requesst_type.to_string(),
|
|
requesst_type.to_string(),
|
|
|
- params.clone(),
|
|
|
|
|
|
|
+ params_str,
|
|
|
|
|
+ body.clone(),
|
|
|
|
|
+ sing.clone(),
|
|
|
headers,
|
|
headers,
|
|
|
).await;
|
|
).await;
|
|
|
|
|
|
|
@@ -507,55 +512,60 @@ impl HtxSwapRest {
|
|
|
|
|
|
|
|
pub fn headers(access_key: String, timestamp: String, sign: String) -> HeaderMap {
|
|
pub fn headers(access_key: String, timestamp: String, sign: String) -> HeaderMap {
|
|
|
let mut headers = HeaderMap::new();
|
|
let mut headers = 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.insert("KEY", access_key.clone().parse().unwrap());
|
|
|
|
|
+ // headers.insert("Timestamp", timestamp.clone().parse().unwrap());
|
|
|
|
|
+ // headers.insert("SIGN", sign.clone().parse().unwrap());
|
|
|
headers
|
|
headers
|
|
|
}
|
|
}
|
|
|
- pub fn sign(secret_key: String,
|
|
|
|
|
- requesst_type: String, prefix_url: String, request_url: String,
|
|
|
|
|
- params: String, body_data: String, timestamp: String) -> String
|
|
|
|
|
|
|
+ pub fn sign(secret_key: String, requesst_type: String,
|
|
|
|
|
+ prefix_url: String, request_url: String,
|
|
|
|
|
+ verify_param: String) -> String
|
|
|
{
|
|
{
|
|
|
- let url = format!("{}{}", prefix_url, request_url);
|
|
|
|
|
- let params_str = RestTool::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{}",
|
|
|
|
|
- requesst_type,
|
|
|
|
|
- url,
|
|
|
|
|
- params_str,
|
|
|
|
|
- hashed_payload,
|
|
|
|
|
- timestamp);
|
|
|
|
|
|
|
+ let mut message = format!("{}\napi.hbdm.com\n{}{}\n{}",
|
|
|
|
|
+ requesst_type,
|
|
|
|
|
+ prefix_url, request_url,
|
|
|
|
|
+ verify_param
|
|
|
|
|
+ );
|
|
|
// trace!("**********", );
|
|
// trace!("**********", );
|
|
|
- // trace!("组装数据:{}", message);
|
|
|
|
|
|
|
+ trace!("组装数据:\n{}", message);
|
|
|
// trace!("**********", );
|
|
// 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);
|
|
|
|
|
|
|
+ let hmac_key = hmac::Key::new(hmac::HMAC_SHA256, secret_key.as_bytes());
|
|
|
|
|
+ let result = hmac::sign(&hmac_key, &message.as_bytes());
|
|
|
|
|
+ let sign = base64::encode(result);
|
|
|
sign
|
|
sign
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
- async fn http_tool(&mut self, request_path: String, request_type: String, params: String, headers: HeaderMap) -> ResponseData {
|
|
|
|
|
|
|
+ async fn http_tool(&mut self, request_path: String,
|
|
|
|
|
+ request_type: String,
|
|
|
|
|
+ params: String,
|
|
|
|
|
+ body: String,
|
|
|
|
|
+ sing: String, headers: HeaderMap) -> ResponseData {
|
|
|
/****请求接口与 地址*/
|
|
/****请求接口与 地址*/
|
|
|
let url = format!("{}{}", self.base_url.to_string(), request_path);
|
|
let url = format!("{}{}", self.base_url.to_string(), request_path);
|
|
|
let request_type = request_type.clone().to_uppercase();
|
|
let request_type = request_type.clone().to_uppercase();
|
|
|
- let addrs_url = format!("{}?{}", url.clone(), RestTool::parse_params_to_str(params.clone()));
|
|
|
|
|
|
|
+ let params_str = if sing.len() > 0 {
|
|
|
|
|
+ format!("{}&Signature={}", params.clone(), sing)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ format!("{}", params.clone())
|
|
|
|
|
+ };
|
|
|
|
|
+ let addrs_url = if params_str.len() > 0 {
|
|
|
|
|
+ format!("{}?{}", url.clone(), params_str)
|
|
|
|
|
+ } else {
|
|
|
|
|
+ format!("{}", url.clone())
|
|
|
|
|
+ };
|
|
|
|
|
+
|
|
|
|
|
+ trace!("url-----:???{}",url.clone());
|
|
|
|
|
+ trace!("addrs_url-----:???{}",addrs_url.clone());
|
|
|
|
|
+ trace!("param-----:???{}",params.clone());
|
|
|
|
|
+ trace!("param_str-----:???{}",params_str.clone());
|
|
|
|
|
+ trace!("body-----:???{}",body.clone());
|
|
|
|
|
|
|
|
let request_builder = match request_type.as_str() {
|
|
let request_builder = match request_type.as_str() {
|
|
|
"GET" => self.client.get(addrs_url.clone()).headers(headers),
|
|
"GET" => self.client.get(addrs_url.clone()).headers(headers),
|
|
|
- "POST" => self.client.post(addrs_url.clone()).body(params.clone()).headers(headers),
|
|
|
|
|
- "DELETE" => self.client.delete(addrs_url.clone()).headers(headers),
|
|
|
|
|
|
|
+ "POST" => self.client.post(addrs_url.clone()).body(body).headers(headers),
|
|
|
|
|
+ // "DELETE" => self.client.delete(addrs_url.clone()).headers(headers),
|
|
|
// "PUT" => self.client.put(url.clone()).json(¶ms),
|
|
// "PUT" => self.client.put(url.clone()).json(¶ms),
|
|
|
_ => {
|
|
_ => {
|
|
|
panic!("{}", format!("错误的请求类型:{}", request_type.clone()))
|
|
panic!("{}", format!("错误的请求类型:{}", request_type.clone()))
|
|
@@ -575,9 +585,22 @@ impl HtxSwapRest {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
pub fn on_success_data(&mut self, text: &String) -> ResponseData {
|
|
pub fn on_success_data(&mut self, text: &String) -> ResponseData {
|
|
|
- let data = serde_json::from_str(text.as_str()).unwrap();
|
|
|
|
|
-
|
|
|
|
|
- ResponseData::new(self.label.clone(), 200, "success".to_string(), data)
|
|
|
|
|
|
|
+ let json_value = serde_json::from_str::<Value>(&text).unwrap();
|
|
|
|
|
+ let status = json_value["status"].as_str().unwrap();
|
|
|
|
|
+ match status {
|
|
|
|
|
+ "ok" => {
|
|
|
|
|
+ //判断是否有code ,没有表示特殊接口,直接返回
|
|
|
|
|
+ if json_value.get("data").is_some() {
|
|
|
|
|
+ let data = json_value.get("data").unwrap();
|
|
|
|
|
+ ResponseData::new(self.label.clone(), 200, "success".to_string(), data.clone())
|
|
|
|
|
+ } else {
|
|
|
|
|
+ ResponseData::new(self.label.clone(), 200, "success".to_string(), json_value)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ _ => {
|
|
|
|
|
+ ResponseData::new(self.label.clone(), 400, "error".to_string(), json_value)
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
pub fn on_error_data(&mut self, text: &String, base_url: &String, params: &String) -> ResponseData {
|
|
pub fn on_error_data(&mut self, text: &String, base_url: &String, params: &String) -> ResponseData {
|
|
@@ -605,4 +628,77 @@ impl HtxSwapRest {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+//对 json 的数据进行 排序
|
|
|
|
|
+fn sort_json_object(value: &Value) -> Value {
|
|
|
|
|
+ match value {
|
|
|
|
|
+ Value::Object(obj) => {
|
|
|
|
|
+ let mut map = BTreeMap::new();
|
|
|
|
|
+ for (k, v) in obj {
|
|
|
|
|
+ // 注意这里使用了clone()来获取键的所有权
|
|
|
|
|
+ map.insert(k.clone(), sort_json_object(v));
|
|
|
|
|
+ }
|
|
|
|
|
+ // 将BTreeMap转换为Map<String, Value>,确保键类型正确
|
|
|
|
|
+ Value::Object(map.into_iter().collect::<Map<String, Value>>())
|
|
|
|
|
+ }
|
|
|
|
|
+ Value::Array(arr) => {
|
|
|
|
|
+ // 对数组中的每个元素递归排序
|
|
|
|
|
+ Value::Array(arr.iter().map(sort_json_object).collect())
|
|
|
|
|
+ }
|
|
|
|
|
+ // 其他类型的Value不需要排序,直接返回
|
|
|
|
|
+ _ => value.clone(),
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+
|
|
|
|
|
+// 合并两个 JSON 对象的函数
|
|
|
|
|
+fn merge_json(a: &mut Value, b: &Value) {
|
|
|
|
|
+ match (a, b) {
|
|
|
|
|
+ (Value::Object(ref mut a_map), Value::Object(b_map)) => {
|
|
|
|
|
+ for (k, v) in b_map {
|
|
|
|
|
+ merge_json(a_map.entry(k.clone()).or_insert(Value::Null), v);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ (a, b) => {
|
|
|
|
|
+ *a = b.clone();
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 函数:将 JSON 对象的键按 ASCII 码排序
|
|
|
|
|
+fn sort_json_keys(value: Value) -> Value {
|
|
|
|
|
+ match value {
|
|
|
|
|
+ Value::Object(obj) => {
|
|
|
|
|
+ let mut map = BTreeMap::new();
|
|
|
|
|
+ for (k, v) in obj {
|
|
|
|
|
+ map.insert(k, sort_json_keys(v));
|
|
|
|
|
+ }
|
|
|
|
|
+ Value::Object(map.into_iter().collect::<Map<String, Value>>())
|
|
|
|
|
+ }
|
|
|
|
|
+ _ => value,
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+// 函数:将 JSON 对象转换为排序后的查询字符串
|
|
|
|
|
+fn json_to_query_string(value: Value) -> String {
|
|
|
|
|
+ let mut params = BTreeMap::new();
|
|
|
|
|
+
|
|
|
|
|
+ if let Value::Object(obj) = value {
|
|
|
|
|
+ for (k, v) in obj {
|
|
|
|
|
+ // 确保只处理字符串值
|
|
|
|
|
+ if let Value::String(v_str) = v {
|
|
|
|
|
+ params.insert(k, v_str);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // 对于非字符串值,我们可以转换为字符串或执行其他处理
|
|
|
|
|
+ params.insert(k, v.to_string());
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 拼接键值对为查询字符串
|
|
|
|
|
+ params.iter()
|
|
|
|
|
+ .map(|(k, v)| format!("{}={}", utf8_percent_encode(k, FRAGMENT), utf8_percent_encode(v, FRAGMENT)))
|
|
|
|
|
+ .collect::<Vec<String>>()
|
|
|
|
|
+ .join("&")
|
|
|
}
|
|
}
|