diff --git a/Cargo.toml b/Cargo.toml index 1e1f89f..5d46a86 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,19 +14,19 @@ version = "0.4.4" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -base64 = "0.12.0" -failure = "0.1.7" +base64 = "0.13" futures = "0.3.9" -hmac = "0.7.1" +hmac = "0.12" pin-project = "1.0.5" serde = "1.0.104" serde_derive = "1.0.104" serde_json = "1.0.48" -sha2 = "0.8.1" +sha2 = "0.10" streamunordered = "0.5" reqwest = { version = "0.11.1", features = ["json", "rustls-tls"] } -tokio = { version = "1.0.1", features = ["full"]} +thiserror = "1.0" +tokio = { version = "1.0.1", features = ["full"] } tokio-native-tls = "0.3.0" -tokio-tungstenite = { version = "0.13.0", features = ["tls"] } -tungstenite = "0.13.0" +tokio-tungstenite = { version = "0.17", features = ["native-tls"] } +tungstenite = "0.17" url = "2.1.1" diff --git a/src/kucoin/client.rs b/src/kucoin/client.rs index b794470..1740a5f 100644 --- a/src/kucoin/client.rs +++ b/src/kucoin/client.rs @@ -3,7 +3,6 @@ use std::collections::HashMap; use std::time::Duration; use base64::encode; -use failure; use hmac::{Hmac, Mac}; use reqwest::header::{HeaderMap, HeaderName, HeaderValue}; use serde_json::json; @@ -42,16 +41,12 @@ pub enum KucoinEnv { #[derive(Debug, Clone)] pub struct Kucoin { credentials: Option, - environment: KucoinEnv, pub prefix: String, pub client: reqwest::Client, } impl Kucoin { - pub fn new( - environment: KucoinEnv, - credentials: Option, - ) -> Result { + pub fn new(environment: KucoinEnv, credentials: Option) -> Result { let client = reqwest::Client::builder() // .use_rustls_tls() .timeout(Duration::from_secs(60)) @@ -62,7 +57,6 @@ impl Kucoin { }; Ok(Kucoin { credentials, - environment, prefix, client, }) @@ -158,7 +152,7 @@ impl Kucoin { params: Option<&HashMap>, query: Option, method: Method, - ) -> Result { + ) -> Result { let mut headers = HeaderMap::new(); let nonce = get_time().to_string(); let mut api_key: &str = ""; @@ -203,15 +197,15 @@ impl Kucoin { } } } - let mut hmac_sign = HmacSha256::new_varkey(secret_key.as_bytes()).expect("HMAC can take key of any size"); - hmac_sign.input(str_to_sign.as_bytes()); - let sign_result = hmac_sign.result(); - let sign_bytes = sign_result.code(); + let mut hmac_sign = HmacSha256::new_from_slice(secret_key.as_bytes()) + .expect("HMAC can take key of any size"); + hmac_sign.update(str_to_sign.as_bytes()); + let sign_bytes = hmac_sign.finalize().into_bytes(); let sign_digest = encode(&sign_bytes); - let mut hmac_passphrase = HmacSha256::new_varkey(secret_key.as_bytes()).expect("HMAC can take key of any size"); - hmac_passphrase.input(passphrase.as_bytes()); - let passphrase_result = hmac_passphrase.result(); - let passphrase_bytes = passphrase_result.code(); + let mut hmac_passphrase = HmacSha256::new_from_slice(secret_key.as_bytes()) + .expect("HMAC can take key of any size"); + hmac_passphrase.update(passphrase.as_bytes()); + let passphrase_bytes = hmac_passphrase.finalize().into_bytes(); let passphrase_digest = encode(&passphrase_bytes); headers.insert( HeaderName::from_static("kc-api-key"), diff --git a/src/kucoin/error.rs b/src/kucoin/error.rs index ed4958e..4db9cfe 100644 --- a/src/kucoin/error.rs +++ b/src/kucoin/error.rs @@ -1,31 +1,15 @@ -#[derive(Fail, Debug)] +use thiserror::Error; + +#[derive(Error, Debug)] pub enum APIError { - #[fail(display = "Serde issue parsing error {}", _0)] - Serde(#[fail(cause)] serde_json::Error), - #[fail(display = "Websocket error {}", _0)] - Websocket(#[fail(cause)] tokio_tungstenite::tungstenite::Error), - #[fail(display = "REST Call error {}", _0)] - HTTP(#[fail(cause)] reqwest::Error), - #[fail(display = "Other issue {}", _0)] + #[error("Serde issue parsing error {}", _0)] + Serde(#[from] serde_json::Error), + #[error("Websocket error {}", _0)] + Websocket(#[from] tokio_tungstenite::tungstenite::Error), + #[error("REST Call error {}", _0)] + HTTP(#[from] reqwest::Error), + #[error("Other issue {}", _0)] Other(String), -} - -impl APIError {} - -impl From for APIError { - fn from(err: reqwest::Error) -> Self { - APIError::HTTP(err) - } -} - -impl From for APIError { - fn from(err: serde_json::Error) -> Self { - APIError::Serde(err) - } -} - -impl From for APIError { - fn from(err: tokio_tungstenite::tungstenite::Error) -> Self { - APIError::Websocket(err) - } + #[error("Tokio JoinError")] + JoinError(#[from] tokio::task::JoinError), } diff --git a/src/kucoin/websocket.rs b/src/kucoin/websocket.rs index 68c1d13..f65bafe 100644 --- a/src/kucoin/websocket.rs +++ b/src/kucoin/websocket.rs @@ -8,10 +8,9 @@ use streamunordered::{StreamUnordered, StreamYield}; use tokio::net::TcpStream; use tokio::sync::Mutex; use tokio::time; -use tokio_tungstenite::{connect_async, tungstenite::Message, WebSocketStream}; +use tokio_tungstenite::{connect_async, tungstenite::Message, MaybeTlsStream, WebSocketStream}; use url::Url; -use failure; use serde_json; use std::{ pin::Pin, @@ -26,9 +25,7 @@ use super::model::websocket::{ use super::model::{APIDatum, Method}; use super::utils::get_time; -type WSStream = WebSocketStream< - tokio_tungstenite::stream::Stream>, ->; +type WSStream = WebSocketStream>; pub type StoredStream = SplitStream; #[pin_project] @@ -98,10 +95,10 @@ impl KucoinWebsocket { if let Err(e) = resp { match e { APIError::Websocket(e) => { - format_err!("Error sending Ping: {}", e); + println!("Error sending Ping: {}", e); break; } - _ => format_err!("None websocket error sending Ping: {}", e), + _ => println!("None websocket error sending Ping: {}", e), }; }; } @@ -264,13 +261,14 @@ fn parse_message(msg: Message) -> Result { Message::Binary(b) => Ok(KucoinWebsocketMsg::Binary(b)), Message::Pong(..) => Ok(KucoinWebsocketMsg::Pong), Message::Ping(..) => Ok(KucoinWebsocketMsg::Ping), - Message::Close(..) => Err(APIError::Other("Socket closed error".to_string())), + Message::Close(..) => Err(APIError::Other("Socket closed error".into())), + Message::Frame(..) => Err(APIError::Other("Frame message not handled".into())), } } pub async fn close_socket( heartbeat: &mut tokio::task::JoinHandle<()>, -) -> Result<(), failure::Error> { +) -> Result<(), APIError> { heartbeat.await?; Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index b28d2a1..5bbe70d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -77,12 +77,12 @@ //! ```ignore //! extern crate kucoin_rs; //! +//! use std::error::Error; //! use kucoin_rs::tokio; -//! use kucoin_rs::failure; //! use kucoin_rs::kucoin::client::{Kucoin, Credentials, KucoinEnv}; //! //! #[tokio::main] -//! async fn main() -> Result<(), failure::Error> { +//! async fn main() -> Result<(), Box> { //! let api = Kucoin::new(KucoinEnv::Sandbox, None)?; //! let result = api.get_ticker("BTC-USDT").await?; //! match result.data { @@ -99,12 +99,12 @@ //! extern crate kucoin_rs; //! //! use kucoin_rs::tokio; -//! use kucoin_rs::failure; +//! use std::error::Error; //! use kucoin_rs::kucoin::client::{Kucoin, Credentials, KucoinEnv}; //! use kucoin_rs::kucoin::error::APIError; //! //! #[tokio::main] -//! async fn main() -> Result<(), failure::Error> { +//! async fn main() -> Result<(), Box> { //! let result = api.get_server_time().await; //! match result { //! Err(e) => { @@ -136,14 +136,14 @@ //! extern crate kucoin_rs; //! //! use kucoin_rs::tokio; -//! use kucoin_rs::failure; +//! use std::error::Error; //! use kucoin_rs::tokio::stream::StreamExt; //! //! use kucoin_rs::kucoin::client::{Kucoin, Credentials, KucoinEnv}; //! use kucoin_rs::kucoin::model::websocket::{Subscribe, KucoinWebsocketMsg, WSType, WSTopic, WSResp}; //! //! #[tokio::main] -//! async fn main() -> Result<(), failure::Error> { +//! async fn main() -> Result<(), Box> { //! // If credentials are needed, generate a new Credentials struct w/ the necessary keys //! let credentials = Credentials::new( //! "xxxxxxxxxxxxxXXXXXXxxx", @@ -239,8 +239,6 @@ pub extern crate serde_json; #[macro_use] pub extern crate serde_derive; -#[macro_use] -pub extern crate failure; /// Kucoin API Module pub mod kucoin;