Explorar o código

rest基本搞定,但是还需要封装,并且要搞懂怎么发的消息

skyfffire hai 3 semanas
pai
achega
3959f423f6

+ 17 - 0
src/exchange/extended_account.rs

@@ -3,4 +3,21 @@ pub struct ExtendedAccount {
     // pub access_key: String,
     // pub secret_key: String,
     // pub pass_key: String,
+    pub api_key: String,
+}
+
+impl ExtendedAccount {
+    pub fn new(api_key: String) -> Self {
+        ExtendedAccount {
+            api_key,
+        }
+    }
+    
+    pub fn is_available(&self) -> bool {
+        if self.api_key.is_empty() {
+            return false;
+        }
+        
+        true
+    }
 }

+ 241 - 0
src/exchange/extended_rest_client.rs

@@ -0,0 +1,241 @@
+use reqwest::Client;
+use reqwest::header::HeaderMap;
+use serde_json::{json, Value};
+use tracing::{error, info};
+use crate::exchange::extended_account::ExtendedAccount;
+use crate::utils::response::Response;
+use crate::utils::rest_utils::RestUtils;
+
+pub struct ExtendedRestClient {
+    pub tag: String,
+
+    // 一些私有变量
+    base_url: String,
+    client: Client,
+    account: Option<ExtendedAccount>,
+
+    // 延迟统计工具
+    delays: Vec<i64>,
+    max_delay: i64,
+    avg_delay: i64,
+}
+
+impl ExtendedRestClient {
+    pub fn new(tag: String, account: Option<ExtendedAccount>) -> Self {
+        ExtendedRestClient {
+            tag,
+            base_url: "https://api.starknet.extended.exchange".to_string(),
+            // base_url: "https://api.starknet.sepolia.extended.exchange".to_string(),
+            client: Client::new(),
+            account,
+
+            delays: vec![],
+            max_delay: 0,
+            avg_delay: 0,
+        }
+    }
+
+    // =================================== 公共方法区 ====================================
+
+    // =================================== 私有方法区,这边仅需要携带header ====================================
+    pub async fn cancel_order(&mut self, external_id: String) -> Response {
+        let params = json!({
+            "external_id": external_id,
+        });
+
+        self.request("DELETE".to_string(),
+                     "/api/v1/user".to_string(),
+                     "/order".to_string(),
+                     true,
+                     false,
+                     params,
+        ).await
+    }
+    // =================================== 签名方法区,这边需要签名=========================
+
+    // =================================== 网络层基础 ====================================
+    // 发送请求
+    pub async fn request(&mut self,
+                         method: String,
+                         prefix_url: String,
+                         request_url: String,
+                         is_private: bool,
+                         _is_sign: bool,
+                         mut params: Value) -> Response
+    {
+        // ----------------- 每个接口都有的公共参数 ------------------
+        // let timestamp = Utc::now().timestamp_millis();
+        // let recv_window = 3000;
+        // params["timestamp"] = serde_json::json!(timestamp);
+        // params["recvWindow"] = serde_json::json!(recv_window);
+
+
+        // ------------------- 请求头填充 --------------------------
+        let mut headers = HeaderMap::new();
+        headers.insert("User-Agent", "RustClient/1.0".parse().unwrap());
+
+        // ---------------- 请求类型不同,可能请求头body不同 ----------
+        let mut body = "{}".to_string();
+
+        if method == "POST" {
+            headers.insert("Content-Type", "application/json".parse().unwrap());
+            body = params.to_string();
+        }
+
+        // ---------------- 签名操作等等 ----------------------------
+        if is_private {
+            if self.account.is_none() {
+                let e = Response::error(self.tag.clone(), "需要补齐登录参数".to_string());
+                return e;
+            } else {
+                // 进行签名等操作
+                headers.insert("X-Api-Key", self.account.clone().unwrap().api_key.parse().unwrap());
+
+                // //组装sing
+                // let sing = Self::sign(secret_key.clone(),
+                //                       method.clone(),
+                //                       prefix_url.clone(),
+                //                       request_url.clone(),
+                //                       params.clone(),
+                //                       body.clone(),
+                //                       timestamp.clone(),
+                // );
+                // //组装header
+                // headers.extend(Self::headers(sing, timestamp, passphrase, access_key));
+            }
+        }
+
+        // --------------------- 最终发送 ---------------------------
+        let start_time = chrono::Utc::now().timestamp_millis();
+        let response = self.do_request(
+            format!("{}{}", prefix_url.clone(), request_url.clone()),
+            method.to_string(),
+            params.to_string(),
+            body,
+            headers,
+        ).await;
+
+        let time_array = chrono::Utc::now().timestamp_millis() - start_time;
+        self.delays.push(time_array);
+        self.get_delay_info();
+
+        response
+    }
+
+    async fn do_request(&mut self, request_path: String,
+                        request_type: String,
+                        params: String,
+                        body: String,
+                        headers: HeaderMap) -> Response {
+        let url = format!("{}{}", self.base_url.to_string(), request_path);
+        let request_type = request_type.clone().to_uppercase();
+
+        let params_str = RestUtils::parse_params_to_str(params.clone());
+        let addrs_url: String = if params_str == "" {
+            url.clone()
+        } else {
+            format!("{}?{}", url.clone(), params_str)
+        };
+
+        let request_builder = match request_type.as_str() {
+            "GET" => self.client.get(addrs_url.clone()).headers(headers),
+            "POST" => self.client.post(url.clone()).body(body).headers(headers),
+            "DELETE" => self.client.delete(addrs_url.clone()).headers(headers),
+            "PUT" => self.client.put(url.clone()).json(&params),
+            _ => {
+                panic!("{}", format!("错误的请求类型:{}", request_type.clone()))
+            }
+        };
+
+        // 读取响应的内容
+        let response = request_builder.send().await.unwrap();
+        // 先检查状态码
+        let is_success = response.status().is_success();
+        let text = response.text().await.unwrap();
+        
+        info!(text);
+
+        if is_success {
+            self.on_success_data(&text)
+        } else {
+            self.on_error_data(&text, &addrs_url, &params)
+        }
+    }
+
+    pub fn on_success_data(&mut self, text: &String) -> Response {
+        let json_value = serde_json::from_str::<Value>(&text).unwrap();
+        Response::new(self.tag.clone(), 200, "success".to_string(), json_value)
+    }
+
+    pub fn on_error_data(&mut self, text: &String, base_url: &String, params: &String) -> Response {
+        let json_value = serde_json::from_str::<Value>(&text);
+
+        match json_value {
+            Ok(data) => {
+                let message;
+
+                if !data["message"].is_null() {
+                    message = format!("{}:{}", data["tag"].as_str().unwrap(), data["message"].as_str().unwrap());
+                } else {
+                    message = data["tag"].to_string();
+                }
+
+                let mut error = Response::error(self.tag.clone(), message);
+                error.message = format!("请求地址:{}, 请求参数:{}, 报错内容:{}。", base_url, params, error.message);
+                error
+            }
+            Err(e) => {
+                error!("解析错误:{:?}", e);
+                let error = Response::error("".to_string(), text.clone());
+                error
+            }
+        }
+    }
+
+    // =================================== 延迟统计相关 ==================================
+    pub fn get_delays(&self) -> Vec<i64> {
+        self.delays.clone()
+    }
+    pub fn get_avg_delay(&self) -> i64 {
+        self.avg_delay.clone()
+    }
+    pub fn get_max_delay(&self) -> i64 {
+        self.max_delay.clone()
+    }
+    fn get_delay_info(&mut self) {
+        let last_100 = if self.delays.len() > 100 {
+            self.delays[self.delays.len() - 100..].to_vec()
+        } else {
+            self.delays.clone()
+        };
+
+        let max_value = last_100.iter().max().unwrap();
+        if max_value.clone().to_owned() > self.max_delay {
+            self.max_delay = max_value.clone().to_owned();
+        }
+
+        let sum: i64 = last_100.iter().sum();
+        let len = last_100.len() as i64;
+        self.avg_delay = sum / len;
+        self.delays = last_100.clone().into_iter().collect();
+    }
+}
+
+#[cfg(test)]
+mod tests {
+    use tracing::info;
+    use crate::exchange::extended_account::ExtendedAccount;
+    use crate::exchange::extended_rest_client::ExtendedRestClient;
+    use crate::utils::log_setup::setup_logging;
+
+    #[tokio::test]
+    async fn test_cancel_order() {
+        let _guard = setup_logging().unwrap();
+        let account = ExtendedAccount::new("a7b197d06d35de11387b8b71f34c87e4".to_string());
+        let mut client = ExtendedRestClient::new("Extended".to_string(), Some(account));
+        let response = client.cancel_order("123456".to_string()).await;
+
+        info!("{:?}", response);
+        info!("{}", serde_json::to_string_pretty(&response.data).unwrap());
+    }
+}

+ 2 - 1
src/exchange/mod.rs

@@ -1,2 +1,3 @@
 pub mod extended_stream_client;
-pub mod extended_account;
+pub mod extended_account;
+mod extended_rest_client;

+ 3 - 2
src/utils/lib.rs

@@ -5,10 +5,11 @@ use starknet::core::crypto::ecdsa_sign;
 use starknet::core::types::Felt;
 use std::str::FromStr;
 
-use crate::starknet_messages::{
+use crate::utils::starknet_messages::{
     AssetId, OffChainMessage, Order, PositionId, StarknetDomain, Timestamp, TransferArgs,
 };
-pub mod starknet_messages;
+use utils::starknet_messages;
+use crate::utils;
 
 pub struct StarkSignature {
     pub r: Felt,

+ 2 - 0
src/utils/mod.rs

@@ -3,3 +3,5 @@ pub mod rest_utils;
 pub mod stream_utils;
 pub(crate) mod response;
 pub(crate) mod proxy;
+mod starknet_messages;
+mod lib;