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, // 延迟统计工具 delays: Vec, max_delay: i64, avg_delay: i64, } impl ExtendedRestClient { pub fn new(tag: String, account: Option) -> 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(¶ms), _ => { 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, ¶ms) } } pub fn on_success_data(&mut self, text: &String) -> Response { let json_value = serde_json::from_str::(&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::(&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 { 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()); } }