Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
26 changes: 10 additions & 16 deletions src/kucoin/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -42,16 +41,12 @@ pub enum KucoinEnv {
#[derive(Debug, Clone)]
pub struct Kucoin {
credentials: Option<Credentials>,
environment: KucoinEnv,
pub prefix: String,
pub client: reqwest::Client,
}

impl Kucoin {
pub fn new(
environment: KucoinEnv,
credentials: Option<Credentials>,
) -> Result<Self, failure::Error> {
pub fn new(environment: KucoinEnv, credentials: Option<Credentials>) -> Result<Self, APIError> {
let client = reqwest::Client::builder()
// .use_rustls_tls()
.timeout(Duration::from_secs(60))
Expand All @@ -62,7 +57,6 @@ impl Kucoin {
};
Ok(Kucoin {
credentials,
environment,
prefix,
client,
})
Expand Down Expand Up @@ -158,7 +152,7 @@ impl Kucoin {
params: Option<&HashMap<String, String>>,
query: Option<String>,
method: Method,
) -> Result<HeaderMap, failure::Error> {
) -> Result<HeaderMap, APIError> {
let mut headers = HeaderMap::new();
let nonce = get_time().to_string();
let mut api_key: &str = "";
Expand Down Expand Up @@ -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"),
Expand Down
40 changes: 12 additions & 28 deletions src/kucoin/error.rs
Original file line number Diff line number Diff line change
@@ -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<reqwest::Error> for APIError {
fn from(err: reqwest::Error) -> Self {
APIError::HTTP(err)
}
}

impl From<serde_json::Error> for APIError {
fn from(err: serde_json::Error) -> Self {
APIError::Serde(err)
}
}

impl From<tokio_tungstenite::tungstenite::Error> for APIError {
fn from(err: tokio_tungstenite::tungstenite::Error) -> Self {
APIError::Websocket(err)
}
#[error("Tokio JoinError")]
JoinError(#[from] tokio::task::JoinError),
}
16 changes: 7 additions & 9 deletions src/kucoin/websocket.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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<TcpStream, tokio_native_tls::TlsStream<TcpStream>>,
>;
type WSStream = WebSocketStream<MaybeTlsStream<TcpStream>>;
pub type StoredStream = SplitStream<WSStream>;

#[pin_project]
Expand Down Expand Up @@ -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),
};
};
}
Expand Down Expand Up @@ -264,13 +261,14 @@ fn parse_message(msg: Message) -> Result<KucoinWebsocketMsg, APIError> {
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(())
}
Expand Down
14 changes: 6 additions & 8 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<dyn Error>> {
//! let api = Kucoin::new(KucoinEnv::Sandbox, None)?;
//! let result = api.get_ticker("BTC-USDT").await?;
//! match result.data {
Expand All @@ -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<dyn Error>> {
//! let result = api.get_server_time().await;
//! match result {
//! Err(e) => {
Expand Down Expand Up @@ -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<dyn Error>> {
//! // If credentials are needed, generate a new Credentials struct w/ the necessary keys
//! let credentials = Credentials::new(
//! "xxxxxxxxxxxxxXXXXXXxxx",
Expand Down Expand Up @@ -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;