|
|
@@ -1,8 +1,10 @@
|
|
|
use std::collections::{BTreeMap, HashMap};
|
|
|
-use std::{env, io};
|
|
|
+use std::{env, io, thread};
|
|
|
use std::io::{Stdout, Write};
|
|
|
use std::net::{IpAddr, Ipv4Addr, SocketAddr};
|
|
|
use std::str::FromStr;
|
|
|
+use std::time::Duration;
|
|
|
+use chrono::Utc;
|
|
|
use reqwest;
|
|
|
use reqwest::header::{HeaderMap, HeaderValue, USER_AGENT};
|
|
|
use hex;
|
|
|
@@ -11,10 +13,10 @@ use ring::hmac;
|
|
|
use serde_json::{json, Value};
|
|
|
use serde_json::map::Values;
|
|
|
use tungstenite::client::{AutoStream, connect_with_proxy, ProxyAutoStream};
|
|
|
-use tungstenite::{Message, WebSocket};
|
|
|
+use tungstenite::{connect, Message, WebSocket};
|
|
|
use tungstenite::protocol::WebSocketConfig;
|
|
|
use url::Url;
|
|
|
-
|
|
|
+use tungstenite::stream::Stream;
|
|
|
// use std::io::{self, Write,io};
|
|
|
|
|
|
|
|
|
@@ -112,13 +114,13 @@ mod tests {
|
|
|
|
|
|
pub struct BinanceExc {
|
|
|
base_url: String,
|
|
|
- access_keu: String,
|
|
|
+ access_key: String,
|
|
|
secret_key: String,
|
|
|
}
|
|
|
|
|
|
impl BinanceExc {
|
|
|
- pub fn new(access_keu: String, secret_key: String) -> BinanceExc {
|
|
|
- BinanceExc { base_url: "https://api.binance.com".to_string(), access_keu, secret_key }
|
|
|
+ pub fn new(access_key: String, secret_key: String) -> BinanceExc {
|
|
|
+ BinanceExc { base_url: "https://api.binance.com".to_string(), access_key, secret_key }
|
|
|
}
|
|
|
|
|
|
//币安-深度信息
|
|
|
@@ -204,7 +206,7 @@ impl OkxExc {
|
|
|
|
|
|
match result {
|
|
|
Ok(req_data) => {
|
|
|
- if (req_data.code != "0") {
|
|
|
+ if req_data.code != "0" {
|
|
|
req_data
|
|
|
} else {
|
|
|
let body: String = req_data.data;
|
|
|
@@ -239,7 +241,7 @@ impl OkxExc {
|
|
|
|
|
|
match result {
|
|
|
Ok(req_data) => {
|
|
|
- if (req_data.code != "0") {
|
|
|
+ if req_data.code != "0" {
|
|
|
req_data
|
|
|
} else {
|
|
|
let body: String = req_data.data;
|
|
|
@@ -278,7 +280,7 @@ impl OkxExc {
|
|
|
|
|
|
match result {
|
|
|
Ok(req_data) => {
|
|
|
- if (req_data.code != "0") {
|
|
|
+ if req_data.code != "0" {
|
|
|
req_data
|
|
|
} else {
|
|
|
let body: String = req_data.data;
|
|
|
@@ -311,7 +313,7 @@ impl OkxExc {
|
|
|
).await;
|
|
|
match result {
|
|
|
Ok(req_data) => {
|
|
|
- if (req_data.code != "0") {
|
|
|
+ if req_data.code != "0" {
|
|
|
req_data
|
|
|
} else {
|
|
|
let body: String = req_data.data;
|
|
|
@@ -539,27 +541,43 @@ impl ReqData {
|
|
|
}
|
|
|
|
|
|
|
|
|
+type HookFn = fn(String);
|
|
|
+
|
|
|
+
|
|
|
pub struct SocketTool {
|
|
|
+ //连接地址
|
|
|
request_url: String,
|
|
|
+ //ip
|
|
|
ip: String,
|
|
|
+ //ip
|
|
|
port: u16,
|
|
|
+ //是否需要登陆
|
|
|
is_login: bool,
|
|
|
+ //登陆所需参数
|
|
|
+ login_param: BTreeMap<String, String>,
|
|
|
+ //订阅参数
|
|
|
subscription: serde_json::Value,
|
|
|
+ //回调
|
|
|
+ hook_fn: HookFn,
|
|
|
}
|
|
|
|
|
|
impl SocketTool {
|
|
|
- pub fn new(request_url: &str, is_login: bool, subscription: serde_json::Value) -> SocketTool {
|
|
|
+ pub fn new(request_url: &str,
|
|
|
+ is_login: bool,
|
|
|
+ login_param: BTreeMap<String, String>,
|
|
|
+ subscription: serde_json::Value,
|
|
|
+ hookfn: HookFn,
|
|
|
+ ) -> SocketTool {
|
|
|
let mut ip_v = "";
|
|
|
let mut port_v = 8080;
|
|
|
let mut v_str = String::from("");
|
|
|
|
|
|
- //拿到本机环境变量,
|
|
|
+ /*******读取环境变量-判定初始化代理地址*******/
|
|
|
let env_var_name = "http_proxy";
|
|
|
// 使用std::env::var函数获取环境变量的值,如果返回Err,则说明环境变量不存在
|
|
|
-
|
|
|
match env::var(env_var_name) {
|
|
|
Ok(value) => {
|
|
|
- println!("Environment variable {} exists with value: {}", env_var_name, value);
|
|
|
+ // println!("Environment variable {} exists with value: {}", env_var_name, value);
|
|
|
v_str = value.clone();
|
|
|
if v_str.len() > 0 {
|
|
|
let parts: Vec<&str> = v_str.split("//").collect();
|
|
|
@@ -567,63 +585,130 @@ impl SocketTool {
|
|
|
ip_v = ip_port[0];
|
|
|
port_v = ip_port[1].parse().unwrap();
|
|
|
}
|
|
|
- //http://127.0.0.1:7890
|
|
|
println!("代理设置成功{0},{1}", ip_v.to_string(), port_v.to_string());
|
|
|
}
|
|
|
Err(_) => {
|
|
|
- println!("Environment variable {} does not exist.", env_var_name);
|
|
|
+ println!("环境变量 {} 不存在,无法开启代理.", env_var_name);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /*****返回结构体*******/
|
|
|
SocketTool {
|
|
|
request_url: request_url.to_string(),
|
|
|
ip: ip_v.clone().to_string(),
|
|
|
port: port_v,
|
|
|
is_login: is_login,
|
|
|
+ login_param: login_param,
|
|
|
subscription: subscription,
|
|
|
+ hook_fn: hookfn,
|
|
|
}
|
|
|
}
|
|
|
pub fn run(&self) {
|
|
|
- //订阅内容
|
|
|
- let sub_json = self.subscription.clone();
|
|
|
-
|
|
|
+ /*****消息溜***/
|
|
|
let mut stdout = io::stdout();
|
|
|
let mut stderr = io::stderr();
|
|
|
+
|
|
|
+ /*****socket配置信息***/
|
|
|
let request_url = Url::parse(self.request_url.as_str()).unwrap();
|
|
|
+ let ip_array: Vec<&str> = self.ip.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.port);
|
|
|
+ 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;
|
|
|
+ /*****判断代理IP是否为空,空则不走代理*****/
|
|
|
if self.ip.len() > 0 {
|
|
|
println!("----socket-走代理");
|
|
|
- let ip_array: Vec<&str> = self.ip.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.port);
|
|
|
- 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 (mut socket, response) =
|
|
|
connect_with_proxy(request_url, proxy_address, websocket_config, max_redirects)
|
|
|
- .expect("Can't connect");
|
|
|
+ .expect("Can't connect(无法连接)");
|
|
|
+
|
|
|
+ /******登陆认证********/
|
|
|
+ if self.is_login {
|
|
|
+ println!("----需要登陆");
|
|
|
+ let lable = self.login_param.get("lable");
|
|
|
+
|
|
|
+ let login_json_str = self.log_in_to_str();
|
|
|
+ println!("---组装 登陆信息:{0}", login_json_str);
|
|
|
+ socket.write_message(Message::Text(login_json_str)).unwrap();
|
|
|
+ thread::sleep(Duration::from_secs(1));
|
|
|
+ } else {
|
|
|
+ println!("----no longin(不需要登陆)");
|
|
|
+ }
|
|
|
+
|
|
|
+ /******订阅信息********/
|
|
|
+ let sub_json = self.subscription.clone();
|
|
|
println!("--订阅内容:{:?}", sub_json);
|
|
|
let sub_json_str = sub_json.to_string();
|
|
|
writeln!(stdout, "subscribe info: {:?}", sub_json_str).unwrap();
|
|
|
-
|
|
|
- // 订阅深度信息
|
|
|
socket.write_message(Message::Text(sub_json_str))
|
|
|
.unwrap();
|
|
|
|
|
|
+ /******数据读取********/
|
|
|
+ let mut z_time = Utc::now().timestamp() ;
|
|
|
+ loop {
|
|
|
+ if !socket.can_read() {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ let msg = socket.read_message();
|
|
|
+
|
|
|
+ match msg {
|
|
|
+ Ok(Message::Text(text)) => {
|
|
|
+ writeln!(stdout, "{:?}", text).unwrap();
|
|
|
+ (self.hook_fn)("mamamimya".to_string());
|
|
|
+ }
|
|
|
+ Ok(Message::Ping(_)) | Ok(Message::Pong(_)) | Ok(Message::Close(_)) => {
|
|
|
+ socket.write_message(Message::text("pong"));
|
|
|
+ // writeln!(stdout, "ping----------pong").unwrap();
|
|
|
+ writeln!(stdout, "ping----------pong").unwrap();
|
|
|
+ }
|
|
|
+ Err(error) => {
|
|
|
+ writeln!(stderr, "Error receiving message: {}", error).unwrap();
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ _ => {}
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ socket.close(None).unwrap();
|
|
|
+ } else {
|
|
|
+ // 提示,并未找到好的优化方式,
|
|
|
+ println!("----socket-没代理");
|
|
|
+ let (mut socket, response) =
|
|
|
+ connect(request_url)
|
|
|
+ .expect("Can't connect(无法连接)");
|
|
|
+
|
|
|
+ /******登陆认证********/
|
|
|
if self.is_login {
|
|
|
- println!("----需要登陆")
|
|
|
+ println!("----需要登陆");
|
|
|
+ let lable = self.login_param.get("lable");
|
|
|
+
|
|
|
+ let login_json_str = self.log_in_to_str();
|
|
|
+ println!("---组装 登陆信息:{0}", login_json_str);
|
|
|
+ socket.write_message(Message::Text(login_json_str)).unwrap();
|
|
|
+ thread::sleep(Duration::from_secs(1));
|
|
|
} else {
|
|
|
- println!("----不需要登陆")
|
|
|
+ println!("----no longin(不需要登陆)");
|
|
|
}
|
|
|
|
|
|
+ /******订阅信息********/
|
|
|
+ let sub_json = self.subscription.clone();
|
|
|
+ println!("--订阅内容:{:?}", sub_json);
|
|
|
+ let sub_json_str = sub_json.to_string();
|
|
|
+ writeln!(stdout, "subscribe info: {:?}", sub_json_str).unwrap();
|
|
|
+ socket.write_message(Message::Text(sub_json_str))
|
|
|
+ .unwrap();
|
|
|
+
|
|
|
+ /******数据读取********/
|
|
|
loop {
|
|
|
if !socket.can_read() {
|
|
|
continue;
|
|
|
@@ -634,6 +719,7 @@ impl SocketTool {
|
|
|
match msg {
|
|
|
Ok(Message::Text(text)) => {
|
|
|
writeln!(stdout, "{:?}", text).unwrap();
|
|
|
+ (self.hook_fn)("mamamimya".to_string());
|
|
|
}
|
|
|
Ok(Message::Ping(_)) | Ok(Message::Pong(_)) | Ok(Message::Close(_)) => {
|
|
|
socket.write_message(Message::Pong(vec![]))
|
|
|
@@ -649,10 +735,59 @@ impl SocketTool {
|
|
|
}
|
|
|
|
|
|
socket.close(None).unwrap();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ fn log_in_to_str(&self) -> String {
|
|
|
+ let mut login_json_str = String::from("");
|
|
|
+
|
|
|
+ //解析并且组装 认证信息
|
|
|
+ let lable = self.login_param.get("lable");
|
|
|
+ if let Some(ref_string) = lable {
|
|
|
+ if *ref_string == "binance" {
|
|
|
+ println!("----币安 暂不做登陆");
|
|
|
+ } else if *ref_string == "okx" {
|
|
|
+ let mut access_key: String = "".to_string();
|
|
|
+ let mut secret_key: String = "".to_string();
|
|
|
+ let mut passphrase: String = "".to_string();
|
|
|
+
|
|
|
+ for (key, value) in &self.login_param {
|
|
|
+ println!("Key: {}, Value: {}", key, value);
|
|
|
+ if key == "access_key" {
|
|
|
+ access_key = value.parse().unwrap();
|
|
|
+ } else if key == "secret_key" {
|
|
|
+ secret_key = value.parse().unwrap();
|
|
|
+ } else if key == "passphrase" {
|
|
|
+ passphrase = value.parse().unwrap();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ let timestamp = Utc::now().timestamp().to_string();
|
|
|
+
|
|
|
+ // 时间戳 + 请求类型+ 请求参数字符串
|
|
|
+ let message = format!("{}GET{}", timestamp, "/users/self/verify");
|
|
|
+ println!("---message:{:?}", message);
|
|
|
+ let hmac_key = ring::hmac::Key::new(hmac::HMAC_SHA256, secret_key.as_bytes());
|
|
|
+ let result = ring::hmac::sign(&hmac_key, &message.as_bytes());
|
|
|
+ let mut sign = base64::encode(result);
|
|
|
+
|
|
|
+ let login_json = json!({
|
|
|
+ "op": "login",
|
|
|
+ "args": [{
|
|
|
+ "apiKey": access_key,
|
|
|
+ "passphrase": passphrase,
|
|
|
+ "timestamp": timestamp,
|
|
|
+ "sign": sign }]
|
|
|
+ });
|
|
|
+
|
|
|
+ // println!("---login_json:{0}", login_json.to_string());
|
|
|
+ println!("--登陆:{:?}", login_json);
|
|
|
+ login_json_str = login_json.to_string();
|
|
|
+ }
|
|
|
} else {
|
|
|
- // 其他情况下的赋值
|
|
|
- println!("----socket-没代理");
|
|
|
+ println!("Option is None(lable 为None)");
|
|
|
}
|
|
|
+
|
|
|
+
|
|
|
+ login_json_str
|
|
|
}
|
|
|
}
|
|
|
|