Преглед изворни кода

修改以前老版本代码 并且测试

hl пре 1 година
родитељ
комит
e1676e5ea7

+ 132 - 268
exchanges/src/binance_spot_ws.rs

@@ -1,13 +1,15 @@
-use std::collections::BTreeMap;
 use std::sync::Arc;
 use std::sync::atomic::AtomicBool;
 
-use tokio::sync::mpsc::Sender;
+use futures_channel::mpsc::{UnboundedReceiver, UnboundedSender};
+use serde_json::json;
+use tokio::sync::Mutex;
+use tokio_tungstenite::tungstenite::{Error, Message};
 use tracing::{info, trace};
 
-use crate::proxy;
-use crate::proxy::ParsingDetail;
 use crate::response_base::ResponseData;
+use crate::socket_tool::{AbstractWsMode, HeartbeatType};
+use crate::utils::get_time_microsecond;
 
 pub enum BinanceSpotWsType {
     //订阅频道类型
@@ -22,68 +24,60 @@ pub enum BinanceSpotSubscribeType {
     PuDepth20levels100ms,
 }
 
+//账号信息
+#[derive(Clone)]
+#[allow(dead_code)]
+pub struct BinanceSpotLogin {
+    pub api_key: String,
+    pub api_secret: String,
+}
+
+
 #[derive(Clone)]
 #[allow(dead_code)]
 pub struct BinanceSpotWs {
-    pub label: String,
-    request_url: String,
-    //实际ws 链接地址
-    proxy: ParsingDetail,
+    //类型
+    label: String,
+    //地址
+    address_url: String,
     //账号信息
-    login_param: BTreeMap<String, String>,
-    //kuconis特殊参数
+    login_param: Option<BinanceSpotLogin>,
+    //币对
     symbol_s: Vec<String>,
-    //订阅币对
+    //订阅
     subscribe_types: Vec<BinanceSpotSubscribeType>,
-    //订阅信息
-    sender: Sender<ResponseData>,
-    //数据通道
+    //心跳间隔
+    heartbeat_time: u64,
 }
 
 impl BinanceSpotWs {
     /*******************************************************************************************************/
     /*****************************************获取一个对象****************************************************/
     /*******************************************************************************************************/
-    pub fn new(is_colo: bool,
-               login_param: BTreeMap<String, String>,
-               ws_type: BinanceSpotWsType,
-               sender: Sender<ResponseData>,
-    ) -> BinanceSpotWs
-    {
-        return BinanceSpotWs::new_label("default-BinanceSpotWs".to_string(), is_colo, login_param, ws_type, sender);
+    pub fn new(is_colo: bool, login_param: Option<BinanceSpotLogin>, ws_type: BinanceSpotWsType) -> BinanceSpotWs {
+        return BinanceSpotWs::new_label("default-BinanceSpotWs".to_string(), is_colo, login_param, ws_type);
     }
-    pub fn new_label(label: String, is_colo: bool,
-                     login_param: BTreeMap<String, String>,
-                     ws_type: BinanceSpotWsType,
-                     sender: Sender<ResponseData>,
-    ) -> BinanceSpotWs
-    {
-
-
-        /*******走代理:根据环境变量配置来决定,如果配置了走代理,没有配置不走*******/
-        let parsing_detail = proxy::ParsingDetail::parsing_environment_variables();
-
+    pub fn new_label(label: String, is_colo: bool, login_param: Option<BinanceSpotLogin>, ws_type: BinanceSpotWsType) -> BinanceSpotWs {
         /*******公共频道-私有频道数据组装*/
-        let request_url = match ws_type {
+        let address_url = match ws_type {
             BinanceSpotWsType::PublicAndPrivate => {
                 "wss://stream.binance.com:9443/ws".to_string()
             }
         };
 
         if is_colo {
-            info!("开启高速(未配置,走普通:{})通道",request_url);
-        }else{
-            info!("走普通通道:{}",request_url);
+            info!("开启高速(未配置,走普通:{})通道",address_url);
+        } else {
+            info!("走普通通道:{}",address_url);
         }
         /*****返回结构体*******/
         BinanceSpotWs {
             label,
-            request_url,
-            proxy: parsing_detail,
+            address_url,
             login_param,
             symbol_s: vec![],
             subscribe_types: vec![],
-            sender,
+            heartbeat_time: 1000 * 20,
         }
     }
 
@@ -94,28 +88,33 @@ impl BinanceSpotWs {
     pub fn set_subscribe(&mut self, subscribe_types: Vec<BinanceSpotSubscribeType>) {
         self.subscribe_types.extend(subscribe_types);
     }
-    //自定义
-    pub async fn custom_subscribe(&mut self, bool_v1: Arc<AtomicBool>, b_array: Vec<String>)
-    {
-        let mut symbol_s = b_array.clone();
-        for symbol in symbol_s.iter_mut() {
-            // 大写
+    //手动添加币对
+    pub fn set_symbols(&mut self, mut b_array: Vec<String>) {
+        for symbol in b_array.iter_mut() {
+            // 小写
             *symbol = symbol.to_lowercase();
             // 字符串替换
             *symbol = symbol.replace("_", "");
             *symbol = symbol.replace("-", "");
         }
-        self.symbol_s = symbol_s;
-        let log_in = self.login_param.clone();
-        trace!(?log_in);
-        self.run(bool_v1).await;
+        self.symbol_s = b_array;
+    }
+    //频道是否需要登录
+    fn contains_pr(&self) -> bool {
+        for t in self.subscribe_types.clone() {
+            if match t {
+                BinanceSpotSubscribeType::PuBookTicker => false,
+                BinanceSpotSubscribeType::PuAggTrade => false,
+                BinanceSpotSubscribeType::PuDepth20levels100ms => false,
+            } {
+                return true;
+            }
+        }
+        false
     }
-
     /*******************************************************************************************************/
     /*****************************************工具函数********************************************************/
     /*******************************************************************************************************/
-
-
     //订阅枚举解析
     pub fn enum_to_string(symbol: String, subscribe_type: BinanceSpotSubscribeType) -> String {
         match subscribe_type {
@@ -130,226 +129,110 @@ impl BinanceSpotWs {
             }
         }
     }
-    //组装订阅数据
-    pub fn get_subscription(&self) -> Vec<String> {
-        let mut args = vec![];
+    //订阅信息生成
+    pub fn get_subscription(&self) -> String {
+        let mut params = vec![];
         for symbol in &self.symbol_s {
             for subscribe_type in &self.subscribe_types {
                 let ty_str = Self::enum_to_string(symbol.clone(), subscribe_type.clone());
-                args.push(ty_str);
+                params.push(ty_str);
             }
         }
 
-        trace!("订阅信息:{:?}", args);
-        args
+        let str = json!({
+            "method": "SUBSCRIBE",
+            "params":  params,
+            "id": 1
+            });
+        str.to_string()
     }
-
     /*******************************************************************************************************/
     /*****************************************socket基本*****************************************************/
     /*******************************************************************************************************/
-    async fn run(&mut self, _bool_v1: Arc<AtomicBool>)
+    //链接
+    pub async fn ws_connect_async(&mut self,
+                                  bool_v1: Arc<AtomicBool>,
+                                  write_tx_am: &Arc<Mutex<UnboundedSender<Message>>>,
+                                  write_rx: UnboundedReceiver<Message>,
+                                  read_tx: UnboundedSender<ResponseData>) -> Result<(), Error>
     {
-        // //订阅信息组装
-        //
-        // let params = self.get_subscription();
-        // let subscription_str = if params.len() > 0 {
-        //     serde_json::json!({
-        //         "method": "SUBSCRIBE",
-        //         "params":serde_json::Value::from(params),
-        //         "id": 1
-        //     }).to_string()
-        // } else {
-        //     "".to_string()
-        // };
-        // trace!("订阅内容:{}",subscription_str);
-        //
-        // let request_url = self.request_url.clone();
-        // loop {
-        //     tokio::time::sleep(Duration::from_millis(5000)).await;
-        //     info!("要连接咯~~!!{}", request_url);
-        //     let request_url = Url::parse(request_url.as_str()).unwrap();
-        //     //1. 判断是否需要代理,根据代理地址是否存来选择
-        //     if self.proxy.ip_address.len() > 0 {
-        //         let ip_array: Vec<&str> = self.proxy.ip_address.split(".").collect();
-        //         let proxy_address = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(
-        //             ip_array[0].parse().unwrap(),
-        //             ip_array[1].parse().unwrap(),
-        //             ip_array[2].parse().unwrap(),
-        //             ip_array[3].parse().unwrap())
-        //         ), self.proxy.port.parse().unwrap());
-        //         let websocket_config = Some(WebSocketConfig {
-        //             max_send_queue: Some(16),
-        //             max_message_size: Some(16 * 1024 * 1024),
-        //             max_frame_size: Some(16 * 1024 * 1024),
-        //             accept_unmasked_frames: false,
-        //         });
-        //         let max_redirects = 5;
-        //         match connect_with_proxy(request_url.clone(),
-        //                                  proxy_address, websocket_config, max_redirects) {
-        //             Ok(ws) => {
-        //                 let bool_v1_clone = Arc::clone(&bool_v1);
-        //                 self.proxy_subscription(bool_v1_clone, ws.0, subscription_str.clone()).await;
-        //             }
-        //             Err(err) => {
-        //                 error!("Can't connect(无法连接): {}", err);
-        //             }
-        //         };
-        //     } else {
-        //         match connect(request_url.clone()) {
-        //             Ok(ws) => {
-        //                 let bool_v1_clone = Arc::clone(&bool_v1);
-        //                 self.subscription(bool_v1_clone, ws.0, subscription_str.clone()).await;
-        //             }
-        //             Err(err) => {
-        //                 // 连接失败时执行的操作
-        //                 error!("Can't connect(无法连接): {}", err);
-        //                 // 返回一个默认的 WebSocket 对象或其他适当的值
-        //                 // 或者根据需要触发 panic 或返回错误信息
-        //             }
-        //         };
-        //     }
-        //     trace!("退出来咯");
-        //
-        //     let bool_v1_clone = Arc::clone(&bool_v1);
-        //     let bool_v1_v = bool_v1_clone.load(Ordering::SeqCst);
-        //     if !bool_v1_v {
-        //         break;
-        //     }
-        // }
-    }
+        let login_is = self.contains_pr();
+        let subscription = self.get_subscription();
+        let address_url = self.address_url.clone();
+        let label = self.label.clone();
+        let heartbeat_time = self.heartbeat_time.clone();
 
-    //代理
-    #[allow(dead_code)]
-    async fn proxy_subscription(&self, _bool_v1: Arc<AtomicBool>,
-                                // mut web_socket: WebSocket<ProxyAutoStream>,
-                                _subscription: String)
-    {
-        // info!("走代理-链接成功!开始数据读取");
-        // let label = self.label.clone();
-        // /*****订阅消息**/
-        // if subscription.len() > 0 {
-        //     web_socket.write_message(Message::Text(subscription)).unwrap();
-        // }
-        // /*****消息溜***/
-        // loop {
-        //     // tokio::time::sleep(Duration::from_nanos(1)).await;
-        //     let msg = web_socket.read_message();
-        //     match msg {
-        //         Ok(Message::Text(text)) => {
-        //             // trace!("获取推送:{}",text.clone());
-        //             let mut res_data = Self::ok_text(label.to_string(), text);
-        //             res_data.time = get_time_microsecond();
-        //             if res_data.code == "-200" {
-        //                 trace!("订阅成功:{:?}", res_data.data);
-        //             } else {
-        //                 let sender = self.sender.clone();
-        //                 tokio::spawn(async move {
-        //                     sender.send(res_data).await.unwrap();
-        //                 });
-        //                 tokio::spawn(async move {});
-        //             }
-        //         }
-        //         Ok(Message::Ping(s)) => {
-        //             trace!( "Ping-响应--{:?}", String::from_utf8(s.clone()));
-        //             // let _ = web_socket.write_message(Message::Pong(Vec::from("pong")));
-        //             trace!( "回应-pong---{:?}", String::from_utf8(s.clone()));
-        //         }
-        //         Ok(Message::Pong(s)) => {
-        //             // trace!("Pong-响应--{:?}", String::from_utf8(s));
-        //             trace!( "Pong-响应--{:?}", String::from_utf8(s.clone()));
-        //         }
-        //         Ok(Message::Close(_)) => {
-        //             // trace!("socket 关闭: ");
-        //             trace!("Close-响应");
-        //         }
-        //         Err(error) => {
-        //             // trace!("Error receiving message: {}", error);
-        //             error!("Err-响应{}", error);
-        //             break;
-        //         }
-        //         _ => {}
-        //     }
-        //
-        //     let bool_v1_v = bool_v1.load(Ordering::SeqCst);
-        //     if !bool_v1_v {
-        //         break;
-        //     }
-        // }
-        // web_socket.close(None).unwrap();
-    }
 
-    //非代理
-    async fn subscription(&self, _bool_v1: Arc<AtomicBool>,
-                          // mut web_socket: WebSocket<AutoStream>,
-                          _subscription: String)
-    {
-        // info!("链接成功!开始数据读取");
-        // let label = self.label.clone();
-        // /*****订阅消息**/
-        // if subscription.len() > 0 {
-        //     web_socket.write_message(Message::Text(subscription.clone())).unwrap();
-        // }
-        // /*****消息溜***/
-        // loop {
-        //     // tokio::time::sleep(Duration::from_nanos(1)).await;
-        //     let msg = web_socket.read_message();
-        //     match msg {
-        //         Ok(Message::Text(text)) => {
-        //             // trace!("获取推送:{}",text.clone());
-        //             let mut res_data = Self::ok_text(label.to_string(), text);
-        //             res_data.time = get_time_microsecond();
-        //             if res_data.code == "-200" {
-        //                 trace!("订阅成功:{:?}", subscription.clone());
-        //             } else {
-        //                 let sender = self.sender.clone();
-        //                 tokio::spawn(async move {
-        //                     sender.send(res_data).await.unwrap();
-        //                 });
-        //                 tokio::spawn(async move {});
-        //             }
-        //         }
-        //         Ok(Message::Ping(s)) => {
-        //             trace!( "Ping-响应--{:?}", String::from_utf8(s.clone()));
-        //             // let _ = web_socket.write_message(Message::Pong(Vec::from("pong")));
-        //             trace!( "回应-pong---{:?}", String::from_utf8(s.clone()));
-        //         }
-        //         Ok(Message::Pong(s)) => {
-        //             // trace!("Pong-响应--{:?}", String::from_utf8(s));
-        //             trace!("Pong-响应--{:?}", String::from_utf8(s.clone()));
-        //         }
-        //         Ok(Message::Close(_)) => {
-        //             // trace!("socket 关闭: ");
-        //             trace!( "Close-响应");
-        //         }
-        //         Err(error) => {
-        //             // trace!("Error receiving message: {}", error);
-        //             error!( "Err-响应{}", error);
-        //             break;
-        //         }
-        //         _ => {}
-        //     }
-        //
-        //     let bool_v1_v = bool_v1.load(Ordering::SeqCst);
-        //     if !bool_v1_v {
-        //         break;
-        //     }
-        // }
-        // web_socket.close(None).unwrap();
-    }
+        //心跳-- 方法内部线程启动
+        let write_tx_clone1 = Arc::clone(write_tx_am);
+        tokio::spawn(async move {
+            trace!("线程-异步心跳-开始");
+            AbstractWsMode::ping_or_pong(write_tx_clone1, HeartbeatType::Pong, heartbeat_time).await;
+            trace!("线程-异步心跳-结束");
+        });
+
+        //设置订阅
+        let mut subscribe_array = vec![];
+        if login_is {
+            //登录相关
+        }
+        subscribe_array.push(subscription.to_string());
+
+        //链接
+        let t2 = tokio::spawn(async move {
+            trace!("线程-异步链接-开始");
+            AbstractWsMode::ws_connect_async(bool_v1, address_url.clone(),
+                                             label.clone(), subscribe_array,
+                                             write_rx, read_tx,
+                                             BinanceSpotWs::message_text,
+                                             BinanceSpotWs::message_ping,
+                                             BinanceSpotWs::message_pong,
+            ).await.expect("币安-现货");
+            trace!("线程-异步链接-结束");
+        });
+        tokio::try_join!(t2).unwrap();
+        trace!("线程-心跳与链接-结束");
 
+        Ok(())
+    }
+    /*******************************************************************************************************/
+    /*****************************************数据解析*****************************************************/
+    /*******************************************************************************************************/
+    //数据解析-Text
+    pub fn message_text(text: String) -> Option<ResponseData> {
+        let mut response_data = Self::ok_text(text);
+        response_data.time = get_time_microsecond();
+        match response_data.code.as_str() {
+            "200" => Option::from(response_data),
+            "-201" => {
+                trace!("订阅成功:{:?}", response_data);
+                None
+            }
+            _ => None
+        }
+    }
+    //数据解析-ping
+    pub fn message_ping(_pi: Vec<u8>) -> Option<ResponseData> {
+        trace!("服务器响应-ping");
+        return None;
+    }
+    //数据解析-pong
+    pub fn message_pong(_po: Vec<u8>) -> Option<ResponseData> {
+        trace!("服务器响应-pong");
+        return None;
+    }
     //数据解析
-    pub fn ok_text(label: String, text: String) -> ResponseData
-    {
+    pub fn ok_text(text: String) -> ResponseData {
         // trace!("原始数据");
         // trace!(?text);
-        let mut res_data = ResponseData::new(label, "200".to_string(), "success".to_string(), "".to_string());
+        let mut res_data = ResponseData::new("".to_string(), "200".to_string(), "success".to_string(), "".to_string());
         let json_value: serde_json::Value = serde_json::from_str(&text).unwrap();
 
         if json_value.get("result").is_some() &&
             json_value.get("id").is_some()
         {
             //订阅反馈
-            res_data.code = "-200".to_string();
+            res_data.code = "-201".to_string();
             res_data.channel = "".to_string();
             res_data.message = "订阅成功!".to_string();
         } else if json_value.get("e").is_some() &&
@@ -374,25 +257,6 @@ impl BinanceSpotWs {
         } else {
             res_data.channel = "未知的频道".to_string();
         }
-        //
-        // if json_value.get("error").is_some() {//订阅返回
-        //     res_data.code = json_value["error"]["code"].to_string();
-        //     res_data.message = json_value["error"]["msg"].to_string();
-        // } else if json_value.get("stream").is_some() {//订阅返回
-        //     res_data.data = format!("{}", json_value.get("data").as_ref().unwrap());
-        //     res_data.code = "200".to_string();
-        //
-        //     let channel = format!("{}", json_value.get("stream").as_ref().unwrap());
-        //     if channel.contains("@aggTrade") {
-        //         res_data.channel = "aggTrade".to_string();
-        //     } else if channel.contains("@depth20@100ms") {
-        //         res_data.channel = "depth".to_string();
-        //     } else if channel.contains("@bookTicker") {
-        //         res_data.channel = "bookTicker".to_string();
-        //     } else {}
-        // } else {
-        //     res_data.data = text
-        // }
         res_data
     }
 }

+ 258 - 359
exchanges/src/binance_swap_ws.rs

@@ -1,359 +1,258 @@
-// use std::collections::{BTreeMap};
-// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
-// use std::sync::Arc;
-// use std::sync::atomic::{AtomicBool, Ordering};
-// use std::time::Duration;
-// use tokio::sync::mpsc::Sender;
-// use tracing::{error, info, trace};
-// use crate::{proxy};
-// use url::Url;
-// use crate::proxy::ParsingDetail;
-// use crate::response_base::ResponseData;
-// use crate::utils::get_time_microsecond;
-//
-// pub enum BinanceWsType {
-//     //订阅频道类型
-//     PublicAndPrivate,
-// }
-//
-//
-// #[derive(Clone)]                        //订阅枚举
-// pub enum BinanceSubscribeType {
-//     PuBookTicker,
-//     PuAggTrade,
-//     PuDepth20levels100ms,
-// }
-//
-// #[derive(Clone)]
-// pub struct BinanceSwapWs {
-//     pub label: String,
-//     request_url: String,
-//     //实际ws 链接地址
-//     proxy: ParsingDetail,
-//     //账号信息
-//     login_param: BTreeMap<String, String>,
-//     //kuconis特殊参数
-//     symbol_s: Vec<String>,
-//     //订阅币对
-//     subscribe_types: Vec<BinanceSubscribeType>,
-//     //订阅信息
-//     sender: Sender<ResponseData>,
-//     //数据通道
-// }
-//
-// impl BinanceSwapWs {
-//     /*******************************************************************************************************/
-//     /*****************************************获取一个对象****************************************************/
-//     /*******************************************************************************************************/
-//     pub fn new(is_colo: bool,
-//                login_param: BTreeMap<String, String>,
-//                ws_type: BinanceWsType,
-//                sender: Sender<ResponseData>,
-//     ) -> BinanceSwapWs
-//     {
-//         return BinanceSwapWs::new_label("default-BinanceSwapWs".to_string(), is_colo, login_param, ws_type, sender);
-//     }
-//     pub fn new_label(label: String, is_colo: bool,
-//                      login_param: BTreeMap<String, String>,
-//                      ws_type: BinanceWsType,
-//                      sender: Sender<ResponseData>,
-//     ) -> BinanceSwapWs
-//     {
-//         /*******走代理:根据环境变量配置来决定,如果配置了走代理,没有配置不走*******/
-//         let parsing_detail = proxy::ParsingDetail::parsing_environment_variables();
-//
-//         /*******公共频道-私有频道数据组装*/
-//         let request_url = match ws_type {
-//             BinanceWsType::PublicAndPrivate => {
-//                 "wss://fstream.binance.com/stream".to_string()
-//             }
-//         };
-//
-//         if is_colo {
-//             info!("开启高速(未配置,走普通:{})通道",request_url);
-//         } else {
-//             info!("走普通通道:{}",request_url);
-//         }
-//         /*****返回结构体*******/
-//         BinanceSwapWs {
-//             label,
-//             request_url,
-//             proxy: parsing_detail,
-//             login_param,
-//             symbol_s: vec![],
-//             subscribe_types: vec![],
-//             sender,
-//         }
-//     }
-//
-//     /*******************************************************************************************************/
-//     /*****************************************订阅函数********************************************************/
-//     /*******************************************************************************************************/
-//     //手动添加订阅信息
-//     pub fn set_subscribe(&mut self, subscribe_types: Vec<BinanceSubscribeType>) {
-//         self.subscribe_types.extend(subscribe_types);
-//     }
-//     //自定义
-//     pub async fn custom_subscribe(&mut self, bool_v1: Arc<AtomicBool>, b_array: Vec<String>)
-//     {
-//         let mut symbol_s = b_array.clone();
-//         for symbol in symbol_s.iter_mut() {
-//             // 大写
-//             *symbol = symbol.to_lowercase();
-//             // 字符串替换
-//             *symbol = symbol.replace("_", "");
-//             *symbol = symbol.replace("-", "");
-//         }
-//         self.symbol_s = symbol_s;
-//         let log_in = self.login_param.clone();
-//         trace!(?log_in);
-//         self.run(bool_v1).await;
-//     }
-//
-//     /*******************************************************************************************************/
-//     /*****************************************工具函数********************************************************/
-//     /*******************************************************************************************************/
-//
-//
-//     //订阅枚举解析
-//     pub fn enum_to_string(symbol: String, subscribe_type: BinanceSubscribeType) -> String {
-//         match subscribe_type {
-//             BinanceSubscribeType::PuAggTrade => {
-//                 format!("{}@aggTrade", symbol)
-//             }
-//             BinanceSubscribeType::PuDepth20levels100ms => {
-//                 format!("{}@depth20@100ms", symbol)
-//             }
-//             BinanceSubscribeType::PuBookTicker => {
-//                 format!("{}@bookTicker", symbol)
-//             }
-//         }
-//     }
-//     //组装订阅数据
-//     pub fn get_subscription(&self) -> String {
-//         let mut str = "".to_string();
-//         // let mut args = vec![];
-//         for symbol in &self.symbol_s {
-//             for subscribe_type in &self.subscribe_types {
-//                 let ty_str = Self::enum_to_string(symbol.clone(), subscribe_type.clone());
-//                 // args.push(ty_str);
-//                 if str.len() > 0 {
-//                     str = format!("{}/", str)
-//                 }
-//                 str = format!("{}{}", str, ty_str.clone().to_string());
-//             }
-//         }
-//
-//         trace!("订阅信息:{}", str.to_string());
-//         str.to_string()
-//     }
-//
-//     /*******************************************************************************************************/
-//     /*****************************************socket基本*****************************************************/
-//     /*******************************************************************************************************/
-//     async fn run(&mut self, bool_v1: Arc<AtomicBool>)
-//     {
-//         //订阅信息组装
-//         let subscription = self.get_subscription();
-//         let request_url = if subscription.len() > 0 {
-//             format!("{}?streams={}", self.request_url, subscription)
-//             // format!("{}", self.request_url)
-//         } else {
-//             format!("{}", self.request_url)
-//         };
-//
-//         loop {
-//             tokio::time::sleep(Duration::from_millis(5000)).await;
-//             info!("要连接咯~~!!{}", request_url);
-//             let request_url = Url::parse(request_url.as_str()).unwrap();
-//             //1. 判断是否需要代理,根据代理地址是否存来选择
-//             if self.proxy.ip_address.len() > 0 {
-//                 let ip_array: Vec<&str> = self.proxy.ip_address.split(".").collect();
-//                 let proxy_address = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(
-//                     ip_array[0].parse().unwrap(),
-//                     ip_array[1].parse().unwrap(),
-//                     ip_array[2].parse().unwrap(),
-//                     ip_array[3].parse().unwrap())
-//                 ), self.proxy.port.parse().unwrap());
-//                 let websocket_config = Some(WebSocketConfig {
-//                     max_send_queue: Some(16),
-//                     max_message_size: Some(16 * 1024 * 1024),
-//                     max_frame_size: Some(16 * 1024 * 1024),
-//                     accept_unmasked_frames: false,
-//                 });
-//                 let max_redirects = 5;
-//                 match connect_with_proxy(request_url.clone(),
-//                                          proxy_address,
-//                                          websocket_config,
-//                                          max_redirects) {
-//                     Ok(ws) => {
-//                         let bool_v1_clone = Arc::clone(&bool_v1);
-//                         self.proxy_subscription(bool_v1_clone, ws.0, subscription.clone()).await;
-//                     }
-//                     Err(err) => {
-//                         error!("Can't connect(无法连接): {}", err);
-//                     }
-//                 };
-//             } else {
-//                 match connect(request_url.clone()) {
-//                     Ok(ws) => {
-//                         let bool_v1_clone = Arc::clone(&bool_v1);
-//                         self.subscription(bool_v1_clone, ws.0, subscription.clone()).await;
-//                     }
-//                     Err(err) => {
-//                         // 连接失败时执行的操作
-//                         error!("Can't connect(无法连接): {}", err);
-//                         // 返回一个默认的 WebSocket 对象或其他适当的值
-//                         // 或者根据需要触发 panic 或返回错误信息
-//                     }
-//                 };
-//             }
-//             trace!("退出来咯");
-//
-//             let bool_v1_clone = Arc::clone(&bool_v1);
-//             let bool_v1_v = bool_v1_clone.load(Ordering::SeqCst);
-//             if !bool_v1_v {
-//                 break;
-//             }
-//         }
-//     }
-//
-//     //代理
-//     async fn proxy_subscription(&self, bool_v1: Arc<AtomicBool>, mut web_socket: WebSocket<ProxyAutoStream>, _subscription: String)
-//     {
-//         info!("走代理-链接成功!开始数据读取");
-//         let lable = self.label.clone();
-//         /*****消息溜***/
-//         loop {
-//             // 如果不暂停,还给cpu,这个loop会吃cpu,不还给操作系统
-//             // 如果暂停,还给cpu,这个ws就会堵塞数据
-//             tokio::time::sleep(Duration::from_millis(1)).await;
-//             let msg = web_socket.read_message();
-//             match msg {
-//                 Ok(Message::Text(text)) => {
-//                     // trace!("获取推送:{}",text.clone());
-//                     let mut res_data = Self::ok_text(lable.to_string(), text);
-//                     res_data.time = get_time_microsecond();
-//                     if res_data.code == "-200" {
-//                         trace!("订阅成功:{:?}", res_data.data);
-//                     } else {
-//                         let sender = self.sender.clone();
-//                         tokio::spawn(async move {
-//                             sender.send(res_data).await.unwrap();
-//                         });
-//                         tokio::spawn(async move {});
-//                     }
-//                 }
-//                 Ok(Message::Ping(s)) => {
-//                     trace!( "Ping-响应--{:?}", String::from_utf8(s.clone()));
-//                     // let _ = web_socket.write_message(Message::Pong(Vec::from("pong")));
-//                     trace!( "回应-pong---{:?}", String::from_utf8(s.clone()));
-//                 }
-//                 Ok(Message::Pong(s)) => {
-//                     // trace!("Pong-响应--{:?}", String::from_utf8(s));
-//                     trace!( "Pong-响应--{:?}", String::from_utf8(s.clone()));
-//                 }
-//                 Ok(Message::Close(_)) => {
-//                     // trace!("socket 关闭: ");
-//                     trace!("Close-响应");
-//                 }
-//                 Err(error) => {
-//                     // trace!("Error receiving message: {}", error);
-//                     error!("Err-响应{}", error);
-//                     break;
-//                 }
-//                 _ => {}
-//             }
-//
-//             let bool_v1_v = bool_v1.load(Ordering::SeqCst);
-//             if !bool_v1_v {
-//                 break;
-//             }
-//         }
-//         web_socket.close(None).unwrap();
-//     }
-//
-//     //非代理
-//     async fn subscription(&self, bool_v1: Arc<AtomicBool>, mut web_socket: WebSocket<AutoStream>, _subscription: String)
-//     {
-//         info!("链接成功!开始数据读取");
-//         let lable = self.label.clone();
-//         /*****消息溜***/
-//         loop {
-//             // tokio::time::sleep(Duration::from_nanos(1)).await;
-//             let msg = web_socket.read_message();
-//             match msg {
-//                 Ok(Message::Text(text)) => {
-//                     // trace!("获取推送:{}",text.clone());
-//                     let mut res_data = Self::ok_text(lable.to_string(), text);
-//                     res_data.time = get_time_microsecond();
-//                     if res_data.code == "-200" {
-//                         trace!("订阅成功:{:?}", res_data.data);
-//                     } else {
-//                         let sender = self.sender.clone();
-//                         tokio::spawn(async move {
-//                             sender.send(res_data).await.unwrap();
-//                         });
-//                         tokio::spawn(async move {});
-//                     }
-//                 }
-//                 Ok(Message::Ping(s)) => {
-//                     trace!( "Ping-响应--{:?}", String::from_utf8(s.clone()));
-//                     // let _ = web_socket.write_message(Message::Pong(Vec::from("pong")));
-//                     trace!( "回应-pong---{:?}", String::from_utf8(s.clone()));
-//                 }
-//                 Ok(Message::Pong(s)) => {
-//                     // trace!("Pong-响应--{:?}", String::from_utf8(s));
-//                     trace!("Pong-响应--{:?}", String::from_utf8(s.clone()));
-//                 }
-//                 Ok(Message::Close(_)) => {
-//                     // trace!("socket 关闭: ");
-//                     trace!( "Close-响应");
-//                 }
-//                 Err(error) => {
-//                     // trace!("Error receiving message: {}", error);
-//                     error!( "Err-响应{}", error);
-//                     break;
-//                 }
-//                 _ => {}
-//             }
-//
-//             let bool_v1_v = bool_v1.load(Ordering::SeqCst);
-//             if !bool_v1_v {
-//                 break;
-//             }
-//         }
-//         web_socket.close(None).unwrap();
-//     }
-//
-//     //数据解析
-//     pub fn ok_text(label: String, text: String) -> ResponseData
-//     {
-//         // trace!("原始数据");
-//         // trace!(?text);
-//         let mut res_data = ResponseData::new(lable, "200".to_string(), "success".to_string(), "".to_string());
-//         let json_value: serde_json::Value = serde_json::from_str(&text).unwrap();
-//
-//         if json_value.get("error").is_some() {//订阅返回
-//             res_data.code = json_value["error"]["code"].to_string();
-//             res_data.message = json_value["error"]["msg"].to_string();
-//         } else if json_value.get("stream").is_some() {//订阅返回
-//             res_data.data = format!("{}", json_value.get("data").as_ref().unwrap());
-//             res_data.code = "200".to_string();
-//
-//             let channel = format!("{}", json_value.get("stream").as_ref().unwrap());
-//             if channel.contains("@aggTrade") {
-//                 res_data.channel = "aggTrade".to_string();
-//             } else if channel.contains("@depth20@100ms") {
-//                 res_data.channel = "depth".to_string();
-//             } else if channel.contains("@bookTicker") {
-//                 res_data.channel = "bookTicker".to_string();
-//             } else {
-//                 res_data.channel = "未知的频道".to_string();
-//             }
-//         } else {
-//             res_data.data = text
-//         }
-//         res_data
-//     }
-// }
+use std::sync::Arc;
+use std::sync::atomic::AtomicBool;
+
+use futures_channel::mpsc::{UnboundedReceiver, UnboundedSender};
+use serde_json::json;
+use tokio::sync::Mutex;
+use tokio_tungstenite::tungstenite::{Error, Message};
+use tracing::{info, trace};
+
+use crate::response_base::ResponseData;
+use crate::socket_tool::{AbstractWsMode, HeartbeatType};
+use crate::utils::get_time_microsecond;
+
+//类型
+pub enum BinanceSwapWsType {
+    //订阅频道类型
+    PublicAndPrivate,
+}
+
+//订阅频道
+#[derive(Clone)]
+pub enum BinanceSwapSubscribeType {
+    PuBookTicker,
+    PuAggTrade,
+    PuDepth20levels100ms,
+}
+
+//账号信息
+#[derive(Clone)]
+#[allow(dead_code)]
+pub struct BinanceSwapLogin {
+    api_key: String,
+    api_secret: String,
+}
+
+#[derive(Clone)]
+#[allow(dead_code)]
+pub struct BinanceSwapWs {
+    //类型
+    label: String,
+    //地址
+    address_url: String,
+    //账号
+    login_param: Option<BinanceSwapLogin>,
+    //币对
+    symbol_s: Vec<String>,
+    //订阅
+    subscribe_types: Vec<BinanceSwapSubscribeType>,
+    //心跳间隔
+    heartbeat_time: u64,
+}
+
+impl BinanceSwapWs {
+    /*******************************************************************************************************/
+    /*****************************************获取一个对象****************************************************/
+    /*******************************************************************************************************/
+    pub fn new(is_colo: bool, login_param: Option<BinanceSwapLogin>, ws_type: BinanceSwapWsType) -> BinanceSwapWs {
+        return BinanceSwapWs::new_label("default-BinanceSwapWs".to_string(), is_colo, login_param, ws_type);
+    }
+    pub fn new_label(label: String, is_colo: bool, login_param: Option<BinanceSwapLogin>, ws_type: BinanceSwapWsType) -> BinanceSwapWs {
+        /*******公共频道-私有频道数据组装*/
+        let address_url = match ws_type {
+            BinanceSwapWsType::PublicAndPrivate => {
+                // "wss://fstream.binance.com/stream?streams=btcusdt@depth20@100ms".to_string(),
+                "wss://fstream.binance.com/stream".to_string()
+            }
+        };
+
+        if is_colo {
+            info!("开启高速(未配置,走普通:{})通道",address_url);
+        } else {
+            info!("走普通通道:{}",address_url);
+        }
+        BinanceSwapWs {
+            label,
+            address_url,
+            login_param,
+            symbol_s: vec![],
+            subscribe_types: vec![],
+            heartbeat_time: 1000 * 20,
+        }
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************订阅函数********************************************************/
+    /*******************************************************************************************************/
+    //手动添加订阅信息
+    pub fn set_subscribe(&mut self, subscribe_types: Vec<BinanceSwapSubscribeType>) {
+        self.subscribe_types.extend(subscribe_types);
+    }
+    //手动添加币对
+    pub fn set_symbols(&mut self, mut b_array: Vec<String>) {
+        for symbol in b_array.iter_mut() {
+            // 小写
+            *symbol = symbol.to_lowercase();
+            // 字符串替换
+            *symbol = symbol.replace("_", "");
+            *symbol = symbol.replace("-", "");
+        }
+        self.symbol_s = b_array;
+    }
+    //频道是否需要登录
+    fn contains_pr(&self) -> bool {
+        for t in self.subscribe_types.clone() {
+            if match t {
+                BinanceSwapSubscribeType::PuBookTicker => false,
+                BinanceSwapSubscribeType::PuAggTrade => false,
+                BinanceSwapSubscribeType::PuDepth20levels100ms => false,
+            } {
+                return true;
+            }
+        }
+        false
+    }
+    /*******************************************************************************************************/
+    /*****************************************工具函数********************************************************/
+    /*******************************************************************************************************/
+    //订阅枚举解析
+    pub fn enum_to_string(symbol: String, subscribe_type: BinanceSwapSubscribeType) -> String {
+        match subscribe_type {
+            BinanceSwapSubscribeType::PuAggTrade => {
+                format!("{}@aggTrade", symbol)
+            }
+            BinanceSwapSubscribeType::PuDepth20levels100ms => {
+                format!("{}@depth20@100ms", symbol)
+            }
+            BinanceSwapSubscribeType::PuBookTicker => {
+                format!("{}@bookTicker", symbol)
+            }
+        }
+    }
+    //订阅信息生成
+    pub fn get_subscription(&self) -> String {
+        let mut params = vec![];
+        for symbol in &self.symbol_s {
+            for subscribe_type in &self.subscribe_types {
+                let ty_str = Self::enum_to_string(symbol.clone(), subscribe_type.clone());
+                params.push(ty_str);
+            }
+        }
+
+        let str = json!({
+            "method": "SUBSCRIBE",
+            "params":  params,
+            "id": 1
+            });
+        str.to_string()
+    }
+    /*******************************************************************************************************/
+    /*****************************************socket基本*****************************************************/
+    /*******************************************************************************************************/
+    //链接
+    pub async fn ws_connect_async(&mut self,
+                                  bool_v1: Arc<AtomicBool>,
+                                  write_tx_am: &Arc<Mutex<UnboundedSender<Message>>>,
+                                  write_rx: UnboundedReceiver<Message>,
+                                  read_tx: UnboundedSender<ResponseData>) -> Result<(), Error>
+    {
+        let login_is = self.contains_pr();
+        let subscription = self.get_subscription();
+        let address_url = self.address_url.clone();
+        let label = self.label.clone();
+        let heartbeat_time = self.heartbeat_time.clone();
+
+
+        //心跳-- 方法内部线程启动
+        let write_tx_clone1 = Arc::clone(write_tx_am);
+        tokio::spawn(async move {
+            trace!("线程-异步心跳-开始");
+            AbstractWsMode::ping_or_pong(write_tx_clone1, HeartbeatType::Pong, heartbeat_time).await;
+            trace!("线程-异步心跳-结束");
+        });
+
+        //设置订阅
+        let mut subscribe_array = vec![];
+        if login_is {
+            //登录相关
+        }
+        subscribe_array.push(subscription.to_string());
+
+        //链接
+        let t2 = tokio::spawn(async move {
+            trace!("线程-异步链接-开始");
+            AbstractWsMode::ws_connect_async(bool_v1, address_url.clone(),
+                                             label.clone(), subscribe_array,
+                                             write_rx, read_tx,
+                                             BinanceSwapWs::message_text,
+                                             BinanceSwapWs::message_ping,
+                                             BinanceSwapWs::message_pong,
+            ).await.expect("币安-期货");
+            trace!("线程-异步链接-结束");
+        });
+        tokio::try_join!(t2).unwrap();
+        trace!("线程-心跳与链接-结束");
+
+        Ok(())
+    }
+    /*******************************************************************************************************/
+    /*****************************************数据解析*****************************************************/
+    /*******************************************************************************************************/
+    //数据解析-Text
+    pub fn message_text(text: String) -> Option<ResponseData> {
+        let mut response_data = Self::ok_text(text);
+        response_data.time = get_time_microsecond();
+        match response_data.code.as_str() {
+            "200" => Option::from(response_data),
+            "-201" => {
+                trace!("订阅成功:{:?}", response_data);
+                None
+            }
+            _ => None
+        }
+    }
+    //数据解析-ping
+    pub fn message_ping(_pi: Vec<u8>) -> Option<ResponseData> {
+        trace!("服务器响应-ping");
+        return None;
+    }
+    //数据解析-pong
+    pub fn message_pong(_po: Vec<u8>) -> Option<ResponseData> {
+        trace!("服务器响应-pong");
+        return None;
+    }
+    //数据解析
+    pub fn ok_text(text: String) -> ResponseData {
+        // trace!("原始数据");
+        // trace!(?text);
+        let mut res_data = ResponseData::new("".to_string(), "200".to_string(), "success".to_string(), "".to_string());
+        let json_value: serde_json::Value = serde_json::from_str(&text).unwrap();
+
+        if json_value.get("result").is_some() && json_value.get("id").is_some() &&
+            json_value.get("id").unwrap() == 1
+        {
+            res_data.code = "-201".to_string();
+            res_data.message = "订阅成功".to_string();
+        } else if json_value.get("error").is_some() {//订阅返回
+            res_data.code = json_value["error"]["code"].to_string();
+            res_data.message = json_value["error"]["msg"].to_string();
+        } else if json_value.get("stream").is_some() {//订阅返回
+            res_data.data = format!("{}", json_value.get("data").as_ref().unwrap());
+            res_data.code = "200".to_string();
+
+            let channel = format!("{}", json_value.get("stream").as_ref().unwrap());
+            if channel.contains("@aggTrade") {
+                res_data.channel = "aggTrade".to_string();
+            } else if channel.contains("@depth20@100ms") {
+                res_data.channel = "depth".to_string();
+            } else if channel.contains("@bookTicker") {
+                res_data.channel = "bookTicker".to_string();
+            } else {
+                res_data.channel = "未知的频道".to_string();
+            }
+        } else {
+            res_data.data = text
+        }
+        res_data
+    }
+}

+ 0 - 308
exchanges/src/binance_swap_ws_async.rs

@@ -1,308 +0,0 @@
-use std::sync::Arc;
-use std::sync::atomic::AtomicBool;
-
-use futures_channel::mpsc::{UnboundedReceiver, UnboundedSender};
-use serde_json::json;
-use tokio::sync::Mutex;
-use tokio_tungstenite::tungstenite::{Error, Message};
-use tracing::{info, trace};
-
-use crate::response_base::ResponseData;
-use crate::socket_tool::{AbstractWsMode, HeartbeatType};
-use crate::utils::get_time_microsecond;
-
-pub enum BinanceSwapWsType {
-    //订阅频道类型
-    PublicAndPrivate,
-}
-
-
-#[derive(Clone)]                        //订阅枚举
-pub enum BinanceSwapSubscribeType {
-    PuBookTicker,
-    PuAggTrade,
-    PuDepth20levels100ms,
-}
-
-#[derive(Clone)]
-#[allow(dead_code)]
-pub struct BinanceSwapLogin {
-    api_key: String,
-    api_secret: String,
-}
-
-#[derive(Clone)]
-#[allow(dead_code)]
-pub struct BinanceSwapWs {
-    //类型
-    label: String,
-    //地址
-    address_url: String,
-    //账号
-    login_param: Option<BinanceSwapLogin>,
-    //币对
-    symbol_s: Vec<String>,
-    //订阅
-    subscribe_types: Vec<BinanceSwapSubscribeType>,
-    //心跳间隔
-    heartbeat_time: u64,
-}
-
-impl BinanceSwapWs {
-    /*******************************************************************************************************/
-    /*****************************************获取一个对象****************************************************/
-    /*******************************************************************************************************/
-    pub fn new(is_colo: bool, login_param: Option<BinanceSwapLogin>, ws_type: BinanceSwapWsType) -> BinanceSwapWs {
-        return BinanceSwapWs::new_label("default-BinanceSwapWs".to_string(), is_colo, login_param, ws_type);
-    }
-    pub fn new_label(label: String, is_colo: bool, login_param: Option<BinanceSwapLogin>, ws_type: BinanceSwapWsType) -> BinanceSwapWs {
-        /*******公共频道-私有频道数据组装*/
-        let address_url = match ws_type {
-            BinanceSwapWsType::PublicAndPrivate => {
-                // "wss://fstream.binance.com/stream?streams=btcusdt@depth20@100ms".to_string(),
-                "wss://fstream.binance.com/stream".to_string()
-            }
-        };
-
-        if is_colo {
-            info!("开启高速(未配置,走普通:{})通道",address_url);
-        } else {
-            info!("走普通通道:{}",address_url);
-        }
-        BinanceSwapWs {
-            label,
-            address_url,
-            login_param,
-            symbol_s: vec![],
-            subscribe_types: vec![],
-            heartbeat_time: 5000,
-        }
-    }
-
-    /*******************************************************************************************************/
-    /*****************************************订阅函数********************************************************/
-    /*******************************************************************************************************/
-    //手动添加订阅信息
-    pub fn set_subscribe(&mut self, subscribe_types: Vec<BinanceSwapSubscribeType>) {
-        self.subscribe_types.extend(subscribe_types);
-    }
-    //手动添加币对
-    pub fn set_symbols(&mut self, mut b_array: Vec<String>) {
-        for symbol in b_array.iter_mut() {
-            // 小写
-            *symbol = symbol.to_lowercase();
-            // 字符串替换
-            *symbol = symbol.replace("_", "");
-            *symbol = symbol.replace("-", "");
-        }
-        self.symbol_s = b_array;
-    }
-    fn contains_pr(&self) -> bool {
-        for t in self.subscribe_types.clone() {
-            if match t {
-                BinanceSwapSubscribeType::PuBookTicker => false,
-                BinanceSwapSubscribeType::PuAggTrade => false,
-                BinanceSwapSubscribeType::PuDepth20levels100ms => false,
-            } {
-                return true;
-            }
-        }
-        false
-    }
-    /*******************************************************************************************************/
-    /*****************************************工具函数********************************************************/
-    /*******************************************************************************************************/
-    //订阅枚举解析
-    pub fn enum_to_string(symbol: String, subscribe_type: BinanceSwapSubscribeType) -> String {
-        match subscribe_type {
-            BinanceSwapSubscribeType::PuAggTrade => {
-                format!("{}@aggTrade", symbol)
-            }
-            BinanceSwapSubscribeType::PuDepth20levels100ms => {
-                format!("{}@depth20@100ms", symbol)
-            }
-            BinanceSwapSubscribeType::PuBookTicker => {
-                format!("{}@bookTicker", symbol)
-            }
-        }
-    }
-    //组装订阅数据-实时订阅
-    fn get_subscription(&self) -> String {
-        // let mut str = "".to_string();
-        let mut params = vec![];
-        for symbol in &self.symbol_s {
-            for subscribe_type in &self.subscribe_types {
-                let ty_str = Self::enum_to_string(symbol.clone(), subscribe_type.clone());
-                params.push(ty_str);
-            }
-        }
-
-        // trace!("订阅信息:{}", str.to_string());
-        // str.to_string()
-
-        let str = json!({
-            "method": "SUBSCRIBE",
-            "params":  params,
-            "id": 1
-            });
-        str.to_string()
-    }
-    //数据解析
-    pub fn analysis_message(message: Result<Message, Error>) -> Option<ResponseData> {
-        let mut code = "00".to_string();
-        let mut message_str = "".to_string();
-        let data = "".to_string();
-        match message {
-            Ok(Message::Text(text)) => {
-                // trace!("Text:{}",text);
-                let mut response_data = Self::ok_text(text);
-                // trace!("response_data:{:?}",response_data);
-                response_data.time = get_time_microsecond();
-                if response_data.code == "-201" {
-                    trace!("订阅成功:{:?}", response_data);
-                    return None;
-                } else if response_data.code == "-202" {
-                    trace!("无用数据:{:?}", response_data);
-                    return None;
-                } else {
-                    return Option::from(response_data);
-                }
-            }
-
-            Ok(Message::Binary(s)) => {
-                trace!("服务器响应:Binary:{:?}",s);
-            }
-            Ok(Message::Ping(pi)) => {
-                trace!("服务器响应:Ping:{:?}",pi);
-                code = "200".to_string();
-                message_str = format!("服务器响应ping:{:?}", String::from_utf8(pi));
-            }
-            Ok(Message::Pong(po)) => {
-                trace!("服务器响应:Pong:{:?}",po);
-                //原始帧 正常读取数据不会读取到该 信息类型
-                code = "200".to_string();
-                message_str = format!("服务器响应pong:{:?}", String::from_utf8(po));
-            }
-            Ok(Message::Close(c)) => {
-                trace!("服务器响应:Close:{:?}",c);
-                //原始帧 正常读取数据不会读取到该 信息类型
-                code = "0".to_string();
-                message_str = format!("关闭指令:{:?}", c);
-            }
-            Ok(Message::Frame(f)) => {
-                trace!("服务器响应:Frame:{:?}",f);
-                //原始帧 正常读取数据不会读取到该 信息类型
-                code = "-2".to_string();
-                message_str = format!("意外读取到原始帧:{:?}", f);
-            }
-            Err(e) => {
-                trace!("服务器响应:Err:{:?}",e);
-                code = "-1".to_string();
-                message_str = format!("币安-数据解析 未知错误:{:?}", e);
-            }
-        }
-        let zz = ResponseData::new("".to_string(), code, message_str, data);
-        // println!("??{:?}", zz);
-        return Option::from(zz);
-    }
-
-    /*******************************************************************************************************/
-    /*****************************************socket基本*****************************************************/
-    /*******************************************************************************************************/
-    //链接
-    pub async fn ws_connect_async(&mut self,
-                                  bool_v1: Arc<AtomicBool>,
-                                  write_tx_am: &Arc<Mutex<UnboundedSender<Message>>>,
-                                  write_rx: UnboundedReceiver<Message>,
-                                  read_tx: UnboundedSender<ResponseData>,
-    ) -> Result<(), Error>
-    {
-        let login_is = self.contains_pr();
-        let subscription = self.get_subscription();
-        let address_url = self.address_url.clone();
-        let label = self.label.clone();
-        let heartbeat_time = self.heartbeat_time.clone();
-
-
-        //心跳-- 方法内部线程启动
-        let write_tx_clone1 = Arc::clone(write_tx_am);
-        tokio::spawn(async move {
-            trace!("线程-异步心跳-开始");
-            AbstractWsMode::ping_or_pong(write_tx_clone1, HeartbeatType::Pong, heartbeat_time).await;
-            trace!("线程-异步心跳-结束");
-        });
-
-
-        //设置订阅
-        let mut subscribe_array = vec![];
-        if login_is {
-            //登录相关
-        }
-        subscribe_array.push(subscription.to_string());
-
-
-        //1 链接
-
-        let t2 = tokio::spawn(async move {
-            trace!("线程-异步链接-开始");
-            AbstractWsMode::ws_connect_async(bool_v1,address_url.clone(),
-                                             label.clone(), subscribe_array,
-                                             write_rx, read_tx, BinanceSwapWs::analysis_message,
-            ).await.expect("币安");
-            trace!("线程-异步链接-结束");
-        });
-        tokio::try_join!(t2).unwrap();
-        trace!("线程-心跳与链接-结束");
-
-
-        Ok(())
-    }
-    // //主动订阅
-    // pub fn send_subscribe(self, write_tx: Arc<Mutex<UnboundedSender<Message>>>) {
-    //     trace!("发起订阅");
-    //     if self.contains_pr() {
-    //         //有订阅需要登录
-    //     }
-    //     //发送订阅
-    //     let subscribe = self.get_subscription();
-    //     let message = Message::Text(subscribe.to_string());
-    //     AbstractWsMode::send_subscribe(write_tx, message);
-    // }
-
-
-    //数据解析
-    pub fn ok_text(text: String) -> ResponseData
-    {
-        // trace!("原始数据");
-        // trace!(?text);
-        let mut res_data = ResponseData::new("".to_string(), "200".to_string(), "success".to_string(), "".to_string());
-        let json_value: serde_json::Value = serde_json::from_str(&text).unwrap();
-
-        if json_value.get("result").is_some() && json_value.get("id").is_some() &&
-            json_value.get("id").unwrap() == 1
-        {
-            res_data.code = "-201".to_string();
-            res_data.message = "订阅成功".to_string();
-        } else if json_value.get("error").is_some() {//订阅返回
-            res_data.code = json_value["error"]["code"].to_string();
-            res_data.message = json_value["error"]["msg"].to_string();
-        } else if json_value.get("stream").is_some() {//订阅返回
-            res_data.data = format!("{}", json_value.get("data").as_ref().unwrap());
-            res_data.code = "200".to_string();
-
-            let channel = format!("{}", json_value.get("stream").as_ref().unwrap());
-            if channel.contains("@aggTrade") {
-                res_data.channel = "aggTrade".to_string();
-            } else if channel.contains("@depth20@100ms") {
-                res_data.channel = "depth".to_string();
-            } else if channel.contains("@bookTicker") {
-                res_data.channel = "bookTicker".to_string();
-            } else {
-                res_data.channel = "未知的频道".to_string();
-            }
-        } else {
-            res_data.data = text
-        }
-        res_data
-    }
-}

+ 391 - 506
exchanges/src/kucoin_spot_ws.rs

@@ -1,506 +1,391 @@
-// use std::collections::{BTreeMap, HashSet};
-// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
-// use std::sync::Arc;
-// use std::sync::atomic::{AtomicBool, Ordering};
-// use std::time::Duration;
-// use tokio::sync::mpsc::Sender;
-// use tracing::{error, info, trace};
-// use crate::{proxy};
-// use url::Url;
-// use crate::kucoin_spot_rest::KucoinSpotRest;
-// use crate::proxy::ParsingDetail;
-// use crate::response_base::ResponseData;
-// use crate::utils::get_time_microsecond;
-//
-//
-// pub enum KucoinWsType {
-//     Public,
-//     Private,
-// }
-//
-// #[derive(Debug)]
-// #[derive(Clone)]
-// pub struct KucoinWsParam {
-//     pub token: String,
-//     pub ws_url: String,
-//     pub ws_ping_interval: i64,
-//     pub ws_ping_timeout: i64,
-// }
-//
-// #[derive(Clone)]                        //订阅枚举
-// pub enum KucoinSubscribeType {
-//     PuSpotMarketLevel2Depth50,
-//     PuMarketMatch,
-//     PuMarketTicker,
-//
-//     PrSpotMarketTradeOrders,
-//     PrAccountBalance,
-// }
-//
-// #[derive(Clone)]
-// pub struct KucoinSpotWs {
-//     pub label: String,
-//     request_url: String,
-//     //实际ws 链接地址
-//     proxy: ParsingDetail,
-//     //代理信息
-//     // login_param: BTreeMap<String, String>,
-//     //登陆数据
-//     ws_param: KucoinWsParam,
-//     //kuconis特殊参数
-//     symbol_s: Vec<String>,
-//     //订阅币对
-//     subscribe_types: Vec<KucoinSubscribeType>,
-//     //订阅信息
-//     sender: Sender<ResponseData>,     //数据通道
-// }
-//
-// impl KucoinSpotWs {
-//     /*******************************************************************************************************/
-//     /*****************************************获取一个对象****************************************************/
-//     /*******************************************************************************************************/
-//     pub async fn new(is_colo: bool,
-//                      login_param: BTreeMap<String, String>,
-//                      ws_type: KucoinWsType,
-//                      sender: Sender<ResponseData>,
-//     ) -> KucoinSpotWs {
-//         return KucoinSpotWs::new_label("default-KucoinSpotWs".to_string(), is_colo, login_param, ws_type, sender).await;
-//     }
-//     pub async fn new_label(label: String, _is_colo: bool,
-//                            login_param: BTreeMap<String, String>,
-//                            ws_type: KucoinWsType,
-//                            sender: Sender<ResponseData>,
-//     ) -> KucoinSpotWs
-//     {
-//         /*******走代理:根据环境变量配置来决定,如果配置了走代理,没有配置不走*******/
-//         let parsing_detail = proxy::ParsingDetail::parsing_environment_variables();
-//
-//         /*******公共频道-私有频道数据组装*/
-//         let mut ws_param = KucoinWsParam {
-//             token: "".to_string(),
-//             ws_url: "".to_string(),
-//             ws_ping_interval: 0,
-//             ws_ping_timeout: 0,
-//         };
-//         let res_data = KucoinSpotWs::get_rul_token(ws_type, login_param.clone()).await;
-//         match res_data {
-//             Ok(param) => {
-//                 ws_param = param
-//             }
-//             Err(error) => {
-//                 error!("-链接地址等参数错误:{:?}", error)
-//             }
-//         }
-//
-//
-//         /*****返回结构体*******/
-//         KucoinSpotWs {
-//             label,
-//             request_url: "".to_string(),
-//             proxy: parsing_detail,
-//             // login_param,
-//             ws_param,
-//             symbol_s: vec![],
-//             subscribe_types: vec![],
-//             sender,
-//         }
-//     }
-//
-//     /*******************************************************************************************************/
-//     /*****************************************订阅函数********************************************************/
-//     /*******************************************************************************************************/
-//     //手动添加订阅信息
-//     pub fn set_subscribe(&mut self, subscribe_types: Vec<KucoinSubscribeType>) {
-//         self.subscribe_types.extend(subscribe_types);
-//     }
-//     //根据当前类型获取对应的频道 地址 与 token
-//     async fn get_rul_token(ws_type: KucoinWsType, login_param: BTreeMap<String, String>) -> Result<KucoinWsParam, reqwest::Error> {
-//         let mut kucoin_exc = KucoinSpotRest::new(false, login_param.clone());
-//         let res_data = match ws_type {
-//             KucoinWsType::Public => {
-//                 kucoin_exc.get_public_token().await
-//             }
-//             KucoinWsType::Private => {
-//                 kucoin_exc.get_private_token().await
-//             }
-//         };
-//
-//         trace!("kucoin-spot-rest 获取ws连接地址:{:?}",res_data);
-//
-//         if res_data.code == "200" {
-//             let mut ws_url = "".to_string();
-//             let mut ws_token = "".to_string();
-//             let mut ws_ping_interval: i64 = 0;
-//             let mut ws_ping_timeout: i64 = 0;
-//
-//
-//             //数据解析
-//             let parsed_json: serde_json::Value = serde_json::from_str(res_data.data.as_str()).unwrap();
-//             if let Some(value) = parsed_json.get("token") {
-//                 let formatted_value = match value {
-//                     serde_json::Value::String(s) => s.clone(),
-//                     _ => value.to_string()
-//                 };
-//                 ws_token = format!("{}", formatted_value);
-//             }
-//             if let Some(endpoint) = parsed_json["instanceServers"][0]["endpoint"].as_str() {
-//                 ws_url = format!("{}", endpoint);
-//             }
-//             if let Some(ping_interval) = parsed_json["instanceServers"][0]["pingInterval"].as_i64() {
-//                 ws_ping_interval = ping_interval;
-//             }
-//             if let Some(ping_timeout) = parsed_json["instanceServers"][0]["pingTimeout"].as_i64() {
-//                 ws_ping_timeout = ping_timeout;
-//             }
-//
-//
-//             Ok(KucoinWsParam { ws_url, token: ws_token, ws_ping_interval, ws_ping_timeout })
-//         } else {
-//             error!("公共/私有-频道获取失败:{:?}", res_data);
-//             panic!("公共/私有-频道获取失败:{:?}", res_data);
-//         }
-//     }
-//     //自定义
-//     pub async fn custom_subscribe(&mut self, bool_v1: Arc<AtomicBool>, b_array: Vec<String>)
-//     {
-//         let mut symbol_s = b_array.clone();
-//         for symbol in symbol_s.iter_mut() {
-//             // 大写
-//             *symbol = symbol.to_uppercase();
-//             // 字符串替换
-//             *symbol = symbol.replace("_", "-");
-//         }
-//         self.symbol_s = symbol_s.clone();
-//         self.request_url = format!("{}?token={}", self.ws_param.ws_url, self.ws_param.token);
-//         info!("走普通通道:{}",  self.request_url);
-//         self.run(bool_v1).await;
-//     }
-//
-//     /*******************************************************************************************************/
-//     /*****************************************工具函数********************************************************/
-//     /*******************************************************************************************************/
-//     //订阅枚举解析
-//     pub fn enum_to_string(symbol: String, subscribe_type: KucoinSubscribeType) -> serde_json::Value {
-//         match subscribe_type {
-//             KucoinSubscribeType::PuSpotMarketLevel2Depth50 => {//level2
-//                 serde_json::json!({
-//                      "topic": format!("/spotMarket/level2Depth50:{}", symbol),
-//                      "type": "subscribe",
-//                      "response": true
-//                 })
-//             }
-//             KucoinSubscribeType::PuMarketMatch => {//match
-//                 serde_json::json!({
-//                      "topic": format!("/market/match:{}", symbol),
-//                      "type": "subscribe",
-//                      "response": true
-//                 })
-//             }
-//             KucoinSubscribeType::PuMarketTicker => {//ticker
-//                 serde_json::json!({
-//                      "topic": format!("/market/ticker:{}", symbol),
-//                      "type": "subscribe",
-//                      "response": true
-//                 })
-//             }
-//
-//             KucoinSubscribeType::PrSpotMarketTradeOrders => {//market.tradeOrders
-//                 serde_json::json!({
-//                     "type": "subscribe",
-//                     "topic": "/spotMarket/tradeOrders",
-//                     "privateChannel":true,
-//                     "response":true,
-//                 })
-//             }
-//             KucoinSubscribeType::PrAccountBalance => {//account.balance
-//                 serde_json::json!({
-//                     "type": "subscribe",
-//                     "topic": "/account/balance",
-//                     "privateChannel":true,
-//                     "response":true,
-//                 })
-//             }
-//         }
-//     }
-//     //组装订阅数据
-//     pub fn get_subscription(&self) -> Vec<String> {
-//         let mut array = vec![];
-//         for symbol in &self.symbol_s {
-//             for subscribe_type in &self.subscribe_types {
-//                 let ty_str = Self::enum_to_string(symbol.clone(), subscribe_type.clone());
-//                 array.push(ty_str.to_string());
-//             }
-//         }
-//         array
-//     }
-//     /*******************************************************************************************************/
-//     /*****************************************socket基本*****************************************************/
-//     /*******************************************************************************************************/
-//     async fn run(&self, bool_v1: Arc<AtomicBool>)
-//     {
-//         //订阅信息组装
-//         let subscription = self.get_subscription();
-//         let subscription: Vec<String> = subscription.into_iter().collect::<HashSet<String>>().into_iter().collect();
-//         loop {
-//             tokio::time::sleep(Duration::from_millis(5000)).await;
-//             trace!("要连接咯~~!!{}", self.request_url);
-//             //币安-登陆流程-rest请求获取k然后拿到 key 拼接地址
-//             // if self.is_login { //暂时没看到有订阅的频道需要登陆 所以暂时不做
-//             // }
-//
-//             let request_url = Url::parse(self.request_url.as_str()).unwrap();
-//             //1. 判断是否需要代理,根据代理地址是否存来选择
-//             if self.proxy.ip_address.len() > 0 {
-//                 let ip_array: Vec<&str> = self.proxy.ip_address.split(".").collect();
-//                 let proxy_address = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(
-//                     ip_array[0].parse().unwrap(),
-//                     ip_array[1].parse().unwrap(),
-//                     ip_array[2].parse().unwrap(),
-//                     ip_array[3].parse().unwrap())
-//                 ), self.proxy.port.parse().unwrap());
-//                 let websocket_config = Some(WebSocketConfig {
-//                     max_send_queue: Some(16),
-//                     max_message_size: Some(16 * 1024 * 1024),
-//                     max_frame_size: Some(16 * 1024 * 1024),
-//                     accept_unmasked_frames: false,
-//                 });
-//                 let max_redirects = 5;
-//                 let _ = match connect_with_proxy(request_url.clone(),
-//                                                  proxy_address, websocket_config, max_redirects) {
-//                     Ok(ws) => {
-//                         let bool_v1_clone = Arc::clone(&bool_v1);
-//                         self.proxy_subscription(bool_v1_clone, ws.0, subscription.clone()).await;
-//                     }
-//                     Err(err) => {
-//                         error!("Can't connect(无法连接): {}", err);
-//                     }
-//                 };
-//             } else {
-//                 let _ = match connect(request_url.clone()) {
-//                     Ok(ws) => {
-//                         let bool_v1_clone = Arc::clone(&bool_v1);
-//                         self.subscription(bool_v1_clone, ws.0, subscription.clone()).await;
-//                     }
-//                     Err(err) => {
-//                         // 连接失败时执行的操作
-//                         error!("Can't connect(无法连接): {}", err);
-//                         // 返回一个默认的 WebSocket 对象或其他适当的值
-//                         // 或者根据需要触发 panic 或返回错误信息
-//                     }
-//                 };
-//             }
-//             trace!("退出来咯");
-//
-//             let bool_v1_clone = Arc::clone(&bool_v1);
-//             let bool_v1_v = bool_v1_clone.load(Ordering::SeqCst);
-//             if !bool_v1_v {
-//                 break;
-//             }
-//         }
-//     }
-//
-//     //代理
-//     async fn proxy_subscription(&self, bool_v1: Arc<AtomicBool>, mut web_socket: WebSocket<ProxyAutoStream>,
-//                                 subscription: Vec<String>)
-//     {
-//         info!("走代理-链接成功!开始数据读取");
-//         info!(?subscription);
-//         let label = self.label.clone();
-//         /*****消息溜***/
-//         let mut ping_interval = chrono::Utc::now().timestamp_millis();
-//         let mut ping_timeout = chrono::Utc::now().timestamp_millis();
-//         loop {
-//             tokio::time::sleep(Duration::from_millis(1)).await;
-//             let msg = web_socket.read_message();
-//             match msg {
-//                 Ok(Message::Text(text)) => {
-//                     //心跳-一定时间间隔发送心跳
-//                     let get_time = chrono::Utc::now().timestamp_millis();
-//                     // trace!("--心跳-{}-{}-{}-{}-{}", get_time, ping_interval
-//                     //          , (get_time - ping_interval), self.ws_param.ws_ping_interval, (get_time - ping_interval) >= self.ws_param.ws_ping_interval);
-//                     if (get_time - ping_interval) >= self.ws_param.ws_ping_interval {
-//                         web_socket.write_message(Message::Ping(Vec::from("ping")))
-//                             .unwrap();
-//                         trace!("--发送心跳-ping");
-//                         ping_interval = get_time;
-//                         ping_timeout = get_time;
-//                     } else if (get_time - ping_timeout) > (self.ws_param.ws_ping_timeout + self.ws_param.ws_ping_interval) {
-//                         //心跳超时-发送心跳之后 一定时间没有响应
-//                         trace!("--心跳相应超时-重连");
-//                         break;
-//                     }
-//
-//                     // trace!("获取推送:{}",text.clone());
-//                     // trace!(stdout, "Text-响应--{:?}", text.clone()).unwrap();
-//                     let mut res_data = Self::ok_text(label.to_string(), text);
-//                     res_data.time = get_time_microsecond();
-//                     // trace!("获取推送:{:?}", res_data);
-//                     if res_data.code == "-200" {//表示链接成功
-//                         for sub in &subscription {
-//                             trace!("--发起订阅:{:?}", sub);
-//                             web_socket.write_message(Message::Text(sub.parse().unwrap()))
-//                                 .unwrap();
-//                         }
-//                     } else if res_data.code == "-201" {
-//                         trace!("订阅成功:{:?}", res_data);
-//                     } else if res_data.code == "-202" {
-//                         trace!("无用数据:{:?}", res_data);
-//                     } else {
-//                         let sender = self.sender.clone();
-//                         tokio::spawn(async move {
-//                             sender.send(res_data).await.unwrap();
-//                         });
-//                         tokio::spawn(async move {});
-//                     }
-//                 }
-//                 Ok(Message::Ping(s)) => {
-//                     trace!( "Ping-响应--{:?}", String::from_utf8(s.clone()));
-//                     let _ = web_socket.write_message(Message::Pong(Vec::from("pong")));
-//                     trace!( "回应-pong---{:?}", String::from_utf8(s.clone()));
-//                 }
-//                 Ok(Message::Pong(s)) => {
-//                     // trace!("Pong-响应--{:?}", String::from_utf8(s));
-//                     trace!( "Pong-响应--{:?}", String::from_utf8(s.clone()));
-//                     ping_timeout = chrono::Utc::now().timestamp_millis();
-//                 }
-//                 Ok(Message::Close(_)) => {
-//                     // trace!("socket 关闭: ");
-//                     trace!( "Close-响应");
-//                 }
-//                 Err(error) => {
-//                     // trace!("Error receiving message: {}", error);
-//                     error!( "Err-响应{}", error);
-//                     break;
-//                 }
-//                 _ => {}
-//             }
-//
-//
-//             let bool_v1_v = bool_v1.load(Ordering::SeqCst);
-//             if !bool_v1_v {
-//                 break;
-//             }
-//         }
-//         web_socket.close(None).unwrap();
-//     }
-//
-//     //非代理
-//     async fn subscription(&self, bool_v1: Arc<AtomicBool>, mut web_socket: WebSocket<AutoStream>,
-//                           subscription: Vec<String>)
-//     {
-//         info!("链接成功!开始数据读取");
-//         let label = self.label.clone();
-//         /*****消息溜***/
-//         let mut ping_interval = chrono::Utc::now().timestamp_millis();
-//         let mut ping_timeout = chrono::Utc::now().timestamp_millis();
-//         loop {
-//             tokio::time::sleep(Duration::from_millis(1)).await;
-//             let msg = web_socket.read_message();
-//             match msg {
-//                 Ok(Message::Text(text)) => {
-//                     //心跳-一定时间间隔发送心跳
-//                     let get_time = chrono::Utc::now().timestamp_millis();
-//                     // trace!("--心跳-{}-{}-{}-{}-{}", get_time, ping_interval
-//                     //          , (get_time - ping_interval), self.ws_param.ws_ping_interval, (get_time - ping_interval) >= self.ws_param.ws_ping_interval);
-//                     if (get_time - ping_interval) >= self.ws_param.ws_ping_interval {
-//                         web_socket.write_message(Message::Ping(Vec::from("ping")))
-//                             .unwrap();
-//                         trace!("--发送心跳-ping");
-//                         ping_interval = get_time;
-//                         ping_timeout = get_time;
-//                     } else if (get_time - ping_timeout) > (self.ws_param.ws_ping_timeout + self.ws_param.ws_ping_interval) {
-//                         //心跳超时-发送心跳之后 一定时间没有响应
-//                         trace!("--心跳相应超时-重连");
-//                         break;
-//                     }
-//
-//                     // trace!("获取推送:{}",text.clone());
-//                     // trace!(stdout, "Text-响应--{:?}", text.clone()).unwrap();
-//                     let mut res_data = Self::ok_text(label.to_string(), text);
-//                     res_data.time = get_time_microsecond();
-//                     // trace!("获取推送:{:?}", res_data);
-//                     if res_data.code == "-200" {//表示链接成功
-//                         for sub in &subscription {
-//                             trace!("--发起订阅:{:?}", sub);
-//                             web_socket.write_message(Message::Text(sub.parse().unwrap()))
-//                                 .unwrap();
-//                         }
-//                     } else if res_data.code == "-201" {
-//                         trace!("订阅成功:{:?}", res_data);
-//                     } else if res_data.code == "-202" {
-//                         trace!("无用数据:{:?}", res_data);
-//                     } else {
-//                         let sender = self.sender.clone();
-//                         tokio::spawn(async move {
-//                             sender.send(res_data).await.unwrap();
-//                         });
-//                         tokio::spawn(async move {});
-//                     }
-//                 }
-//                 Ok(Message::Ping(s)) => {
-//                     trace!( "Ping-响应--{:?}", String::from_utf8(s.clone()));
-//                     let _ = web_socket.write_message(Message::Pong(Vec::from("pong")));
-//                     trace!( "回应-pong---{:?}", String::from_utf8(s.clone()));
-//                 }
-//                 Ok(Message::Pong(s)) => {
-//                     // trace!("Pong-响应--{:?}", String::from_utf8(s));
-//                     trace!( "Pong-响应--{:?}", String::from_utf8(s.clone()));
-//                     ping_timeout = chrono::Utc::now().timestamp_millis();
-//                 }
-//                 Ok(Message::Close(_)) => {
-//                     // trace!("socket 关闭: ");
-//                     trace!( "Close-响应");
-//                 }
-//                 Err(error) => {
-//                     // trace!("Error receiving message: {}", error);
-//                     error!( "Err-响应{}", error);
-//                     break;
-//                 }
-//                 _ => {}
-//             }
-//
-//
-//             let bool_v1_v = bool_v1.load(Ordering::SeqCst);
-//             if !bool_v1_v {
-//                 break;
-//             }
-//         }
-//         web_socket.close(None).unwrap();
-//     }
-//
-//     //数据解析
-//     pub fn ok_text(label: String, text: String) -> ResponseData
-//     {
-//         let mut res_data = ResponseData::new(lable, "200".to_string(), "success".to_string(), "".to_string());
-//         let json_value: serde_json::Value = serde_json::from_str(&text).unwrap();
-//         //订阅 相应
-//         if json_value["type"].as_str() == Option::from("welcome") {
-//             //链接成功
-//             res_data.code = "-200".to_string();
-//             res_data.message = "链接成功,主动发起订阅".to_string();
-//             trace!("链接成功,主动发起订阅:");
-//         } else if json_value["type"].as_str() == Option::from("ack") {
-//             res_data.code = "-201".to_string();
-//             res_data.message = "订阅成功".to_string();
-//         } else if json_value["type"].as_str() == Option::from("error") {
-//             res_data.code = format!("{}", json_value["code"]);
-//             res_data.message = format!("{}", json_value["data"].as_str().unwrap());
-//         } else if json_value.get("topic").is_some() {
-//             res_data.channel = format!("{}", json_value["subject"].as_str().unwrap());
-//
-//             if json_value["topic"].as_str() == Option::from("/contractAccount/wallet") {
-//                 res_data.code = "-202".to_string();
-//                 if json_value["subject"].as_str() == Option::from("availableBalance.change") {
-//                     res_data.code = "200".to_string();
-//                     res_data.data = json_value["data"].to_string();
-//                 } else {}
-//             } else {
-//                 res_data.data = json_value["data"].to_string();
-//             }
-//         } else {
-//             res_data.code = "-1".to_string();
-//             res_data.message = "未知解析".to_string();
-//         }
-//         res_data
-//     }
-// }
+use std::collections::BTreeMap;
+use std::sync::Arc;
+use std::sync::atomic::AtomicBool;
+
+use futures_channel::mpsc::{UnboundedReceiver, UnboundedSender};
+use tokio::sync::Mutex;
+use tokio_tungstenite::tungstenite::{Error, Message};
+use tracing::{error, info, trace};
+
+use crate::kucoin_spot_rest::KucoinSpotRest;
+use crate::response_base::ResponseData;
+use crate::socket_tool::{AbstractWsMode, HeartbeatType};
+use crate::utils::get_time_microsecond;
+
+//类型
+pub enum KucoinSpotWsType {
+    Public,
+    Private,
+}
+
+#[derive(Debug)]
+#[derive(Clone)]
+pub struct KucoinSpotWsParam {
+    pub token: String,
+    pub ws_url: String,
+    pub ws_ping_interval: i64,
+    pub ws_ping_timeout: i64,
+    pub is_ok_subscribe: bool,
+}
+
+//订阅频道
+#[derive(Clone)]
+pub enum KucoinSpotSubscribeType {
+    PuSpotMarketLevel2Depth50,
+    PuMarketMatch,
+    PuMarketTicker,
+
+    PrSpotMarketTradeOrders,
+    PrAccountBalance,
+}
+
+//账号信息
+#[derive(Clone, Debug)]
+pub struct KucoinSpotLogin {
+    pub access_key: String,
+    pub secret_key: String,
+    pub pass_key: String,
+}
+
+#[derive(Clone)]
+#[allow(dead_code)]
+pub struct KucoinSpotWs {
+    //类型
+    label: String,
+    //地址
+    address_url: String,
+    //代理信息
+    login_param: Option<KucoinSpotLogin>,
+    //登陆数据
+    ws_param: KucoinSpotWsParam,
+    //币对
+    symbol_s: Vec<String>,
+    //订阅
+    subscribe_types: Vec<KucoinSpotSubscribeType>,
+    //心跳间隔
+    heartbeat_time: u64,
+}
+
+impl KucoinSpotWs {
+    /*******************************************************************************************************/
+    /*****************************************获取一个对象****************************************************/
+    /*******************************************************************************************************/
+    pub async fn new(is_colo: bool, login_param: Option<KucoinSpotLogin>, ws_type: KucoinSpotWsType) -> KucoinSpotWs {
+        return KucoinSpotWs::new_label("default-KucoinSpotWs".to_string(), is_colo, login_param, ws_type).await;
+    }
+    pub async fn new_label(label: String, is_colo: bool, login_param: Option<KucoinSpotLogin>, ws_type: KucoinSpotWsType) -> KucoinSpotWs {
+        /*******公共频道-私有频道数据组装*/
+        let mut ws_param = KucoinSpotWsParam {
+            token: "".to_string(),
+            ws_url: "".to_string(),
+            ws_ping_interval: 0,
+            ws_ping_timeout: 0,
+            is_ok_subscribe: false,
+        };
+
+        /*******公共频道-私有频道数据组装*/
+        let res_data = KucoinSpotWs::get_rul_token(ws_type, login_param.clone()).await;
+        let address_url = match res_data {
+            Ok(param) => {
+                ws_param = param;
+                format!("{}?token={}", ws_param.ws_url, ws_param.token)
+            }
+            Err(error) => {
+                error!("-链接地址等参数错误:{:?}", error);
+                "".to_string()
+            }
+        };
+
+        if is_colo {
+            info!("开启高速(未配置,走普通:{})通道",address_url);
+        } else {
+            info!("走普通通道:{}",address_url);
+        }
+
+        KucoinSpotWs {
+            label,
+            address_url,
+            login_param,
+            ws_param,
+            symbol_s: vec![],
+            subscribe_types: vec![],
+            heartbeat_time: 1000 * 18,
+        }
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************订阅函数********************************************************/
+    /*******************************************************************************************************/
+    //根据当前类型获取对应的频道 地址 与 token
+    async fn get_rul_token(ws_type: KucoinSpotWsType, login_param: Option<KucoinSpotLogin>) -> Result<KucoinSpotWsParam, reqwest::Error> {
+        let mut kucoin_exc = KucoinSpotRest::new(false, match login_param {
+            None => {
+                let btree_map: BTreeMap<String, String> = BTreeMap::new();
+                btree_map
+            }
+            Some(d) => {
+                let mut btree_map: BTreeMap<String, String> = BTreeMap::new();
+                btree_map.insert("access_key".to_string(), d.access_key);
+                btree_map.insert("secret_key".to_string(), d.secret_key);
+                btree_map.insert("pass_key".to_string(), d.pass_key);
+                btree_map
+            }
+        });
+        let res_data = match ws_type {
+            KucoinSpotWsType::Public => {
+                kucoin_exc.get_public_token().await
+            }
+            KucoinSpotWsType::Private => {
+                kucoin_exc.get_private_token().await
+            }
+        };
+
+        trace!("kucoin-spot-rest 获取ws连接地址:{:?}",res_data);
+
+        if res_data.code == "200" {
+            let mut ws_url = "".to_string();
+            let mut ws_token = "".to_string();
+            let mut ws_ping_interval: i64 = 0;
+            let mut ws_ping_timeout: i64 = 0;
+
+
+            //数据解析
+            let parsed_json: serde_json::Value = serde_json::from_str(res_data.data.as_str()).unwrap();
+            if let Some(value) = parsed_json.get("token") {
+                let formatted_value = match value {
+                    serde_json::Value::String(s) => s.clone(),
+                    _ => value.to_string()
+                };
+                ws_token = format!("{}", formatted_value);
+            }
+            if let Some(endpoint) = parsed_json["instanceServers"][0]["endpoint"].as_str() {
+                ws_url = format!("{}", endpoint);
+            }
+            if let Some(ping_interval) = parsed_json["instanceServers"][0]["pingInterval"].as_i64() {
+                ws_ping_interval = ping_interval;
+            }
+            if let Some(ping_timeout) = parsed_json["instanceServers"][0]["pingTimeout"].as_i64() {
+                ws_ping_timeout = ping_timeout;
+            }
+
+
+            Ok(KucoinSpotWsParam { ws_url, token: ws_token, ws_ping_interval, ws_ping_timeout, is_ok_subscribe: false })
+        } else {
+            error!("公共/私有-频道获取失败:{:?}", res_data);
+            panic!("公共/私有-频道获取失败:{:?}", res_data);
+        }
+    }
+    //手动添加订阅信息
+    pub fn set_subscribe(&mut self, subscribe_types: Vec<KucoinSpotSubscribeType>) {
+        self.subscribe_types.extend(subscribe_types);
+    }
+    //手动添加币对
+    pub fn set_symbols(&mut self, mut b_array: Vec<String>) {
+        for symbol in b_array.iter_mut() {
+            // 大写
+            *symbol = symbol.to_uppercase();
+            // 字符串替换
+            *symbol = symbol.replace("_", "-");
+        }
+        self.symbol_s = b_array;
+    }
+    fn contains_pr(&self) -> bool {
+        for t in self.subscribe_types.clone() {
+            if match t {
+                KucoinSpotSubscribeType::PuSpotMarketLevel2Depth50 => false,
+                KucoinSpotSubscribeType::PuMarketMatch => false,
+                KucoinSpotSubscribeType::PuMarketTicker => false,
+
+                KucoinSpotSubscribeType::PrSpotMarketTradeOrders => true,
+                KucoinSpotSubscribeType::PrAccountBalance => true
+            } {
+                return true;
+            }
+        }
+        false
+    }
+    /*******************************************************************************************************/
+    /*****************************************工具函数********************************************************/
+    /*******************************************************************************************************/
+    //订阅枚举解析
+    pub fn enum_to_string(symbol: String, subscribe_type: KucoinSpotSubscribeType) -> serde_json::Value {
+        match subscribe_type {
+            KucoinSpotSubscribeType::PuSpotMarketLevel2Depth50 => {//level2
+                serde_json::json!({
+                     "topic": format!("/spotMarket/level2Depth50:{}", symbol),
+                     "type": "subscribe",
+                     "response": true
+                })
+            }
+            KucoinSpotSubscribeType::PuMarketMatch => {//match
+                serde_json::json!({
+                     "topic": format!("/market/match:{}", symbol),
+                     "type": "subscribe",
+                     "response": true
+                })
+            }
+            KucoinSpotSubscribeType::PuMarketTicker => {//ticker
+                serde_json::json!({
+                     "topic": format!("/market/ticker:{}", symbol),
+                     "type": "subscribe",
+                     "response": true
+                })
+            }
+
+            KucoinSpotSubscribeType::PrSpotMarketTradeOrders => {//market.tradeOrders
+                serde_json::json!({
+                    "type": "subscribe",
+                    "topic": "/spotMarket/tradeOrders",
+                    "privateChannel":true,
+                    "response":true,
+                })
+            }
+            KucoinSpotSubscribeType::PrAccountBalance => {//account.balance
+                serde_json::json!({
+                    "type": "subscribe",
+                    "topic": "/account/balance",
+                    "privateChannel":true,
+                    "response":true,
+                })
+            }
+        }
+    }
+    //订阅信息生成
+    pub fn get_subscription(&self) -> Vec<String> {
+        let mut array = vec![];
+        for symbol in &self.symbol_s {
+            for subscribe_type in &self.subscribe_types {
+                let ty_str = Self::enum_to_string(symbol.clone(), subscribe_type.clone());
+                array.push(ty_str.to_string());
+            }
+        }
+        array
+    }
+    /*******************************************************************************************************/
+    /*****************************************socket基本*****************************************************/
+    /*******************************************************************************************************/
+    //链接
+    pub async fn ws_connect_async(&mut self,
+                                  bool_v1: Arc<AtomicBool>,
+                                  write_tx_am: &Arc<Mutex<UnboundedSender<Message>>>,
+                                  write_rx: UnboundedReceiver<Message>,
+                                  read_tx: UnboundedSender<ResponseData>,
+    ) -> Result<(), Error>
+    {
+        let login_is = self.contains_pr();
+        let subscription = self.get_subscription();
+        let address_url = self.address_url.clone();
+        let label = self.label.clone();
+        let heartbeat_time = self.heartbeat_time.clone();
+
+        //心跳-- 方法内部线程启动
+        let write_tx_clone1 = write_tx_am.clone();
+        tokio::spawn(async move {
+            trace!("线程-异步心跳-开始");
+            AbstractWsMode::ping_or_pong(write_tx_clone1, HeartbeatType::Ping, heartbeat_time).await;
+            trace!("线程-异步心跳-结束");
+        });
+
+
+        //设置订阅
+        let subscribe_array = subscription.clone();
+        if login_is {
+            //登录相关
+        }
+        // let write_tx_clone2 = write_tx_am.clone();
+        // tokio::spawn(async move {
+        //     tokio::time::sleep(Duration::from_millis(3 * 1000)).await;
+        //     for su in subscription.clone(){
+        //         let write_tx_clone = write_tx_clone2.lock().await;
+        //         let message = Message::Text(su.clone());
+        //         write_tx_clone.unbounded_send(message).unwrap();
+        //     }
+        // });
+
+
+        //1 链接
+
+        let t2 = tokio::spawn(async move {
+            trace!("线程-异步链接-开始");
+            AbstractWsMode::ws_connect_async(bool_v1, address_url.clone(),
+                                             label.clone(), subscribe_array.clone(),
+                                             write_rx, read_tx,
+                                             KucoinSpotWs::message_text,
+                                             KucoinSpotWs::message_ping,
+                                             KucoinSpotWs::message_pong,
+            ).await.expect("kucoin-现货");
+            trace!("线程-异步链接-结束");
+        });
+        tokio::try_join!(t2).unwrap();
+        trace!("线程-心跳与链接-结束");
+
+
+        Ok(())
+    }
+    /*******************************************************************************************************/
+    /*****************************************数据解析*****************************************************/
+    /*******************************************************************************************************/
+    //数据解析-Text
+    pub fn message_text(text: String) -> Option<ResponseData> {
+        let mut response_data = Self::ok_text(text);
+        response_data.time = get_time_microsecond();
+        match response_data.code.as_str() {
+            "200" => Option::from(response_data),
+            "-201" => {
+                trace!("订阅成功:{:?}", response_data);
+                None
+            }
+            "-202" => {
+                trace!("未知解析:{:?}", response_data);
+                None
+            }
+            _ => None
+        }
+    }
+    //数据解析-ping
+    pub fn message_ping(_pi: Vec<u8>) -> Option<ResponseData> {
+        trace!("服务器响应-ping");
+        return None;
+    }
+    //数据解析-pong
+    pub fn message_pong(_po: Vec<u8>) -> Option<ResponseData> {
+        trace!("服务器响应-pong");
+        return None;
+    }
+
+    //数据解析
+    pub fn ok_text(text: String) -> ResponseData
+    {
+        let mut res_data = ResponseData::new("".to_string(), "200".to_string(), "success".to_string(), "".to_string());
+        let json_value: serde_json::Value = serde_json::from_str(&text).unwrap();
+        //订阅 相应
+        if json_value["type"].as_str() == Option::from("welcome") {
+            //链接成功
+            res_data.code = "-200".to_string();
+            res_data.message = "链接成功,主动发起订阅".to_string();
+            trace!("链接成功,主动发起订阅:");
+        } else if json_value["type"].as_str() == Option::from("ack") {
+            res_data.code = "-201".to_string();
+            res_data.message = "订阅成功".to_string();
+        } else if json_value["type"].as_str() == Option::from("error") {
+            res_data.code = format!("{}", json_value["code"]);
+            res_data.message = format!("{}", json_value["data"].as_str().unwrap());
+        } else if json_value.get("topic").is_some() {
+            res_data.channel = format!("{}", json_value["subject"].as_str().unwrap());
+
+            if json_value["topic"].as_str() == Option::from("/contractAccount/wallet") {
+                res_data.code = "-202".to_string();
+                if json_value["subject"].as_str() == Option::from("availableBalance.change") {
+                    res_data.code = "200".to_string();
+                    res_data.data = json_value["data"].to_string();
+                } else {}
+            } else {
+                res_data.data = json_value["data"].to_string();
+            }
+        } else {
+            res_data.code = "-202".to_string();
+            res_data.message = "未知解析".to_string();
+        }
+        res_data
+    }
+}

+ 405 - 516
exchanges/src/kucoin_swap_ws.rs

@@ -1,516 +1,405 @@
-// use std::collections::{BTreeMap, HashSet};
-// use std::net::{IpAddr, Ipv4Addr, SocketAddr};
-// use std::sync::Arc;
-// use std::sync::atomic::{AtomicBool, Ordering};
-// use std::time::Duration;
-// use tokio::sync::mpsc::Sender;
-// use tracing::{error, info, trace};
-// use crate::{proxy};
-// use url::Url;
-// use crate::kucoin_swap_rest::KucoinSwapRest;
-// use crate::proxy::ParsingDetail;
-// use crate::response_base::ResponseData;
-// use crate::utils::get_time_microsecond;
-//
-//
-// pub enum KucoinWsType {
-//     Public,
-//     Private,
-// }
-//
-// #[derive(Debug)]
-// #[derive(Clone)]
-// pub struct KucoinWsParam {
-//     pub token: String,
-//     pub ws_url: String,
-//     pub ws_ping_interval: i64,
-//     pub ws_ping_timeout: i64,
-// }
-//
-// #[derive(Clone)]                        //订阅枚举
-// pub enum KucoinSubscribeType {
-//     PuContractMarketLevel2Depth50,
-//     PuContractMarketExecution,
-//     PuContractMarkettickerV2,
-//
-//     PrContractAccountWallet,
-//     PrContractPosition,
-//     PrContractMarketTradeOrdersSys,
-//     PrContractMarketTradeOrders,
-// }
-//
-// #[derive(Clone)]
-// pub struct KucoinSwapWs {
-//     pub label: String,
-//     request_url: String,
-//     //实际ws 链接地址
-//     proxy: ParsingDetail,
-//     //代理信息
-//     // login_param: BTreeMap<String, String>,
-//     //登陆数据
-//     ws_param: KucoinWsParam,
-//     //kuconis特殊参数
-//     symbol_s: Vec<String>,
-//     //订阅币对
-//     subscribe_types: Vec<KucoinSubscribeType>,
-//     //订阅信息
-//     sender: Sender<ResponseData>,     //数据通道
-// }
-//
-// impl KucoinSwapWs {
-//     /*******************************************************************************************************/
-//     /*****************************************获取一个对象****************************************************/
-//     /*******************************************************************************************************/
-//     pub async fn new(is_colo: bool,
-//                      login_param: BTreeMap<String, String>,
-//                      ws_type: KucoinWsType,
-//                      sender: Sender<ResponseData>,
-//     ) -> KucoinSwapWs {
-//         return KucoinSwapWs::new_label("default-KucoinSwapWs".to_string(), is_colo, login_param, ws_type, sender).await;
-//     }
-//     pub async fn new_label(label: String, _is_colo: bool,
-//                            login_param: BTreeMap<String, String>,
-//                            ws_type: KucoinWsType,
-//                            sender: Sender<ResponseData>,
-//     ) -> KucoinSwapWs
-//     {
-//         /*******走代理:根据环境变量配置来决定,如果配置了走代理,没有配置不走*******/
-//         let parsing_detail = proxy::ParsingDetail::parsing_environment_variables();
-//
-//         /*******公共频道-私有频道数据组装*/
-//         let mut ws_param = KucoinWsParam {
-//             token: "".to_string(),
-//             ws_url: "".to_string(),
-//             ws_ping_interval: 0,
-//             ws_ping_timeout: 0,
-//         };
-//         let res_data = KucoinSwapWs::get_rul_token(ws_type, login_param.clone()).await;
-//         match res_data {
-//             Ok(param) => {
-//                 ws_param = param
-//             }
-//             Err(error) => {
-//                 error!("-链接地址等参数错误:{:?}", error)
-//             }
-//         }
-//
-//
-//         /*****返回结构体*******/
-//         KucoinSwapWs {
-//             label,
-//             request_url: "".to_string(),
-//             proxy: parsing_detail,
-//             // login_param,
-//             ws_param,
-//             symbol_s: vec![],
-//             subscribe_types: vec![],
-//             sender,
-//         }
-//     }
-//
-//     /*******************************************************************************************************/
-//     /*****************************************订阅函数********************************************************/
-//     /*******************************************************************************************************/
-//     //手动添加订阅信息
-//     pub fn set_subscribe(&mut self, subscribe_types: Vec<KucoinSubscribeType>) {
-//         self.subscribe_types.extend(subscribe_types);
-//     }
-//     //根据当前类型获取对应的频道 地址 与 token
-//     async fn get_rul_token(ws_type: KucoinWsType, login_param: BTreeMap<String, String>) -> Result<KucoinWsParam, reqwest::Error> {
-//         let mut kucoin_exc = KucoinSwapRest::new(false, login_param.clone());
-//         let res_data = match ws_type {
-//             KucoinWsType::Public => {
-//                 kucoin_exc.get_public_token().await
-//             }
-//             KucoinWsType::Private => {
-//                 kucoin_exc.get_private_token().await
-//             }
-//         };
-//
-//         trace!("kucoin-swap-rest 获取ws连接地址:{:?}",res_data);
-//
-//         if res_data.code == "200" {
-//             let mut ws_url = "".to_string();
-//             let mut ws_token = "".to_string();
-//             let mut ws_ping_interval: i64 = 0;
-//             let mut ws_ping_timeout: i64 = 0;
-//
-//
-//             //数据解析
-//             let parsed_json: serde_json::Value = serde_json::from_str(res_data.data.as_str()).unwrap();
-//             if let Some(value) = parsed_json.get("token") {
-//                 let formatted_value = match value {
-//                     serde_json::Value::String(s) => s.clone(),
-//                     _ => value.to_string()
-//                 };
-//                 ws_token = format!("{}", formatted_value);
-//             }
-//             if let Some(endpoint) = parsed_json["instanceServers"][0]["endpoint"].as_str() {
-//                 ws_url = format!("{}", endpoint);
-//             }
-//             if let Some(ping_interval) = parsed_json["instanceServers"][0]["pingInterval"].as_i64() {
-//                 ws_ping_interval = ping_interval;
-//             }
-//             if let Some(ping_timeout) = parsed_json["instanceServers"][0]["pingTimeout"].as_i64() {
-//                 ws_ping_timeout = ping_timeout;
-//             }
-//
-//
-//             Ok(KucoinWsParam { ws_url, token: ws_token, ws_ping_interval, ws_ping_timeout })
-//         } else {
-//             error!("公共/私有-频道获取失败:{:?}", res_data);
-//             panic!("公共/私有-频道获取失败:{:?}", res_data);
-//         }
-//     }
-//     //自定义
-//     pub async fn custom_subscribe(&mut self, bool_v1: Arc<AtomicBool>, b_array: Vec<String>)
-//     {
-//         self.symbol_s = b_array.clone();
-//         self.request_url = format!("{}?token={}", self.ws_param.ws_url, self.ws_param.token);
-//         info!("走普通通道:{}",  self.request_url);
-//         self.run(bool_v1).await;
-//     }
-//
-//     /*******************************************************************************************************/
-//     /*****************************************工具函数********************************************************/
-//     /*******************************************************************************************************/
-//     //订阅枚举解析
-//     pub fn enum_to_string(symbol: String, subscribe_type: KucoinSubscribeType) -> serde_json::Value {
-//         match subscribe_type {
-//             KucoinSubscribeType::PuContractMarketLevel2Depth50 => {//level2
-//                 serde_json::json!({
-//                      "topic": format!("/contractMarket/level2Depth50:{}", symbol),
-//                      "type": "subscribe",
-//                      "response": true
-//                 })
-//             }
-//             KucoinSubscribeType::PuContractMarketExecution => {//match
-//                 serde_json::json!({
-//                      "topic": format!("/contractMarket/execution:{}", symbol),
-//                      "type": "subscribe",
-//                      "response": true
-//                 })
-//             }
-//             KucoinSubscribeType::PuContractMarkettickerV2 => {//tickerV2
-//                 serde_json::json!({
-//                      "topic": format!("/contractMarket/tickerV2:{}", symbol),
-//                      "type": "subscribe",
-//                      "response": true
-//                 })
-//             }
-//             KucoinSubscribeType::PrContractAccountWallet => {//orderMargin.change
-//                 serde_json::json!({
-//                     "type": "subscribe",
-//                     "topic": "/contractAccount/wallet",
-//                     "privateChannel":true,
-//                     "response":true,
-//                 })
-//             }
-//             KucoinSubscribeType::PrContractPosition => {//position.change
-//                 serde_json::json!({
-//                     "type": "subscribe",
-//                     "topic": format!("/contract/position:{}", symbol),
-//                     "privateChannel":true,
-//                     "response":true,
-//                 })
-//             }
-//             KucoinSubscribeType::PrContractMarketTradeOrdersSys => {//orderChange
-//                 serde_json::json!({
-//                     "type": "subscribe",
-//                     "topic": format!("/contractMarket/tradeOrders"),
-//                     "privateChannel":true,
-//                     "response":true,
-//                 })
-//             }
-//             KucoinSubscribeType::PrContractMarketTradeOrders => {//symbolOrderChange
-//                 serde_json::json!({
-//                     "type": "subscribe",
-//                     "topic": format!("/contractMarket/tradeOrders:{}", symbol),
-//                     "privateChannel":true,
-//                     "response":true,
-//                 })
-//             }
-//         }
-//     }
-//     //组装订阅数据
-//     pub fn get_subscription(&self) -> Vec<String> {
-//         let mut array = vec![];
-//         for symbol in &self.symbol_s {
-//             for subscribe_type in &self.subscribe_types {
-//                 let ty_str = Self::enum_to_string(symbol.clone(), subscribe_type.clone());
-//                 array.push(ty_str.to_string());
-//             }
-//         }
-//         array
-//     }
-//     /*******************************************************************************************************/
-//     /*****************************************socket基本*****************************************************/
-//     /*******************************************************************************************************/
-//     async fn run(&self, bool_v1: Arc<AtomicBool>)
-//     {
-//         //订阅信息组装
-//         let subscription = self.get_subscription();
-//         let subscription: Vec<String> = subscription.into_iter().collect::<HashSet<String>>().into_iter().collect();
-//         loop {
-//             tokio::time::sleep(Duration::from_millis(5000)).await;
-//             trace!("要连接咯~~!!{}", self.request_url);
-//             //币安-登陆流程-rest请求获取k然后拿到 key 拼接地址
-//             // if self.is_login { //暂时没看到有订阅的频道需要登陆 所以暂时不做
-//             // }
-//
-//             let request_url = Url::parse(self.request_url.as_str()).unwrap();
-//             //1. 判断是否需要代理,根据代理地址是否存来选择
-//             if self.proxy.ip_address.len() > 0 {
-//                 let ip_array: Vec<&str> = self.proxy.ip_address.split(".").collect();
-//                 let proxy_address = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(
-//                     ip_array[0].parse().unwrap(),
-//                     ip_array[1].parse().unwrap(),
-//                     ip_array[2].parse().unwrap(),
-//                     ip_array[3].parse().unwrap())
-//                 ), self.proxy.port.parse().unwrap());
-//                 let websocket_config = Some(WebSocketConfig {
-//                     max_send_queue: Some(16),
-//                     max_message_size: Some(16 * 1024 * 1024),
-//                     max_frame_size: Some(16 * 1024 * 1024),
-//                     accept_unmasked_frames: false,
-//                 });
-//                 let max_redirects = 5;
-//                 let _ = match connect_with_proxy(request_url.clone(),
-//                                                  proxy_address, websocket_config, max_redirects) {
-//                     Ok(ws) => {
-//                         let bool_v1_clone = Arc::clone(&bool_v1);
-//                         self.proxy_subscription(bool_v1_clone, ws.0, subscription.clone()).await;
-//                     }
-//                     Err(err) => {
-//                         error!("Can't connect(无法连接): {}", err);
-//                     }
-//                 };
-//             } else {
-//                 let _ = match connect(request_url.clone()) {
-//                     Ok(ws) => {
-//                         let bool_v1_clone = Arc::clone(&bool_v1);
-//                         self.subscription(bool_v1_clone, ws.0, subscription.clone()).await;
-//                     }
-//                     Err(err) => {
-//                         // 连接失败时执行的操作
-//                         error!("Can't connect(无法连接): {}", err);
-//                         // 返回一个默认的 WebSocket 对象或其他适当的值
-//                         // 或者根据需要触发 panic 或返回错误信息
-//                     }
-//                 };
-//             }
-//             trace!("退出来咯");
-//
-//             let bool_v1_clone = Arc::clone(&bool_v1);
-//             let bool_v1_v = bool_v1_clone.load(Ordering::SeqCst);
-//             if !bool_v1_v {
-//                 break;
-//             }
-//         }
-//     }
-//
-//     //代理
-//     async fn proxy_subscription(&self, bool_v1: Arc<AtomicBool>, mut web_socket: WebSocket<ProxyAutoStream>,
-//                                 subscription: Vec<String>)
-//     {
-//         info!("走代理-链接成功!开始数据读取");
-//         let label = self.label.clone();
-//         /*****消息溜***/
-//         let mut ping_interval = chrono::Utc::now().timestamp_millis();
-//         let mut ping_timeout = chrono::Utc::now().timestamp_millis();
-//         loop {
-//             tokio::time::sleep(Duration::from_millis(1)).await;
-//             let msg = web_socket.read_message();
-//             match msg {
-//                 Ok(Message::Text(text)) => {
-//                     //心跳-一定时间间隔发送心跳
-//                     let get_time = chrono::Utc::now().timestamp_millis();
-//                     // trace!("--心跳-{}-{}-{}-{}-{}", get_time, ping_interval
-//                     //          , (get_time - ping_interval), self.ws_param.ws_ping_interval, (get_time - ping_interval) >= self.ws_param.ws_ping_interval);
-//                     if (get_time - ping_interval) >= self.ws_param.ws_ping_interval {
-//                         web_socket.write_message(Message::Ping(Vec::from("ping")))
-//                             .unwrap();
-//                         trace!("--发送心跳-ping");
-//                         ping_interval = get_time;
-//                         ping_timeout = get_time;
-//                     } else if (get_time - ping_timeout) > (self.ws_param.ws_ping_timeout + self.ws_param.ws_ping_interval) {
-//                         //心跳超时-发送心跳之后 一定时间没有响应
-//                         trace!("--心跳相应超时-重连");
-//                         break;
-//                     }
-//
-//                     trace!("获取推送:{}",text.clone());
-//                     // trace!(stdout, "Text-响应--{:?}", text.clone()).unwrap();
-//                     let mut res_data = Self::ok_text(label.to_string(), text);
-//                     res_data.time = get_time_microsecond();
-//                     // trace!("获取推送:{:?}", res_data);
-//                     if res_data.code == "-200" {//表示链接成功
-//                         for sub in &subscription {
-//                             trace!("--发起订阅:{:?}", sub);
-//                             web_socket.write_message(Message::Text(sub.parse().unwrap()))
-//                                 .unwrap();
-//                         }
-//                     } else if res_data.code == "-201" {
-//                         trace!("订阅成功:{:?}", res_data);
-//                     } else if res_data.code == "-202" {
-//                         trace!("无用数据:{:?}", res_data);
-//                     } else {
-//                         let sender = self.sender.clone();
-//                         // let prev_time = Utc::now().timestamp_millis();
-//                         tokio::spawn(async move {
-//                             // info!("{:04} {}", Utc::now().timestamp_millis() - prev_time, res_data.channel);
-//                             sender.send(res_data).await.unwrap();
-//                         });
-//                         tokio::spawn(async move {});
-//                     }
-//                 }
-//                 Ok(Message::Ping(s)) => {
-//                     trace!( "Ping-响应--{:?}", String::from_utf8(s.clone()));
-//                     let _ = web_socket.write_message(Message::Pong(Vec::from("pong")));
-//                     trace!( "回应-pong---{:?}", String::from_utf8(s.clone()));
-//                 }
-//                 Ok(Message::Pong(s)) => {
-//                     // trace!("Pong-响应--{:?}", String::from_utf8(s));
-//                     trace!( "Pong-响应--{:?}", String::from_utf8(s.clone()));
-//                     ping_timeout = chrono::Utc::now().timestamp_millis();
-//                 }
-//                 Ok(Message::Close(_)) => {
-//                     // trace!("socket 关闭: ");
-//                     trace!( "Close-响应");
-//                 }
-//                 Err(error) => {
-//                     // trace!("Error receiving message: {}", error);
-//                     error!( "Err-响应{}", error);
-//                     break;
-//                 }
-//                 _ => {}
-//             }
-//
-//
-//             let bool_v1_v = bool_v1.load(Ordering::SeqCst);
-//             if !bool_v1_v {
-//                 break;
-//             }
-//         }
-//         web_socket.close(None).unwrap();
-//     }
-//
-//     //非代理
-//     async fn subscription(&self, bool_v1: Arc<AtomicBool>, mut web_socket: WebSocket<AutoStream>,
-//                           subscription: Vec<String>)
-//     {
-//         info!("链接成功!开始数据读取");
-//         let label = self.label.clone();
-//         /*****消息溜***/
-//         let mut ping_interval = chrono::Utc::now().timestamp_millis();
-//         let mut ping_timeout = chrono::Utc::now().timestamp_millis();
-//         loop {
-//             tokio::time::sleep(Duration::from_millis(1)).await;
-//             let msg = web_socket.read_message();
-//             match msg {
-//                 Ok(Message::Text(text)) => {
-//                     //心跳-一定时间间隔发送心跳
-//                     let get_time = chrono::Utc::now().timestamp_millis();
-//                     // trace!("--心跳-{}-{}-{}-{}-{}", get_time, ping_interval
-//                     //          , (get_time - ping_interval), self.ws_param.ws_ping_interval, (get_time - ping_interval) >= self.ws_param.ws_ping_interval);
-//                     if (get_time - ping_interval) >= self.ws_param.ws_ping_interval {
-//                         web_socket.write_message(Message::Ping(Vec::from("ping")))
-//                             .unwrap();
-//                         trace!("--发送心跳-ping");
-//                         ping_interval = get_time;
-//                         ping_timeout = get_time;
-//                     } else if (get_time - ping_timeout) > (self.ws_param.ws_ping_timeout + self.ws_param.ws_ping_interval) {
-//                         //心跳超时-发送心跳之后 一定时间没有响应
-//                         trace!("--心跳相应超时-重连");
-//                         break;
-//                     }
-//
-//                     trace!("获取推送:{}",text.clone());
-//                     // trace!(stdout, "Text-响应--{:?}", text.clone()).unwrap();
-//                     let mut res_data = Self::ok_text(label.to_string(), text);
-//                     res_data.time = get_time_microsecond();
-//                     // trace!("获取推送:{:?}", res_data);
-//                     if res_data.code == "-200" {//表示链接成功
-//                         for sub in &subscription {
-//                             trace!("--发起订阅:{:?}", sub);
-//                             web_socket.write_message(Message::Text(sub.parse().unwrap()))
-//                                 .unwrap();
-//                         }
-//                     } else if res_data.code == "-201" {
-//                         trace!("订阅成功:{:?}", res_data);
-//                     } else if res_data.code == "-202" {
-//                         trace!("无用数据:{:?}", res_data);
-//                     } else {
-//                         let sender = self.sender.clone();
-//                         tokio::spawn(async move {
-//                             sender.send(res_data).await.unwrap();
-//                         });
-//                         tokio::spawn(async move {});
-//                     }
-//                 }
-//                 Ok(Message::Ping(s)) => {
-//                     trace!("Ping-响应--{:?}", String::from_utf8(s.clone()));
-//                     let _ = web_socket.write_message(Message::Pong(Vec::from("pong")));
-//                     trace!( "回应-pong---{:?}", String::from_utf8(s.clone()));
-//                 }
-//                 Ok(Message::Pong(s)) => {
-//                     // trace!("Pong-响应--{:?}", String::from_utf8(s));
-//                     trace!("Pong-响应--{:?}", String::from_utf8(s.clone()));
-//                     ping_timeout = chrono::Utc::now().timestamp_millis();
-//                 }
-//                 Ok(Message::Close(_)) => {
-//                     // trace!("socket 关闭: ");
-//                     trace!( "Close-响应");
-//                 }
-//                 Err(error) => {
-//                     // trace!("Error receiving message: {}", error);
-//                     error!( "Err-响应{}", error);
-//                     break;
-//                 }
-//                 _ => {}
-//             }
-//
-//             let bool_v1_v = bool_v1.load(Ordering::SeqCst);
-//             if !bool_v1_v {
-//                 break;
-//             }
-//         }
-//         web_socket.close(None).unwrap();
-//     }
-//
-//     //数据解析
-//     pub fn ok_text(label: String, text: String) -> ResponseData
-//     {
-//         let mut res_data = ResponseData::new(lable, "200".to_string(), "success".to_string(), "".to_string());
-//         let json_value: serde_json::Value = serde_json::from_str(&text).unwrap();
-//         //订阅 相应
-//         if json_value["type"].as_str() == Option::from("welcome") {
-//             //链接成功
-//             res_data.code = "-200".to_string();
-//             res_data.message = "链接成功,主动发起订阅".to_string();
-//             trace!("链接成功,主动发起订阅:");
-//         } else if json_value["type"].as_str() == Option::from("ack") {
-//             res_data.code = "-201".to_string();
-//             res_data.message = "订阅成功".to_string();
-//         } else if json_value["type"].as_str() == Option::from("error") {
-//             res_data.code = format!("{}", json_value["code"]);
-//             res_data.message = format!("{}", json_value["data"].as_str().unwrap());
-//         } else if json_value.get("topic").is_some() {
-//             res_data.channel = format!("{}", json_value["subject"].as_str().unwrap());
-//
-//             if json_value["topic"].as_str() == Option::from("/contractAccount/wallet") {
-//                 res_data.code = "-202".to_string();
-//                 if json_value["subject"].as_str() == Option::from("availableBalance.change") {
-//                     res_data.code = "200".to_string();
-//                     res_data.data = json_value["data"].to_string();
-//                 } else {}
-//             } else {
-//                 res_data.data = json_value["data"].to_string();
-//             }
-//         } else {
-//             res_data.code = "-1".to_string();
-//             res_data.message = "未知解析".to_string();
-//         }
-//         res_data
-//     }
-// }
+use std::collections::BTreeMap;
+use std::sync::Arc;
+use std::sync::atomic::AtomicBool;
+
+use futures_channel::mpsc::{UnboundedReceiver, UnboundedSender};
+use tokio::sync::Mutex;
+use tokio_tungstenite::tungstenite::{Error, Message};
+use tracing::{error, info, trace};
+
+use crate::kucoin_swap_rest::KucoinSwapRest;
+use crate::response_base::ResponseData;
+use crate::socket_tool::{AbstractWsMode, HeartbeatType};
+use crate::utils::get_time_microsecond;
+
+//类型
+pub enum KucoinSwapWsType {
+    Public,
+    Private,
+}
+
+
+#[derive(Debug)]
+#[derive(Clone)]
+pub struct KucoinSwapWsParam {
+    pub token: String,
+    pub ws_url: String,
+    pub ws_ping_interval: i64,
+    pub ws_ping_timeout: i64,
+    pub is_ok_subscribe: bool,
+}
+
+//订阅频道
+#[derive(Clone)]
+pub enum KucoinSwapSubscribeType {
+    PuContractMarketLevel2Depth50,
+    PuContractMarketExecution,
+    PuContractMarkettickerV2,
+
+    PrContractAccountWallet,
+    PrContractPosition,
+    PrContractMarketTradeOrdersSys,
+    PrContractMarketTradeOrders,
+}
+
+//账号信息
+#[derive(Clone, Debug)]
+pub struct KucoinSwapLogin {
+    pub access_key: String,
+    pub secret_key: String,
+    pub pass_key: String,
+}
+
+#[derive(Clone)]
+#[allow(dead_code)]
+pub struct KucoinSwapWs {
+    //类型
+    label: String,
+    //地址
+    address_url: String,
+    //账号
+    login_param: Option<KucoinSwapLogin>,
+    //登陆数据
+    ws_param: KucoinSwapWsParam,
+    //币对
+    symbol_s: Vec<String>,
+    //订阅
+    subscribe_types: Vec<KucoinSwapSubscribeType>,
+    //心跳间隔
+    heartbeat_time: u64,
+}
+
+impl KucoinSwapWs {
+    /*******************************************************************************************************/
+    /*****************************************获取一个对象****************************************************/
+    /*******************************************************************************************************/
+    pub async fn new(is_colo: bool, login_param: Option<KucoinSwapLogin>, ws_type: KucoinSwapWsType) -> KucoinSwapWs {
+        return Self::new_label("default-KucoinSwapWs".to_string(), is_colo, login_param, ws_type).await;
+    }
+    pub async fn new_label(label: String, is_colo: bool, login_param: Option<KucoinSwapLogin>, ws_type: KucoinSwapWsType) -> KucoinSwapWs {
+        /*******公共频道-私有频道数据组装*/
+        let mut ws_param = KucoinSwapWsParam {
+            token: "".to_string(),
+            ws_url: "".to_string(),
+            ws_ping_interval: 0,
+            ws_ping_timeout: 0,
+            is_ok_subscribe: false,
+        };
+
+        /*******公共频道-私有频道数据组装*/
+        let res_data = Self::get_rul_token(ws_type, login_param.clone()).await;
+        let address_url = match res_data {
+            Ok(param) => {
+                ws_param = param;
+                format!("{}?token={}", ws_param.ws_url, ws_param.token)
+            }
+            Err(error) => {
+                error!("-链接地址等参数错误:{:?}", error);
+                "".to_string()
+            }
+        };
+
+        if is_colo {
+            info!("开启高速(未配置,走普通:{})通道",address_url);
+        } else {
+            info!("走普通通道:{}",address_url);
+        }
+
+        KucoinSwapWs {
+            label,
+            address_url,
+            login_param,
+            ws_param,
+            symbol_s: vec![],
+            subscribe_types: vec![],
+            heartbeat_time: 1000 * 18,
+        }
+    }
+
+    /*******************************************************************************************************/
+    /*****************************************订阅函数********************************************************/
+    /*******************************************************************************************************/
+    //根据当前类型获取对应的频道 地址 与 token
+    async fn get_rul_token(ws_type: KucoinSwapWsType, login_param: Option<KucoinSwapLogin>) -> Result<KucoinSwapWsParam, reqwest::Error> {
+        let mut kucoin_exc = KucoinSwapRest::new(false, match login_param {
+            None => {
+                let btree_map: BTreeMap<String, String> = BTreeMap::new();
+                btree_map
+            }
+            Some(d) => {
+                let mut btree_map: BTreeMap<String, String> = BTreeMap::new();
+                btree_map.insert("access_key".to_string(), d.access_key);
+                btree_map.insert("secret_key".to_string(), d.secret_key);
+                btree_map.insert("pass_key".to_string(), d.pass_key);
+                btree_map
+            }
+        });
+
+
+        let res_data = match ws_type {
+            KucoinSwapWsType::Public => {
+                kucoin_exc.get_public_token().await
+            }
+            KucoinSwapWsType::Private => {
+                kucoin_exc.get_private_token().await
+            }
+        };
+
+        trace!("kucoin-swap-rest 获取ws连接地址:{:?}",res_data);
+
+        if res_data.code == "200" {
+            let mut ws_url = "".to_string();
+            let mut ws_token = "".to_string();
+            let mut ws_ping_interval: i64 = 0;
+            let mut ws_ping_timeout: i64 = 0;
+
+
+            //数据解析
+            let parsed_json: serde_json::Value = serde_json::from_str(res_data.data.as_str()).unwrap();
+            if let Some(value) = parsed_json.get("token") {
+                let formatted_value = match value {
+                    serde_json::Value::String(s) => s.clone(),
+                    _ => value.to_string()
+                };
+                ws_token = format!("{}", formatted_value);
+            }
+            if let Some(endpoint) = parsed_json["instanceServers"][0]["endpoint"].as_str() {
+                ws_url = format!("{}", endpoint);
+            }
+            if let Some(ping_interval) = parsed_json["instanceServers"][0]["pingInterval"].as_i64() {
+                ws_ping_interval = ping_interval;
+            }
+            if let Some(ping_timeout) = parsed_json["instanceServers"][0]["pingTimeout"].as_i64() {
+                ws_ping_timeout = ping_timeout;
+            }
+
+
+            Ok(KucoinSwapWsParam { ws_url, token: ws_token, ws_ping_interval, ws_ping_timeout, is_ok_subscribe: false })
+        } else {
+            error!("公共/私有-频道获取失败:{:?}", res_data);
+            panic!("公共/私有-频道获取失败:{:?}", res_data);
+        }
+    }
+    //手动添加订阅信息
+    pub fn set_subscribe(&mut self, subscribe_types: Vec<KucoinSwapSubscribeType>) {
+        self.subscribe_types.extend(subscribe_types);
+    }
+    //手动添加币对
+    pub fn set_symbols(&mut self, mut b_array: Vec<String>) {
+        for symbol in b_array.iter_mut() {
+            // 大写
+            *symbol = symbol.to_uppercase();
+            // 字符串替换
+            *symbol = symbol.replace("_", "");
+            *symbol = symbol.replace("-", "");
+        }
+        self.symbol_s = b_array;
+    }
+    fn contains_pr(&self) -> bool {
+        for t in self.subscribe_types.clone() {
+            if match t {
+                KucoinSwapSubscribeType::PuContractMarketLevel2Depth50 => false,
+                KucoinSwapSubscribeType::PuContractMarketExecution => false,
+                KucoinSwapSubscribeType::PuContractMarkettickerV2 => false,
+
+                KucoinSwapSubscribeType::PrContractAccountWallet => true,
+                KucoinSwapSubscribeType::PrContractPosition => true,
+                KucoinSwapSubscribeType::PrContractMarketTradeOrdersSys => true,
+                KucoinSwapSubscribeType::PrContractMarketTradeOrders => true,
+            } {
+                return true;
+            }
+        }
+        false
+    }
+    /*******************************************************************************************************/
+    /*****************************************工具函数********************************************************/
+    /*******************************************************************************************************/
+    //订阅枚举解析
+    pub fn enum_to_string(symbol: String, subscribe_type: KucoinSwapSubscribeType) -> serde_json::Value {
+        match subscribe_type {
+            KucoinSwapSubscribeType::PuContractMarketLevel2Depth50 => {//level2
+                serde_json::json!({
+                     "topic": format!("/contractMarket/level2Depth50:{}", symbol),
+                     "type": "subscribe",
+                     "response": true
+                })
+            }
+            KucoinSwapSubscribeType::PuContractMarketExecution => {//match
+                serde_json::json!({
+                     "topic": format!("/contractMarket/execution:{}", symbol),
+                     "type": "subscribe",
+                     "response": true
+                })
+            }
+            KucoinSwapSubscribeType::PuContractMarkettickerV2 => {//tickerV2
+                serde_json::json!({
+                     "topic": format!("/contractMarket/tickerV2:{}", symbol),
+                     "type": "subscribe",
+                     "response": true
+                })
+            }
+            KucoinSwapSubscribeType::PrContractAccountWallet => {//orderMargin.change
+                serde_json::json!({
+                    "type": "subscribe",
+                    "topic": "/contractAccount/wallet",
+                    "privateChannel":true,
+                    "response":true,
+                })
+            }
+            KucoinSwapSubscribeType::PrContractPosition => {//position.change
+                serde_json::json!({
+                    "type": "subscribe",
+                    "topic": format!("/contract/position:{}", symbol),
+                    "privateChannel":true,
+                    "response":true,
+                })
+            }
+            KucoinSwapSubscribeType::PrContractMarketTradeOrdersSys => {//orderChange
+                serde_json::json!({
+                    "type": "subscribe",
+                    "topic": format!("/contractMarket/tradeOrders"),
+                    "privateChannel":true,
+                    "response":true,
+                })
+            }
+            KucoinSwapSubscribeType::PrContractMarketTradeOrders => {//symbolOrderChange
+                serde_json::json!({
+                    "type": "subscribe",
+                    "topic": format!("/contractMarket/tradeOrders:{}", symbol),
+                    "privateChannel":true,
+                    "response":true,
+                })
+            }
+        }
+    }
+    //订阅信息生成
+    pub fn get_subscription(&self) -> Vec<String> {
+        let mut array = vec![];
+        for symbol in &self.symbol_s {
+            for subscribe_type in &self.subscribe_types {
+                let ty_str = Self::enum_to_string(symbol.clone(), subscribe_type.clone());
+                array.push(ty_str.to_string());
+            }
+        }
+        array
+    }
+    /*******************************************************************************************************/
+    /*****************************************socket基本*****************************************************/
+    /*******************************************************************************************************/
+    //链接
+    pub async fn ws_connect_async(&mut self,
+                                  bool_v1: Arc<AtomicBool>,
+                                  write_tx_am: &Arc<Mutex<UnboundedSender<Message>>>,
+                                  write_rx: UnboundedReceiver<Message>,
+                                  read_tx: UnboundedSender<ResponseData>,
+    ) -> Result<(), Error>
+    {
+        let login_is = self.contains_pr();
+        let subscription = self.get_subscription();
+        let address_url = self.address_url.clone();
+        let label = self.label.clone();
+        let heartbeat_time = self.heartbeat_time.clone();
+
+        //心跳-- 方法内部线程启动
+        let write_tx_clone1 = write_tx_am.clone();
+        tokio::spawn(async move {
+            trace!("线程-异步心跳-开始");
+            AbstractWsMode::ping_or_pong(write_tx_clone1, HeartbeatType::Ping, heartbeat_time).await;
+            trace!("线程-异步心跳-结束");
+        });
+
+
+        //设置订阅
+        let subscribe_array = subscription.clone();
+        if login_is {
+            //登录相关
+        }
+
+
+        //1 链接
+
+        let t2 = tokio::spawn(async move {
+            trace!("线程-异步链接-开始");
+            AbstractWsMode::ws_connect_async(bool_v1, address_url.clone(),
+                                             label.clone(), subscribe_array,
+                                             write_rx, read_tx,
+                                             KucoinSwapWs::message_text,
+                                             KucoinSwapWs::message_ping,
+                                             KucoinSwapWs::message_pong,
+            ).await.expect("kucoin-期货");
+            trace!("线程-异步链接-结束");
+        });
+        tokio::try_join!(t2).unwrap();
+        trace!("线程-心跳与链接-结束");
+
+
+        Ok(())
+    }
+    /*******************************************************************************************************/
+    /*****************************************数据解析*****************************************************/
+    /*******************************************************************************************************/
+    //数据解析-Text
+    pub fn message_text(text: String) -> Option<ResponseData> {
+        let mut response_data = Self::ok_text(text);
+        response_data.time = get_time_microsecond();
+        match response_data.code.as_str() {
+            "200" => Option::from(response_data),
+            "-201" => {
+                trace!("订阅成功:{:?}", response_data);
+                None
+            }
+            "-202" => {
+                trace!("未知解析:{:?}", response_data);
+                None
+            }
+            _ => None
+        }
+    }
+    //数据解析-ping
+    pub fn message_ping(_pi: Vec<u8>) -> Option<ResponseData> {
+        trace!("服务器响应-ping");
+        return None;
+    }
+    //数据解析-pong
+    pub fn message_pong(_po: Vec<u8>) -> Option<ResponseData> {
+        trace!("服务器响应-pong");
+        return None;
+    }
+    //数据解析
+    pub fn ok_text(text: String) -> ResponseData
+    {
+        // trace!("原始数据:{:?}",text);
+        let mut res_data = ResponseData::new("".to_string(), "200".to_string(), "success".to_string(), "".to_string());
+        let json_value: serde_json::Value = serde_json::from_str(&text).unwrap();
+
+        //订阅 相应
+        if json_value["type"].as_str() == Option::from("welcome") {
+            //链接成功
+            res_data.code = "-200".to_string();
+            res_data.message = "链接成功,主动发起订阅".to_string();
+        } else if json_value["type"].as_str() == Option::from("ack") {
+            res_data.code = "-201".to_string();
+            res_data.message = "订阅成功".to_string();
+        } else if json_value["type"].as_str() == Option::from("error") {
+            res_data.code = format!("{}", json_value["code"]);
+            res_data.message = format!("{}", json_value["data"].as_str().unwrap());
+        } else if json_value.get("topic").is_some() {
+            res_data.channel = format!("{}", json_value["subject"].as_str().unwrap());
+
+            if json_value["topic"].as_str() == Option::from("/contractAccount/wallet") {
+                res_data.code = "-202".to_string();
+                if json_value["subject"].as_str() == Option::from("availableBalance.change") {
+                    res_data.code = "200".to_string();
+                    res_data.data = json_value["data"].to_string();
+                } else {}
+            } else {
+                res_data.data = json_value["data"].to_string();
+            }
+        } else {
+            res_data.code = "-202".to_string();
+            res_data.message = "未知解析".to_string();
+        }
+        res_data
+    }
+}

+ 0 - 436
exchanges/src/kucoin_swap_ws_async.rs

@@ -1,436 +0,0 @@
-use std::collections::BTreeMap;
-use std::sync::Arc;
-use std::sync::atomic::AtomicBool;
-
-use futures_channel::mpsc::{UnboundedReceiver, UnboundedSender};
-use tokio::sync::Mutex;
-use tokio_tungstenite::tungstenite::{Error, Message};
-use tracing::{error, info, trace};
-
-use crate::kucoin_swap_rest::KucoinSwapRest;
-use crate::response_base::ResponseData;
-use crate::socket_tool::{AbstractWsMode, HeartbeatType};
-
-pub enum KucoinSwapWsType {
-    //订阅频道类型
-    Public,
-    Private,
-}
-
-#[derive(Debug)]
-#[derive(Clone)]
-pub struct KucoinSwapWsParam {
-    pub token: String,
-    pub ws_url: String,
-    pub ws_ping_interval: i64,
-    pub ws_ping_timeout: i64,
-    pub is_ok_subscribe: bool,
-}
-
-
-#[derive(Clone)]                        //订阅枚举
-pub enum KucoinSwapSubscribeType {
-    PuContractMarketLevel2Depth50,
-    PuContractMarketExecution,
-    PuContractMarkettickerV2,
-
-    PrContractAccountWallet,
-    PrContractPosition,
-    PrContractMarketTradeOrdersSys,
-    PrContractMarketTradeOrders,
-}
-
-#[derive(Clone, Debug)]
-pub struct KucoinSwapLogin {
-    pub access_key: String,
-    pub secret_key: String,
-    pub pass_key: String,
-}
-
-#[derive(Clone)]
-#[allow(dead_code)]
-pub struct KucoinSwapWs {
-    //类型
-    label: String,
-    //地址
-    address_url: String,
-    //账号信息
-    login_param: Option<KucoinSwapLogin>,
-    //登陆数据
-    ws_param: KucoinSwapWsParam,
-    //币对
-    symbol_s: Vec<String>,
-    //订阅
-    subscribe_types: Vec<KucoinSwapSubscribeType>,
-    //心跳间隔
-    heartbeat_time: u64,
-}
-
-impl KucoinSwapWs {
-    /*******************************************************************************************************/
-    /*****************************************获取一个对象****************************************************/
-    /*******************************************************************************************************/
-    pub async fn new(is_colo: bool, login_param: Option<KucoinSwapLogin>, ws_type: KucoinSwapWsType) -> KucoinSwapWs {
-        return Self::new_label("default-KucoinSwapWs".to_string(), is_colo, login_param, ws_type).await;
-    }
-    pub async fn new_label(label: String, is_colo: bool, login_param: Option<KucoinSwapLogin>, ws_type: KucoinSwapWsType) -> KucoinSwapWs {
-        /*******公共频道-私有频道数据组装*/
-        let mut ws_param = KucoinSwapWsParam {
-            token: "".to_string(),
-            ws_url: "".to_string(),
-            ws_ping_interval: 0,
-            ws_ping_timeout: 0,
-            is_ok_subscribe: false,
-        };
-
-        /*******公共频道-私有频道数据组装*/
-        let res_data = Self::get_rul_token(ws_type, login_param.clone()).await;
-        let address_url = match res_data {
-            Ok(param) => {
-                ws_param = param;
-                format!("{}?token={}", ws_param.ws_url, ws_param.token)
-            }
-            Err(error) => {
-                error!("-链接地址等参数错误:{:?}", error);
-                "".to_string()
-            }
-        };
-
-        if is_colo {
-            info!("开启高速(未配置,走普通:{})通道",address_url);
-        } else {
-            info!("走普通通道:{}",address_url);
-        }
-
-        KucoinSwapWs {
-            label,
-            address_url,
-            login_param,
-            ws_param,
-            symbol_s: vec![],
-            subscribe_types: vec![],
-            heartbeat_time: 5000,
-        }
-    }
-
-    /*******************************************************************************************************/
-    /*****************************************订阅函数********************************************************/
-    /*******************************************************************************************************/
-    //根据当前类型获取对应的频道 地址 与 token
-    async fn get_rul_token(ws_type: KucoinSwapWsType, login_param: Option<KucoinSwapLogin>) -> Result<KucoinSwapWsParam, reqwest::Error> {
-        let mut kucoin_exc = KucoinSwapRest::new(false, match login_param {
-            None => {
-                let btree_map: BTreeMap<String, String> = BTreeMap::new();
-                btree_map
-            }
-            Some(d) => {
-                let mut btree_map: BTreeMap<String, String> = BTreeMap::new();
-                btree_map.insert("access_key".to_string(), d.access_key);
-                btree_map.insert("secret_key".to_string(), d.secret_key);
-                btree_map.insert("pass_key".to_string(), d.pass_key);
-                btree_map
-            }
-        });
-
-
-        let res_data = match ws_type {
-            KucoinSwapWsType::Public => {
-                kucoin_exc.get_public_token().await
-            }
-            KucoinSwapWsType::Private => {
-                kucoin_exc.get_private_token().await
-            }
-        };
-
-        trace!("kucoin-swap-rest 获取ws连接地址:{:?}",res_data);
-
-        if res_data.code == "200" {
-            let mut ws_url = "".to_string();
-            let mut ws_token = "".to_string();
-            let mut ws_ping_interval: i64 = 0;
-            let mut ws_ping_timeout: i64 = 0;
-
-
-            //数据解析
-            let parsed_json: serde_json::Value = serde_json::from_str(res_data.data.as_str()).unwrap();
-            if let Some(value) = parsed_json.get("token") {
-                let formatted_value = match value {
-                    serde_json::Value::String(s) => s.clone(),
-                    _ => value.to_string()
-                };
-                ws_token = format!("{}", formatted_value);
-            }
-            if let Some(endpoint) = parsed_json["instanceServers"][0]["endpoint"].as_str() {
-                ws_url = format!("{}", endpoint);
-            }
-            if let Some(ping_interval) = parsed_json["instanceServers"][0]["pingInterval"].as_i64() {
-                ws_ping_interval = ping_interval;
-            }
-            if let Some(ping_timeout) = parsed_json["instanceServers"][0]["pingTimeout"].as_i64() {
-                ws_ping_timeout = ping_timeout;
-            }
-
-
-            Ok(KucoinSwapWsParam { ws_url, token: ws_token, ws_ping_interval, ws_ping_timeout, is_ok_subscribe: false })
-        } else {
-            error!("公共/私有-频道获取失败:{:?}", res_data);
-            panic!("公共/私有-频道获取失败:{:?}", res_data);
-        }
-    }
-    //手动添加订阅信息
-    pub fn set_subscribe(&mut self, subscribe_types: Vec<KucoinSwapSubscribeType>) {
-        self.subscribe_types.extend(subscribe_types);
-    }
-
-    //手动添加币对
-    pub fn set_symbols(&mut self, mut b_array: Vec<String>) {
-        for symbol in b_array.iter_mut() {
-            // 大写
-            *symbol = symbol.to_uppercase();
-            // 字符串替换
-            *symbol = symbol.replace("_", "");
-            *symbol = symbol.replace("-", "");
-        }
-        self.symbol_s = b_array;
-        trace!("币对??:{:?}",self.symbol_s);
-    }
-    fn contains_pr(&self) -> bool {
-        for t in self.subscribe_types.clone() {
-            if match t {
-                KucoinSwapSubscribeType::PuContractMarketLevel2Depth50 => false,
-                KucoinSwapSubscribeType::PuContractMarketExecution => false,
-                KucoinSwapSubscribeType::PuContractMarkettickerV2 => false,
-
-                KucoinSwapSubscribeType::PrContractAccountWallet => true,
-                KucoinSwapSubscribeType::PrContractPosition => true,
-                KucoinSwapSubscribeType::PrContractMarketTradeOrdersSys => true,
-                KucoinSwapSubscribeType::PrContractMarketTradeOrders => true,
-            } {
-                return true;
-            }
-        }
-        false
-    }
-    /*******************************************************************************************************/
-    /*****************************************工具函数********************************************************/
-    /*******************************************************************************************************/
-    //订阅枚举解析
-    pub fn enum_to_string(symbol: String, subscribe_type: KucoinSwapSubscribeType) -> serde_json::Value {
-        match subscribe_type {
-            KucoinSwapSubscribeType::PuContractMarketLevel2Depth50 => {//level2
-                serde_json::json!({
-                     "topic": format!("/contractMarket/level2Depth50:{}", symbol),
-                     "type": "subscribe",
-                     "response": true
-                })
-            }
-            KucoinSwapSubscribeType::PuContractMarketExecution => {//match
-                serde_json::json!({
-                     "topic": format!("/contractMarket/execution:{}", symbol),
-                     "type": "subscribe",
-                     "response": true
-                })
-            }
-            KucoinSwapSubscribeType::PuContractMarkettickerV2 => {//tickerV2
-                serde_json::json!({
-                     "topic": format!("/contractMarket/tickerV2:{}", symbol),
-                     "type": "subscribe",
-                     "response": true
-                })
-            }
-            KucoinSwapSubscribeType::PrContractAccountWallet => {//orderMargin.change
-                serde_json::json!({
-                    "type": "subscribe",
-                    "topic": "/contractAccount/wallet",
-                    "privateChannel":true,
-                    "response":true,
-                })
-            }
-            KucoinSwapSubscribeType::PrContractPosition => {//position.change
-                serde_json::json!({
-                    "type": "subscribe",
-                    "topic": format!("/contract/position:{}", symbol),
-                    "privateChannel":true,
-                    "response":true,
-                })
-            }
-            KucoinSwapSubscribeType::PrContractMarketTradeOrdersSys => {//orderChange
-                serde_json::json!({
-                    "type": "subscribe",
-                    "topic": format!("/contractMarket/tradeOrders"),
-                    "privateChannel":true,
-                    "response":true,
-                })
-            }
-            KucoinSwapSubscribeType::PrContractMarketTradeOrders => {//symbolOrderChange
-                serde_json::json!({
-                    "type": "subscribe",
-                    "topic": format!("/contractMarket/tradeOrders:{}", symbol),
-                    "privateChannel":true,
-                    "response":true,
-                })
-            }
-        }
-    }
-    //组装订阅数据
-    pub fn get_subscription(&self) -> Vec<String> {
-        let mut array = vec![];
-        for symbol in &self.symbol_s {
-            for subscribe_type in &self.subscribe_types {
-                let ty_str = Self::enum_to_string(symbol.clone(), subscribe_type.clone());
-                array.push(ty_str.to_string());
-            }
-        }
-        array
-    }
-    //数据解析
-    pub fn analysis_message(message: Result<Message, Error>) -> Option<ResponseData> {
-        let mut code = "00".to_string();
-        let mut message_str = "".to_string();
-        let data = "".to_string();
-        match message {
-            Ok(Message::Text(text)) => {
-                let response_data = Self::ok_text(text);
-                if response_data.code == "-200" {
-                    trace!("链接成功允许订阅:{:?}", response_data);
-                    return None;
-                } else if response_data.code == "-201" {
-                    trace!("订阅成功:{:?}", response_data);
-                    return None;
-                } else if response_data.code == "-202" {
-                    trace!("未知数据:{:?}", response_data);
-                    return None;
-                } else {
-                    return Option::from(response_data);
-                }
-            }
-
-            Ok(Message::Binary(s)) => {
-                trace!("Binary:{:?}",s);
-            }
-            Ok(Message::Ping(pi)) => {
-                trace!("Ping:{:?}",pi);
-                code = "200".to_string();
-                message_str = format!("服务器响应ping:{:?}", String::from_utf8(pi));
-            }
-            Ok(Message::Pong(po)) => {
-                trace!("Pong:{:?}",po);
-                //原始帧 正常读取数据不会读取到该 信息类型
-                code = "200".to_string();
-                message_str = format!("服务器响应pong:{:?}", String::from_utf8(po));
-            }
-            Ok(Message::Close(c)) => {
-                trace!("Close:{:?}",c);
-                //原始帧 正常读取数据不会读取到该 信息类型
-                code = "0".to_string();
-                message_str = format!("关闭指令:{:?}", c);
-            }
-            Ok(Message::Frame(f)) => {
-                trace!("Frame:{:?}",f);
-                //原始帧 正常读取数据不会读取到该 信息类型
-                code = "-2".to_string();
-                message_str = format!("意外读取到原始帧:{:?}", f);
-            }
-            Err(e) => {
-                trace!("Err:{:?}",e);
-                code = "-1".to_string();
-                message_str = format!("币安-数据解析 未知错误:{:?}", e);
-            }
-        }
-        let zz = ResponseData::new("".to_string(), code, message_str, data);
-        // println!("??{:?}", zz);
-        return Option::from(zz);
-    }
-
-    /*******************************************************************************************************/
-    /*****************************************socket基本*****************************************************/
-    /*******************************************************************************************************/
-    //链接
-    pub async fn ws_connect_async(&mut self,
-                                  bool_v1: Arc<AtomicBool>,
-                                  write_tx_am: &Arc<Mutex<UnboundedSender<Message>>>,
-                                  write_rx: UnboundedReceiver<Message>,
-                                  read_tx: UnboundedSender<ResponseData>,
-    ) -> Result<(), Error>
-    {
-        let login_is = self.contains_pr();
-        let subscription = self.get_subscription();
-        let address_url = self.address_url.clone();
-        let label = self.label.clone();
-        let heartbeat_time = self.heartbeat_time.clone();
-
-        //心跳-- 方法内部线程启动
-        let write_tx_clone1 = write_tx_am.clone();
-        tokio::spawn(async move {
-            trace!("线程-异步心跳-开始");
-            AbstractWsMode::ping_or_pong(write_tx_clone1, HeartbeatType::Ping, heartbeat_time).await;
-            trace!("线程-异步心跳-结束");
-        });
-
-
-        //设置订阅
-        let subscribe_array = subscription.clone();
-        if login_is {
-            //登录相关
-        }
-
-
-        //1 链接
-
-        let t2 = tokio::spawn(async move {
-            trace!("线程-异步链接-开始");
-            AbstractWsMode::ws_connect_async(bool_v1, address_url.clone(),
-                                             label.clone(), subscribe_array,
-                                             write_rx, read_tx, KucoinSwapWs::analysis_message,
-            ).await.expect("kucoin");
-            trace!("线程-异步链接-结束");
-        });
-        tokio::try_join!(t2).unwrap();
-        trace!("线程-心跳与链接-结束");
-
-
-        Ok(())
-    }
-    //发出指令
-    pub fn write_message(&self, write_tx: UnboundedSender<Message>, str: String) {
-        trace!("发送指令:{}",str);
-        write_tx.unbounded_send(Message::Text(str.to_string())).expect(format!("发送失败:{}", str).as_str());
-    }
-
-    //数据解析
-    pub fn ok_text(text: String) -> ResponseData
-    {
-        // trace!("原始数据:{:?}",text);
-        let mut res_data = ResponseData::new("".to_string(), "200".to_string(), "success".to_string(), "".to_string());
-        let json_value: serde_json::Value = serde_json::from_str(&text).unwrap();
-
-        //订阅 相应
-        if json_value["type"].as_str() == Option::from("welcome") {
-            //链接成功
-            res_data.code = "-200".to_string();
-            res_data.message = "链接成功,主动发起订阅".to_string();
-        } else if json_value["type"].as_str() == Option::from("ack") {
-            res_data.code = "-201".to_string();
-            res_data.message = "订阅成功".to_string();
-        } else if json_value["type"].as_str() == Option::from("error") {
-            res_data.code = format!("{}", json_value["code"]);
-            res_data.message = format!("{}", json_value["data"].as_str().unwrap());
-        } else if json_value.get("topic").is_some() {
-            res_data.channel = format!("{}", json_value["subject"].as_str().unwrap());
-
-            if json_value["topic"].as_str() == Option::from("/contractAccount/wallet") {
-                res_data.code = "-202".to_string();
-                if json_value["subject"].as_str() == Option::from("availableBalance.change") {
-                    res_data.code = "200".to_string();
-                    res_data.data = json_value["data"].to_string();
-                } else {}
-            } else {
-                res_data.data = json_value["data"].to_string();
-            }
-        } else {
-            res_data.code = "-1".to_string();
-            res_data.message = "未知解析".to_string();
-        }
-        res_data
-    }
-}

+ 0 - 2
exchanges/src/lib.rs

@@ -19,6 +19,4 @@ pub mod bitget_spot_ws;
 pub mod bitget_spot_rest;
 pub mod kucoin_spot_ws;
 pub mod kucoin_spot_rest;
-pub mod binance_swap_ws_async;//临时文件
-pub mod kucoin_swap_ws_async;//临时文件
 

+ 64 - 114
exchanges/src/socket_tool.rs

@@ -28,74 +28,19 @@ pub enum HeartbeatType {
 pub struct AbstractWsMode {}
 
 impl AbstractWsMode {
-    // pub fn new(write_rx: UnboundedReceiver<Message>,
-    //            read_tx: UnboundedSender<ResponseData>) -> AbstractWsMode {
-    //     AbstractWsMode {
-    //         write_rx,
-    //         read_tx,
-    //     }
-    // }
-    // pub async fn ws_connect_async2<F>(&mut self,
-    //                                   address_url: String,
-    //                                   lable: String,
-    //                                   func: F) -> Result<(), Error>
-    //     where F: Fn(Result<Message, Error>) -> Option<ResponseData>,
-    // {
-    //     //1.是否走代理
-    //     /*******走代理:根据环境变量配置来决定,如果配置了走代理,没有配置不走*******/
-    //     let proxy = match proxy::ParsingDetail::env_proxy(ProxyEnum::WS) {
-    //         ProxyResponseEnum::NO => {
-    //             // trace!("非 代理");
-    //             None
-    //         }
-    //         ProxyResponseEnum::YES(proxy) => {
-    //             // trace!("代理");
-    //             Option::from(proxy)
-    //         }
-    //     };
-    //
-    //     let (ws_stream, _) = connect_async(address_url.clone(), proxy).await.expect("链接失败");
-    //     trace!("WebSocket 握手完成。");
-    //     let (mut write, mut read) = ws_stream.split();
-    //
-    //     //将socket 的写操作与 写通道链接起来,将数据以ok的结构体封装进行传递
-    //     let stdin_to_ws = self.write_rx.map(Ok).forward(write);
-    //     let ws_to_stdout = {
-    //         trace!("---1");
-    //         //读,循环读取,然后拿到 message,,然后开启异步处理 message,
-    //         let result = read.for_each(|message| async {
-    //             let response_data = func(message);
-    //             if response_data.is_some() {
-    //                 let mut data = response_data.unwrap();
-    //                 data.label = lable.clone();
-    //                 let code = data.code.clone();
-    //                 if code.as_str() == "-1" {} else if code.as_str() == "200" {
-    //                     self.read_tx.unbounded_send(data).unwrap();
-    //                 }
-    //             }
-    //         });
-    //         trace!("---3");
-    //         result
-    //     };
-    //
-    //     //必须操作。,因为不同于其他的高级语言,有自动内存管理,所以为了防范地址改变,所以需要做此处理
-    //     pin_mut!(stdin_to_ws, ws_to_stdout,);
-    //     future::select(stdin_to_ws, ws_to_stdout).await;
-    //     trace!("---5");
-    //     trace!("---4");
-    //     Ok(())
-    // }
-
-
     //创建链接
-    pub async fn ws_connect_async<F>(bool_v1: Arc<AtomicBool>,
-                                     address_url: String,
-                                     lable: String,
-                                     subscribe_array: Vec<String>,
-                                     mut write_rx: UnboundedReceiver<Message>,
-                                     read_tx: UnboundedSender<ResponseData>,
-                                     func: F, ) -> Result<(), Error>
-        where F: Fn(Result<Message, Error>) -> Option<ResponseData>,
+    pub async fn ws_connect_async<T, PI, PO>(bool_v1: Arc<AtomicBool>,
+                                             address_url: String,
+                                             lable: String,
+                                             subscribe_array: Vec<String>,
+                                             mut write_rx: UnboundedReceiver<Message>,
+                                             read_tx: UnboundedSender<ResponseData>,
+                                             message_text: T,
+                                             message_ping: PI,
+                                             message_pong: PO) -> Result<(), Error>
+        where T: Fn(String) -> Option<ResponseData> + Copy,
+              PI: Fn(Vec<u8>) -> Option<ResponseData> + Copy,
+              PO: Fn(Vec<u8>) -> Option<ResponseData> + Copy
     {
         //1.是否走代理
         /*******走代理:根据环境变量配置来决定,如果配置了走代理,没有配置不走*******/
@@ -116,6 +61,7 @@ impl AbstractWsMode {
             let (mut write, mut read) = ws_stream.split();
 
             //订阅写入(包括订阅信息 )
+            trace!("订阅内容:{:?}",subscribe_array.clone());
             for s in &subscribe_array {
                 write.send(Message::Text(s.parse().unwrap())).await?;
             }
@@ -131,7 +77,8 @@ impl AbstractWsMode {
             };
             let ws_to_stdout = async {
                 while let Some(message) = read.next().await {
-                    let response_data = func(message);
+                    let response_data = AbstractWsMode::analysis_message(message, message_text, message_ping, message_pong);
+                    // let response_data = func(message);
                     if response_data.is_some() {
                         let mut data = response_data.unwrap();
                         data.label = lable.clone();
@@ -179,47 +126,6 @@ impl AbstractWsMode {
         }
         // return Ok(());
     }
-
-// match connect_async(address_url, proxy).await {
-//     Ok((ws_stream, _)) => {
-//         trace!("WebSocket 握手完成。");
-//         // tokio::task::spawn_local(async move {
-//         let (write, read) = ws_stream.split();
-//
-//         //将socket 的写操作与 写通道链接起来,将数据以ok的结构体封装进行传递
-//         let stdin_to_ws = write_rx.map(Ok).forward(write);
-//         let ws_to_stdout = {
-//             trace!("---1");
-//             //读,循环读取,然后拿到 message,,然后开启异步处理 message,
-//             let result = read.for_each(|message| async {
-//                 // let bool_v1_clone = Arc::clone(&bool_v1);
-//                 // let _bool_v1_v = bool_v1_clone.load(Ordering::SeqCst);
-//                 let response_data = func(message);
-//                 if response_data.is_some() {
-//                     let mut data = response_data.unwrap();
-//                     data.label = lable.clone();
-//                     read_tx.unbounded_send(data).unwrap();
-//                 }
-//             });
-//             trace!("---3");
-//             result
-//         };
-//
-//         //必须操作。,因为不同于其他的高级语言,有自动内存管理,所以为了防范地址改变,所以需要做此处理
-//         pin_mut!(stdin_to_ws, ws_to_stdout,);
-//         future::select(stdin_to_ws, ws_to_stdout).await;
-//         trace!("---5");
-//         trace!("---4");
-//
-//         Ok(())
-//     }
-//     Err(_) => {
-//         trace!("链接失败");
-//         Err(Error::Url(UrlError::UnableToConnect("连接失败".to_string())))
-//     }
-// }
-
-
     //心跳包
     pub async fn ping_or_pong(write_tx_clone: Arc<Mutex<UnboundedSender<Message>>>, h_type: HeartbeatType, millis: u64) {
         loop {
@@ -235,10 +141,54 @@ impl AbstractWsMode {
                     }
                 }
             ).expect("发送失败");
-            trace!("发起心跳:{:?}",h_type);
+            trace!("发送指令-心跳:{:?}",h_type);
+        }
+    }
+    //数据解析
+    pub fn analysis_message<T, PI, PO>(message: Result<Message, Error>,
+                                       message_text: T,
+                                       message_ping: PI,
+                                       message_pong: PO) -> Option<ResponseData>
+        where T: Fn(String) -> Option<ResponseData>,
+              PI: Fn(Vec<u8>) -> Option<ResponseData>,
+              PO: Fn(Vec<u8>) -> Option<ResponseData>
+    {
+        match message {
+            Ok(Message::Text(text)) => message_text(text),
+            Ok(Message::Ping(pi)) => message_ping(pi),
+            Ok(Message::Pong(po)) => message_pong(po),
+            Ok(Message::Binary(s)) => {
+                //二进制WebSocket消息
+                let message_str = format!("Binary:{:?}", s);
+                trace!("{:?}",message_str);
+                Option::from(ResponseData::new("".to_string(),
+                                               "2".to_string(),
+                                               message_str, "".to_string()))
+            }
+            Ok(Message::Close(c)) => {
+                let message_str = format!("关闭指令:{:?}", c);
+                trace!("{:?}",message_str);
+                Option::from(ResponseData::new("".to_string(),
+                                               "0".to_string(),
+                                               message_str, "".to_string()))
+            }
+            Ok(Message::Frame(f)) => {
+                //原始帧 正常读取数据不会读取到该 信息类型
+                let message_str = format!("意外读取到原始帧:{:?}", f);
+                trace!("{:?}",message_str);
+                Option::from(ResponseData::new("".to_string(),
+                                               "-2".to_string(),
+                                               message_str, "".to_string()))
+            }
+            Err(e) => {
+                let message_str = format!("服务器响应:{:?}", e);
+                trace!("{:?}",message_str);
+                Option::from(ResponseData::new("".to_string(),
+                                               "-1".to_string(),
+                                               message_str, "".to_string()))
+            }
         }
     }
-
     //发送数据
     pub async fn send_subscribe(write_tx_clone: Arc<Mutex<UnboundedSender<Message>>>, message: Message) -> bool {
         let write_tx_clone = write_tx_clone.lock().await;
@@ -374,9 +324,9 @@ async fn read_sell(mut rx: futures_channel::mpsc::UnboundedReceiver<Message>) {
 pub fn log_in_to_str() -> String {
     let mut login_json_str = "".to_string();
 
-    let access_key: String = "b812814f-b792-432c-9c65-44ebe3b8976b".to_string();
-    let secret_key: String = "D6AF4764DF5FDC74BF2CC88A4A8FD035".to_string();
-    let passphrase: String = "Astest!@#1".to_string();
+    let access_key: String = "".to_string();
+    let secret_key: String = "".to_string();
+    let passphrase: String = "".to_string();
 
     if access_key.len() > 0 || secret_key.len() > 0 || passphrase.len() > 0 {
         let timestamp = Utc::now().timestamp().to_string();

+ 68 - 26
exchanges/tests/binance_spot_test.rs

@@ -1,11 +1,14 @@
-use std::collections::BTreeMap;
 use std::sync::Arc;
 use std::sync::atomic::AtomicBool;
-use tokio::sync::mpsc::{channel, Sender};
-use tokio::try_join;
+use std::time::Duration;
+use futures_util::StreamExt;
+
+use tokio::sync::Mutex;
+use tokio_tungstenite::tungstenite::Message;
 use tracing::trace;
-use exchanges::binance_spot_ws::{BinanceSpotSubscribeType, BinanceSpotWs, BinanceSpotWsType};
-use exchanges::response_base::ResponseData;
+
+use exchanges::binance_spot_ws::{BinanceSpotLogin, BinanceSpotSubscribeType, BinanceSpotWs, BinanceSpotWsType};
+use exchanges::socket_tool::AbstractWsMode;
 
 // 账号密码
 const ACCESS_KEY: &str = "";
@@ -17,36 +20,75 @@ const SECRET_KEY: &str = "";
 async fn ws_custom_subscribe() {
     global::log_utils::init_log_with_trace();
 
-    let  bool_v1 = Arc::new(AtomicBool::new(true));
-    let mut  btree_map: BTreeMap<String, String> = BTreeMap::new();
-    btree_map.insert("access_key".to_string(), ACCESS_KEY.to_string());
-    btree_map.insert("secret_key".to_string(), SECRET_KEY.to_string());
-    let (tx, mut rx) = channel(1024);
-    let mut ws = get_ws(btree_map, tx);
+    let (write_tx, write_rx) = futures_channel::mpsc::unbounded();
+    let (read_tx, mut read_rx) = futures_channel::mpsc::unbounded();
+
+    let login_param = BinanceSpotLogin {
+        api_key: ACCESS_KEY.to_string(),
+        api_secret: SECRET_KEY.to_string(),
+    };
+    let mut ws = get_ws(None);
+    ws.set_symbols(vec!["BTC_USDT".to_string()]);
     ws.set_subscribe(vec![
-        BinanceSpotSubscribeType::PuBookTicker,
+        // BinanceSpotSubscribeType::PuBookTicker,
         BinanceSpotSubscribeType::PuAggTrade,
-        BinanceSpotSubscribeType::PuDepth20levels100ms,
-
+        // BinanceSpotSubscribeType::PuDepth20levels100ms,
     ]);
-    let t1 = tokio::spawn(async move {
-        ws.custom_subscribe(bool_v1, vec!["BTCUSDT".to_string()]).await;
-    });
-    let t2 = tokio::spawn(async move {
+
+    let write_tx_am = Arc::new(Mutex::new(write_tx));
+    let bool_v1 = Arc::new(AtomicBool::new(true));
+
+    //读取
+    let _bool_v1_clone = Arc::clone(&bool_v1);
+    let _tr = tokio::spawn(async move {
+        trace!("线程-数据读取-开启");
         loop {
-            if let Ok(received) = rx.try_recv() {
-                trace!( "age: {:?}", received);
+            if let Some(data) = read_rx.next().await {
+                trace!("读取数据data:{:?}",data)
             }
         }
+        // trace!("线程-数据读取-结束");
+    });
+
+    //写数据
+    let bool_v2_clone = Arc::clone(&bool_v1);
+    let write_tx_clone = Arc::clone(&write_tx_am);
+    let su = ws.get_subscription();
+    let tw = tokio::spawn(async move {
+        trace!("线程-数据写入-开始");
+        loop {
+            tokio::time::sleep(Duration::from_millis(20 * 1000)).await;
+            // let close_frame = CloseFrame {
+            //     code: CloseCode::Normal,
+            //     reason: Cow::Borrowed("Bye bye"),
+            // };
+            // let message = Message::Close(Some(close_frame));
+
+
+            let message = Message::Text(su.clone());
+            AbstractWsMode::send_subscribe(write_tx_clone.clone(), message.clone()).await;
+            trace!("发送指令成功");
+        }
+        trace!("线程-数据写入-结束");
+    });
+
+    let t1 = tokio::spawn(async move {
+        //链接
+        let bool_v3_clone = Arc::clone(&bool_v1);
+        ws.ws_connect_async(bool_v3_clone, &write_tx_am, write_rx, read_tx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
+        trace!("test 唯一线程结束--");
     });
-    try_join!(t1,t2).unwrap();
+    tokio::try_join!(t1).unwrap();
+    trace!("当此结束");
+    trace!("重启!");
+    trace!("参考交易所关闭");
+    return;
 }
 
-fn get_ws(btree_map: BTreeMap<String, String>, tx: Sender<ResponseData>) -> BinanceSpotWs {
-    let  binance_ws = BinanceSpotWs::new(false,
-                                            btree_map,
-                                            BinanceSpotWsType::PublicAndPrivate,
-                                            tx);
+fn get_ws(login_param: Option<BinanceSpotLogin>) -> BinanceSpotWs {
+    let binance_ws = BinanceSpotWs::new(false,
+                                        login_param, BinanceSpotWsType::PublicAndPrivate,
+    );
     binance_ws
 }
 

+ 29 - 27
exchanges/tests/binance_swap_test.rs

@@ -1,13 +1,19 @@
+use std::borrow::Cow;
 use std::collections::BTreeMap;
 use std::sync::Arc;
 use std::sync::atomic::AtomicBool;
+use std::time::Duration;
 
 use futures_util::StreamExt;
 use tokio::sync::Mutex;
+use tokio_tungstenite::tungstenite::Message;
+use tokio_tungstenite::tungstenite::protocol::CloseFrame;
+use tokio_tungstenite::tungstenite::protocol::frame::coding::CloseCode;
 use tracing::trace;
 
 use exchanges::binance_swap_rest::BinanceSwapRest;
-use exchanges::binance_swap_ws_async::{BinanceSwapLogin, BinanceSwapSubscribeType, BinanceSwapWs, BinanceSwapWsType};
+use exchanges::binance_swap_ws::{BinanceSwapLogin, BinanceSwapSubscribeType, BinanceSwapWs, BinanceSwapWsType};
+use exchanges::socket_tool::AbstractWsMode;
 
 const ACCESS_KEY: &str = "";
 const SECRET_KEY: &str = "";
@@ -34,47 +40,44 @@ async fn ws_custom_subscribe() {
         // BinanceSwapSubscribeType::PuDepth20levels100ms,
     ]);
 
-    /*
-    当前问题 卡在,重连机制采用循环的方式,这样会出现通道的引用限制,所以考虑将重连机制的循环拿到最外层,
-        然后现在是的问题是,正常关闭链接,有某个线程没有关闭,导致进程没有结束,无法达成 重连的触发条件
-    */
-
 
     let write_tx_am = Arc::new(Mutex::new(write_tx));
     let bool_v1 = Arc::new(AtomicBool::new(true));
 
     //读取
-    let bool_v1_clone = Arc::clone(&bool_v1);
-    let tr = tokio::spawn(async move {
+    let _bool_v1_clone = Arc::clone(&bool_v1);
+    let _tr = tokio::spawn(async move {
         trace!("线程-数据读取-开启");
         loop {
             if let Some(data) = read_rx.next().await {
-                trace!("读取数据data:{:?}",data)
+                // trace!("读取数据data:{:?}",data)
             }
         }
-        trace!("线程-数据读取-结束");
+        // trace!("线程-数据读取-结束");
     });
 
     //写数据
     let bool_v2_clone = Arc::clone(&bool_v1);
     let write_tx_clone = Arc::clone(&write_tx_am);
-    // let tw = tokio::spawn(async move {
-    //     trace!("线程-数据写入-开始");
-    //     loop {
-    //         tokio::time::sleep(Duration::from_millis(20*1000)).await;
-    //         let close_frame = CloseFrame {
-    //             code: CloseCode::Normal,
-    //             reason: Cow::Borrowed("Bye bye"),
-    //         };
-    //         let close_message = Message::Close(Some(close_frame));
-    //         // AbstractWsMode::send_subscribe(write_tx_clone.clone(), Message::Text("32313221".to_string()));
-    //         AbstractWsMode::send_subscribe(write_tx_clone.clone(), close_message);
-    //         trace!("发送指令成功");
-    //     }
-    //     trace!("线程-数据写入-结束");
-    // });
+    let su = ws.get_subscription();
+    let tw = tokio::spawn(async move {
+        trace!("线程-数据写入-开始");
+        loop {
+            tokio::time::sleep(Duration::from_millis(20 * 1000)).await;
+            // let close_frame = CloseFrame {
+            //     code: CloseCode::Normal,
+            //     reason: Cow::Borrowed("Bye bye"),
+            // };
+            // let message = Message::Close(Some(close_frame));
+
+
+            let message = Message::Text(su.clone());
+            AbstractWsMode::send_subscribe(write_tx_clone.clone(), message.clone()).await;
+            trace!("发送指令成功");
+        }
+        trace!("线程-数据写入-结束");
+    });
 
-    // loop {
     let t1 = tokio::spawn(async move {
         //链接
         let bool_v3_clone = Arc::clone(&bool_v1);
@@ -83,7 +86,6 @@ async fn ws_custom_subscribe() {
     });
     tokio::try_join!(t1).unwrap();
     trace!("当此结束");
-    // }
     trace!("重启!");
     trace!("参考交易所关闭");
     return;

+ 116 - 41
exchanges/tests/kucoin_spot_test.rs

@@ -1,42 +1,81 @@
 use std::collections::BTreeMap;
 use std::sync::Arc;
 use std::sync::atomic::AtomicBool;
-use tokio::sync::mpsc::{channel, Sender};
-use tokio::try_join;
+
+use futures_util::StreamExt;
+use tokio::sync::Mutex;
 use tracing::trace;
+
 use exchanges::kucoin_spot_rest::KucoinSpotRest;
-use exchanges::kucoin_spot_ws::{KucoinSpotWs, KucoinSubscribeType, KucoinWsType};
-use exchanges::response_base::ResponseData;
+use exchanges::kucoin_spot_ws::{KucoinSpotLogin, KucoinSpotSubscribeType, KucoinSpotWs, KucoinSpotWsType};
 
 const ACCESS_KEY: &str = "";
 const SECRET_KEY: &str = "";
 const PASS_KEY: &str = "";
 
 //ws-订阅公共频道信息
-#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
+#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
 async fn ws_custom_subscribe_pu() {
     global::log_utils::init_log_with_trace();
 
-    let mut bool_v1 = Arc::new(AtomicBool::new(true));
-    let btree_map: BTreeMap<String, String> = BTreeMap::new();
-    let (tx, mut rx) = channel(1024);
-    let mut ws = get_ws(btree_map, KucoinWsType::Public, tx).await;
+    let (write_tx, write_rx) = futures_channel::mpsc::unbounded();
+    let (read_tx, mut read_rx) = futures_channel::mpsc::unbounded();
+
+
+    let mut ws = get_ws(None, KucoinSpotWsType::Public).await;
+    ws.set_symbols(vec!["BTC-USDT".to_string()]);
     ws.set_subscribe(vec![
-        // KucoinSubscribeType::PuMarketMatch,
-        KucoinSubscribeType::PuSpotMarketLevel2Depth50,
-        // KucoinSubscribeType::PuMarketTicker,
+        KucoinSpotSubscribeType::PuSpotMarketLevel2Depth50,
+        KucoinSpotSubscribeType::PuMarketTicker,
+        KucoinSpotSubscribeType::PuMarketMatch,
     ]);
-    let t1 = tokio::spawn(async move {
-        ws.custom_subscribe(bool_v1, vec!["ACH_USDT".to_string(), "ROSE_USDT".to_string()]).await;
-    });
-    let t2 = tokio::spawn(async move {
+
+    let write_tx_am = Arc::new(Mutex::new(write_tx));
+    let bool_v1 = Arc::new(AtomicBool::new(true));
+
+    //读取
+    let _bool_v1_clone = Arc::clone(&bool_v1);
+    let _tr = tokio::spawn(async move {
+        trace!("线程-数据读取-开启");
         loop {
-            if let Ok(received) = rx.try_recv() {
-                trace!( "age: {:?}", received);
+            if let Some(data) = read_rx.next().await {
+                trace!("读取数据data:{:?}",data)
             }
         }
     });
-    try_join!(t1,t2).unwrap();
+
+    //写数据
+    let _bool_v2_clone = Arc::clone(&bool_v1);
+    let _write_tx_clone = Arc::clone(&write_tx_am);
+    // let tw = tokio::spawn(async move {
+    //     trace!("线程-数据写入-开始");
+    //     loop {
+    //         tokio::time::sleep(Duration::from_millis(20*1000)).await;
+    //         let close_frame = CloseFrame {
+    //             code: CloseCode::Normal,
+    //             reason: Cow::Borrowed("Bye bye"),
+    //         };
+    //         let close_message = Message::Close(Some(close_frame));
+    //         // AbstractWsMode::send_subscribe(write_tx_clone.clone(), Message::Text("32313221".to_string()));
+    //         AbstractWsMode::send_subscribe(write_tx_clone.clone(), close_message);
+    //         trace!("发送指令成功");
+    //     }
+    //     trace!("线程-数据写入-结束");
+    // });
+
+    // loop {
+    let t1 = tokio::spawn(async move {
+        //链接
+        let bool_v3_clone = Arc::clone(&bool_v1);
+        ws.ws_connect_async(bool_v3_clone, &write_tx_am, write_rx, read_tx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
+        trace!("test 唯一线程结束--");
+    });
+    tokio::try_join!(t1).unwrap();
+    trace!("当此结束");
+    // }
+    trace!("重启!");
+    trace!("参考交易所关闭");
+    return;
 }
 
 //ws-订阅私有频道信息
@@ -44,30 +83,67 @@ async fn ws_custom_subscribe_pu() {
 async fn ws_custom_subscribe_pr() {
     global::log_utils::init_log_with_trace();
 
-    let mut bool_v1 = Arc::new(AtomicBool::new(true));
-    let mut btree_map: BTreeMap<String, String> = BTreeMap::new();
-    btree_map.insert("access_key".to_string(), ACCESS_KEY.to_string());
-    btree_map.insert("secret_key".to_string(), SECRET_KEY.to_string());
-    btree_map.insert("pass_key".to_string(), PASS_KEY.to_string());
-    let (tx, mut rx) = channel(1024);
-    let mut ws = get_ws(btree_map, KucoinWsType::Private, tx).await;
+    let (write_tx, write_rx) = futures_channel::mpsc::unbounded();
+    let (read_tx, mut read_rx) = futures_channel::mpsc::unbounded();
+
+    let btree_map = KucoinSpotLogin {
+        access_key: ACCESS_KEY.to_string(),
+        secret_key: SECRET_KEY.to_string(),
+        pass_key: PASS_KEY.to_string(),
+    };
+    let mut ws = get_ws(Option::from(btree_map), KucoinSpotWsType::Public).await;
+    ws.set_symbols(vec!["BTC-USDT".to_string()]);
     ws.set_subscribe(vec![
-        KucoinSubscribeType::PrAccountBalance,
-        KucoinSubscribeType::PrSpotMarketTradeOrders,
-        KucoinSubscribeType::PuMarketTicker,
+        KucoinSpotSubscribeType::PrAccountBalance,
+        KucoinSpotSubscribeType::PrSpotMarketTradeOrders,
     ]);
-    let t1 = tokio::spawn(async move {
-        ws.custom_subscribe(bool_v1, vec!["ACH_USDT".to_string(), "ROSE_USDT".to_string()]).await;
-    });
 
-    let t2 = tokio::spawn(async move {
+    let write_tx_am = Arc::new(Mutex::new(write_tx));
+    let bool_v1 = Arc::new(AtomicBool::new(true));
+
+    //读取
+    let _bool_v1_clone = Arc::clone(&bool_v1);
+    let _tr = tokio::spawn(async move {
+        trace!("线程-数据读取-开启");
         loop {
-            if let Ok(received) = rx.try_recv() {
-                trace!( "age: {:?}", received);
+            if let Some(data) = read_rx.next().await {
+                trace!("读取数据data:{:?}",data)
             }
         }
     });
-    try_join!(t1,t2).unwrap();
+
+    //写数据
+    let _bool_v2_clone = Arc::clone(&bool_v1);
+    let _write_tx_clone = Arc::clone(&write_tx_am);
+    // let tw = tokio::spawn(async move {
+    //     trace!("线程-数据写入-开始");
+    //     loop {
+    //         tokio::time::sleep(Duration::from_millis(20*1000)).await;
+    //         let close_frame = CloseFrame {
+    //             code: CloseCode::Normal,
+    //             reason: Cow::Borrowed("Bye bye"),
+    //         };
+    //         let close_message = Message::Close(Some(close_frame));
+    //         // AbstractWsMode::send_subscribe(write_tx_clone.clone(), Message::Text("32313221".to_string()));
+    //         AbstractWsMode::send_subscribe(write_tx_clone.clone(), close_message);
+    //         trace!("发送指令成功");
+    //     }
+    //     trace!("线程-数据写入-结束");
+    // });
+
+    // loop {
+    let t1 = tokio::spawn(async move {
+        //链接
+        let bool_v3_clone = Arc::clone(&bool_v1);
+        ws.ws_connect_async(bool_v3_clone, &write_tx_am, write_rx, read_tx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
+        trace!("test 唯一线程结束--");
+    });
+    tokio::try_join!(t1).unwrap();
+    trace!("当此结束");
+    // }
+    trace!("重启!");
+    trace!("参考交易所关闭");
+    return;
 }
 
 
@@ -88,7 +164,6 @@ async fn rest_get_fills_test() {
 }
 
 
-
 //rest-获取订单
 #[tokio::test]
 async fn rest_get_order_test() {
@@ -170,9 +245,9 @@ async fn rest_cancel_order_by_client_id_test() {
 }
 
 
-async fn get_ws(btree_map: BTreeMap<String, String>, type_v: KucoinWsType, tx: Sender<ResponseData>) -> KucoinSpotWs {
-    let mut ku_ws = KucoinSpotWs::new(false, btree_map.clone(),
-                                      type_v, tx).await;
+async fn get_ws(btree_map: Option<KucoinSpotLogin>, type_v: KucoinSpotWsType) -> KucoinSpotWs {
+    let ku_ws = KucoinSpotWs::new(false, btree_map,
+                                  type_v).await;
     ku_ws
 }
 
@@ -184,6 +259,6 @@ fn get_rest() -> KucoinSpotRest {
     btree_map.insert("secret_key".to_string(), SECRET_KEY.to_string());
     btree_map.insert("pass_key".to_string(), PASS_KEY.to_string());
 
-    let mut ku_exc = KucoinSpotRest::new(false, btree_map);
+    let ku_exc = KucoinSpotRest::new(false, btree_map);
     ku_exc
 }

+ 128 - 122
exchanges/tests/kucoin_swap_test.rs

@@ -1,162 +1,168 @@
-use std::collections::BTreeMap;
 use std::sync::Arc;
 use std::sync::atomic::AtomicBool;
-use tokio::sync::mpsc::{channel, Sender};
-use tokio::try_join;
+
+use futures_util::StreamExt;
+use tokio::sync::Mutex;
 use tracing::trace;
-use exchanges::binance_swap_rest::BinanceSwapRest;
-use exchanges::binance_swap_ws::{BinanceSubscribeType, BinanceSwapWs, BinanceWsType};
-use exchanges::kucoin_swap_rest::KucoinSwapRest;
-use exchanges::kucoin_swap_ws::{KucoinSubscribeType, KucoinSwapWs, KucoinWsType};
-use exchanges::proxy;
-use exchanges::response_base::ResponseData;
+
+use exchanges::kucoin_swap_ws::{KucoinSwapLogin, KucoinSwapSubscribeType, KucoinSwapWs, KucoinSwapWsType};
 
 const ACCESS_KEY: &str = "";
 const SECRET_KEY: &str = "";
 const PASS_KEY: &str = "";
 
 //ws-订阅公共频道信息
-#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
+#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
 async fn ws_custom_subscribe_pu() {
     global::log_utils::init_log_with_trace();
 
-    let mut bool_v1 = Arc::new(AtomicBool::new(true));
-    let btree_map: BTreeMap<String, String> = BTreeMap::new();
-    let (tx, mut rx) = channel(1024);
-    let mut ws = get_ws(btree_map, KucoinWsType::Public, tx).await;
-    ws.set_subscribe(vec![
-        KucoinSubscribeType::PuContractMarketExecution,
-        // KucoinSubscribeType::PuContractMarketLevel2Depth50,
-        // KucoinSubscribeType::PuContractMarkettickerV2,
-    ]);
-    let t1 = tokio::spawn(async move {
-        ws.custom_subscribe(bool_v1, vec!["ACHUSDTM".to_string(), "ROSEUSDTM".to_string(), "xbtusdtM".to_string()]).await;
-    });
-    let t2 = tokio::spawn(async move {
-        loop {
-            if let Ok(received) = rx.try_recv() {
-                trace!( "age: {:?}", received);
-            }
-        }
-    });
-    try_join!(t1,t2).unwrap();
-}
 
-//ws-订阅私有频道信息
-#[tokio::test(flavor = "multi_thread", worker_threads = 2)]
-async fn ws_custom_subscribe_pr() {
-    global::log_utils::init_log_with_trace();
+    let (write_tx, write_rx) = futures_channel::mpsc::unbounded();
+    let (read_tx, mut read_rx) = futures_channel::mpsc::unbounded();
 
-    let mut bool_v1 = Arc::new(AtomicBool::new(true));
-    let mut btree_map: BTreeMap<String, String> = BTreeMap::new();
-    btree_map.insert("access_key".to_string(), ACCESS_KEY.to_string());
-    btree_map.insert("secret_key".to_string(), SECRET_KEY.to_string());
-    btree_map.insert("pass_key".to_string(), PASS_KEY.to_string());
-    let (tx, mut rx) = channel(1024);
-    let mut ws = get_ws(btree_map, KucoinWsType::Private, tx).await;
+
+
+    let mut ws = get_ws(None, KucoinSwapWsType::Public).await;
+    ws.set_symbols(vec!["xbt_usdtM".to_string()]);
     ws.set_subscribe(vec![
-        KucoinSubscribeType::PrContractPosition,
-        KucoinSubscribeType::PrContractAccountWallet,
-        KucoinSubscribeType::PrContractMarketTradeOrdersSys,
-        KucoinSubscribeType::PrContractPosition,
+        KucoinSwapSubscribeType::PuContractMarketLevel2Depth50,
+        KucoinSwapSubscribeType::PuContractMarketExecution,
+        KucoinSwapSubscribeType::PuContractMarkettickerV2,
     ]);
-    let t1 = tokio::spawn(async move {
-        ws.custom_subscribe(bool_v1, vec!["ACHUSDTM".to_string(), "ROSEUSDTM".to_string()]).await;
-    });
 
-    let t2 = tokio::spawn(async move {
+
+    let write_tx_am = Arc::new(Mutex::new(write_tx));
+    let bool_v1 = Arc::new(AtomicBool::new(true));
+
+    //读取
+    let _bool_v1_clone = Arc::clone(&bool_v1);
+    let _tr = tokio::spawn(async move {
+        trace!("线程-数据读取-开启");
         loop {
-            if let Ok(received) = rx.try_recv() {
-                trace!( "age: {:?}", received);
+            if let Some(data) = read_rx.next().await {
+                trace!("读取数据data:{:?}",data)
             }
         }
     });
-    try_join!(t1,t2).unwrap();
-}
-
 
-//rest-获取成交记录
-#[tokio::test]
-async fn rest_get_fills_test() {
-    global::log_utils::init_log_with_trace();
-
-    let mut rest = get_rest();
-    let rep_data = rest.get_fills("BLZUSDTM".to_string(),
-                                  "".to_string(),
-                                  "".to_string(),
-                                  -1,
-                                  -1,
-                                  500,
-    ).await;
-    trace!(?rep_data)
+    //写数据
+    let _bool_v2_clone = Arc::clone(&bool_v1);
+    let _write_tx_clone = Arc::clone(&write_tx_am);
+    // let tw = tokio::spawn(async move {
+    //     trace!("线程-数据写入-开始");
+    //     loop {
+    //         tokio::time::sleep(Duration::from_millis(20*1000)).await;
+    //         let close_frame = CloseFrame {
+    //             code: CloseCode::Normal,
+    //             reason: Cow::Borrowed("Bye bye"),
+    //         };
+    //         let close_message = Message::Close(Some(close_frame));
+    //         // AbstractWsMode::send_subscribe(write_tx_clone.clone(), Message::Text("32313221".to_string()));
+    //         AbstractWsMode::send_subscribe(write_tx_clone.clone(), close_message);
+    //         trace!("发送指令成功");
+    //     }
+    //     trace!("线程-数据写入-结束");
+    // });
+
+    // loop {
+    let t1 = tokio::spawn(async move {
+        //链接
+        let bool_v3_clone = Arc::clone(&bool_v1);
+        ws.ws_connect_async(bool_v3_clone, &write_tx_am, write_rx, read_tx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
+        trace!("test 唯一线程结束--");
+    });
+    tokio::try_join!(t1).unwrap();
+    trace!("当此结束");
+    // }
+    trace!("重启!");
+    trace!("参考交易所关闭");
+    return;
 }
 
-//rest-撤销全部订单
-#[tokio::test]
-async fn rest_cancel_orders_test() {
+//ws-订阅私有频道信息
+#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
+async fn ws_custom_subscribe_pr() {
     global::log_utils::init_log_with_trace();
 
-    let mut rest = get_rest();
-    let rep_data = rest.cancel_orders("BLZUSDTM".to_string()).await;
-    trace!(?rep_data)
-}
 
-//rest-撤销全部订单
-#[tokio::test]
-async fn rest_cancel_order_all_test() {
-    global::log_utils::init_log_with_trace();
+    //对象
+    let btree_map = KucoinSwapLogin {
+        access_key: ACCESS_KEY.to_string(),
+        secret_key: SECRET_KEY.to_string(),
+        pass_key: PASS_KEY.to_string(),
+    };
 
-    let mut rest = get_rest();
-    let rep_data = rest.cancel_order_all().await;
-    trace!(?rep_data)
-}
+    let (write_tx, write_rx) = futures_channel::mpsc::unbounded();
+    let (read_tx, mut read_rx) = futures_channel::mpsc::unbounded();
 
+    // let (write_tx, write_rx) = tokio::sync::broadcast::channel::<Message>(10);
+    // let (read_tx, mut read_rx) = tokio::sync::broadcast::channel::<ResponseData>(10);
 
-//rest-杠杆测试
-#[tokio::test]
-async fn rest_leverage_test() {
-    global::log_utils::init_log_with_trace();
 
-    // //查询杠杆
-    let mut rest = get_rest();
-    // let rep_data = rest.get_leverage("ADAUSDTM".to_string()).await;
-    // trace!("查询杠杆{:?}",rep_data);
+    let mut ws = get_ws(Option::from(btree_map), KucoinSwapWsType::Private).await;
+    ws.set_symbols(vec!["xbt_usdtM".to_string()]);
+    ws.set_subscribe(vec![
+        // KucoinSwapSubscribeType::PuContractMarketLevel2Depth50,
+        // KucoinSwapSubscribeType::PuContractMarketExecution,
+        KucoinSwapSubscribeType::PuContractMarkettickerV2,
+        KucoinSwapSubscribeType::PrContractAccountWallet,
+        KucoinSwapSubscribeType::PrContractPosition,
+        KucoinSwapSubscribeType::PrContractMarketTradeOrdersSys,
+        KucoinSwapSubscribeType::PrContractMarketTradeOrders,
+    ]);
 
-    //设置杠杆
-    let rep_data2 = rest.set_leverage("BLZUSDTM".to_string(), 1).await;
-    trace!("设置杠杆{:?}",rep_data2);
 
-    // //查询杠杆
-    // let rep_data3 = rest.get_leverage("BLZUSDTM".to_string()).await;
-    // trace!("查询杠杆{:?}",rep_data3);
-}
+    let write_tx_am = Arc::new(Mutex::new(write_tx));
+    let bool_v1 = Arc::new(AtomicBool::new(true));
 
-//rest-设置自动开启补仓
-#[tokio::test]
-async fn rest_auto_deposit_test() {
-    global::log_utils::init_log_with_trace();
+    //读取
+    let _bool_v1_clone = Arc::clone(&bool_v1);
+    let _tr = tokio::spawn(async move {
+        trace!("线程-数据读取-开启");
+        loop {
+            if let Some(data) = read_rx.next().await {
+                trace!("读取数据data:{:?}",data)
+            }
+        }
+    });
 
-    //设置是否自动补仓
-    let mut rest = get_rest();
-    let rep_data = rest.auto_deposit_status("BLZUSDTM".to_string(), false).await;
-    trace!("设置是否自动补仓{:?}",rep_data);
+    //写数据
+    let _bool_v2_clone = Arc::clone(&bool_v1);
+    let _write_tx_clone = Arc::clone(&write_tx_am);
+    // let tw = tokio::spawn(async move {
+    //     trace!("线程-数据写入-开始");
+    //     loop {
+    //         tokio::time::sleep(Duration::from_millis(20*1000)).await;
+    //         let close_frame = CloseFrame {
+    //             code: CloseCode::Normal,
+    //             reason: Cow::Borrowed("Bye bye"),
+    //         };
+    //         let close_message = Message::Close(Some(close_frame));
+    //         // AbstractWsMode::send_subscribe(write_tx_clone.clone(), Message::Text("32313221".to_string()));
+    //         AbstractWsMode::send_subscribe(write_tx_clone.clone(), close_message);
+    //         trace!("发送指令成功");
+    //     }
+    //     trace!("线程-数据写入-结束");
+    // });
+
+    // loop {
+    let t1 = tokio::spawn(async move {
+        //链接
+        let bool_v3_clone = Arc::clone(&bool_v1);
+        ws.ws_connect_async(bool_v3_clone, &write_tx_am, write_rx, read_tx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
+        trace!("test 唯一线程结束--");
+    });
+    tokio::try_join!(t1).unwrap();
+    trace!("当此结束");
+    // }
+    trace!("重启!");
+    trace!("参考交易所关闭");
+    return;
 }
 
 
-async fn get_ws(btree_map: BTreeMap<String, String>, type_v: KucoinWsType, tx: Sender<ResponseData>) -> KucoinSwapWs {
-    let mut ku_ws = KucoinSwapWs::new(false, btree_map.clone(),
-                                      type_v, tx).await;
+async fn get_ws(btree_map: Option<KucoinSwapLogin>, type_v: KucoinSwapWsType) -> KucoinSwapWs {
+    let ku_ws = KucoinSwapWs::new(false, btree_map,
+                                  type_v).await;
     ku_ws
 }
-
-fn get_rest() -> KucoinSwapRest {
-    let mut btree_map: BTreeMap<String, String> = BTreeMap::new();
-    // btree_map.insert("access_key".to_string(), ACCESS_KEY.to_string());
-    // btree_map.insert("secret_key".to_string(), SECRET_KEY.to_string());
-    btree_map.insert("access_key".to_string(), ACCESS_KEY.to_string());
-    btree_map.insert("secret_key".to_string(), SECRET_KEY.to_string());
-    btree_map.insert("pass_key".to_string(), PASS_KEY.to_string());
-
-    let mut ku_exc = KucoinSwapRest::new(false, btree_map);
-    ku_exc
-}

+ 0 - 168
exchanges/tests/kucoin_swap_test_async.rs

@@ -1,168 +0,0 @@
-use std::sync::Arc;
-use std::sync::atomic::AtomicBool;
-
-use futures_util::StreamExt;
-use tokio::sync::Mutex;
-use tracing::trace;
-
-use exchanges::kucoin_swap_ws_async::{KucoinSwapLogin, KucoinSwapSubscribeType, KucoinSwapWs, KucoinSwapWsType};
-
-const ACCESS_KEY: &str = "";
-const SECRET_KEY: &str = "";
-const PASS_KEY: &str = "";
-
-//ws-订阅公共频道信息
-#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
-async fn ws_custom_subscribe_pu() {
-    global::log_utils::init_log_with_trace();
-
-
-    let (write_tx, write_rx) = futures_channel::mpsc::unbounded();
-    let (read_tx, mut read_rx) = futures_channel::mpsc::unbounded();
-
-
-
-    let mut ws = get_ws(None, KucoinSwapWsType::Public).await;
-    ws.set_symbols(vec!["xbt_usdtM".to_string()]);
-    ws.set_subscribe(vec![
-        KucoinSwapSubscribeType::PuContractMarketLevel2Depth50,
-        KucoinSwapSubscribeType::PuContractMarketExecution,
-        KucoinSwapSubscribeType::PuContractMarkettickerV2,
-    ]);
-
-
-    let write_tx_am = Arc::new(Mutex::new(write_tx));
-    let bool_v1 = Arc::new(AtomicBool::new(true));
-
-    //读取
-    let _bool_v1_clone = Arc::clone(&bool_v1);
-    let _tr = tokio::spawn(async move {
-        trace!("线程-数据读取-开启");
-        loop {
-            if let Some(data) = read_rx.next().await {
-                trace!("读取数据data:{:?}",data)
-            }
-        }
-    });
-
-    //写数据
-    let _bool_v2_clone = Arc::clone(&bool_v1);
-    let _write_tx_clone = Arc::clone(&write_tx_am);
-    // let tw = tokio::spawn(async move {
-    //     trace!("线程-数据写入-开始");
-    //     loop {
-    //         tokio::time::sleep(Duration::from_millis(20*1000)).await;
-    //         let close_frame = CloseFrame {
-    //             code: CloseCode::Normal,
-    //             reason: Cow::Borrowed("Bye bye"),
-    //         };
-    //         let close_message = Message::Close(Some(close_frame));
-    //         // AbstractWsMode::send_subscribe(write_tx_clone.clone(), Message::Text("32313221".to_string()));
-    //         AbstractWsMode::send_subscribe(write_tx_clone.clone(), close_message);
-    //         trace!("发送指令成功");
-    //     }
-    //     trace!("线程-数据写入-结束");
-    // });
-
-    // loop {
-    let t1 = tokio::spawn(async move {
-        //链接
-        let bool_v3_clone = Arc::clone(&bool_v1);
-        ws.ws_connect_async(bool_v3_clone, &write_tx_am, write_rx, read_tx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
-        trace!("test 唯一线程结束--");
-    });
-    tokio::try_join!(t1).unwrap();
-    trace!("当此结束");
-    // }
-    trace!("重启!");
-    trace!("参考交易所关闭");
-    return;
-}
-
-//ws-订阅私有频道信息
-#[tokio::test(flavor = "multi_thread", worker_threads = 5)]
-async fn ws_custom_subscribe_pr() {
-    global::log_utils::init_log_with_trace();
-
-
-    //对象
-    let btree_map = KucoinSwapLogin {
-        access_key: ACCESS_KEY.to_string(),
-        secret_key: SECRET_KEY.to_string(),
-        pass_key: PASS_KEY.to_string(),
-    };
-
-    let (write_tx, write_rx) = futures_channel::mpsc::unbounded();
-    let (read_tx, mut read_rx) = futures_channel::mpsc::unbounded();
-
-    // let (write_tx, write_rx) = tokio::sync::broadcast::channel::<Message>(10);
-    // let (read_tx, mut read_rx) = tokio::sync::broadcast::channel::<ResponseData>(10);
-
-
-    let mut ws = get_ws(Option::from(btree_map), KucoinSwapWsType::Private).await;
-    ws.set_symbols(vec!["xbt_usdtM".to_string()]);
-    ws.set_subscribe(vec![
-        // KucoinSwapSubscribeType::PuContractMarketLevel2Depth50,
-        // KucoinSwapSubscribeType::PuContractMarketExecution,
-        KucoinSwapSubscribeType::PuContractMarkettickerV2,
-        KucoinSwapSubscribeType::PrContractAccountWallet,
-        KucoinSwapSubscribeType::PrContractPosition,
-        KucoinSwapSubscribeType::PrContractMarketTradeOrdersSys,
-        KucoinSwapSubscribeType::PrContractMarketTradeOrders,
-    ]);
-
-
-    let write_tx_am = Arc::new(Mutex::new(write_tx));
-    let bool_v1 = Arc::new(AtomicBool::new(true));
-
-    //读取
-    let _bool_v1_clone = Arc::clone(&bool_v1);
-    let _tr = tokio::spawn(async move {
-        trace!("线程-数据读取-开启");
-        loop {
-            if let Some(data) = read_rx.next().await {
-                trace!("读取数据data:{:?}",data)
-            }
-        }
-    });
-
-    //写数据
-    let _bool_v2_clone = Arc::clone(&bool_v1);
-    let _write_tx_clone = Arc::clone(&write_tx_am);
-    // let tw = tokio::spawn(async move {
-    //     trace!("线程-数据写入-开始");
-    //     loop {
-    //         tokio::time::sleep(Duration::from_millis(20*1000)).await;
-    //         let close_frame = CloseFrame {
-    //             code: CloseCode::Normal,
-    //             reason: Cow::Borrowed("Bye bye"),
-    //         };
-    //         let close_message = Message::Close(Some(close_frame));
-    //         // AbstractWsMode::send_subscribe(write_tx_clone.clone(), Message::Text("32313221".to_string()));
-    //         AbstractWsMode::send_subscribe(write_tx_clone.clone(), close_message);
-    //         trace!("发送指令成功");
-    //     }
-    //     trace!("线程-数据写入-结束");
-    // });
-
-    // loop {
-    let t1 = tokio::spawn(async move {
-        //链接
-        let bool_v3_clone = Arc::clone(&bool_v1);
-        ws.ws_connect_async(bool_v3_clone, &write_tx_am, write_rx, read_tx).await.expect("链接失败(内部一个心跳线程应该已经关闭了)");
-        trace!("test 唯一线程结束--");
-    });
-    tokio::try_join!(t1).unwrap();
-    trace!("当此结束");
-    // }
-    trace!("重启!");
-    trace!("参考交易所关闭");
-    return;
-}
-
-
-async fn get_ws(btree_map: Option<KucoinSwapLogin>, type_v: KucoinSwapWsType) -> KucoinSwapWs {
-    let ku_ws = KucoinSwapWs::new(false, btree_map,
-                                  type_v).await;
-    ku_ws
-}