Skip to content

Commit

Permalink
Merge pull request #9 from aloysius-pgast/develop
Browse files Browse the repository at this point in the history
Develop
  • Loading branch information
aloysius-pgast authored May 7, 2018
2 parents c00168a + 1faaeb5 commit 6f5e4e4
Show file tree
Hide file tree
Showing 8 changed files with 151 additions and 19 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
# Change Log

## [v1.1.2]
* Ensures connection to exchange is always closed when we don't have any subscription remaining
* New constructor option _watchdog.orders_ to automatically force re-subscriptions for orders periodically
* Fix method _unsubscribeFromOrders_ (subscription wasn't cancelled)

## [v1.1.1]
* Allows to force re-subscription to orders (Bittrex Beta API)
* New method to enable logging keepalive messages (node _DEBUG_ must be enabled)
Expand Down
42 changes: 37 additions & 5 deletions doc/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,11 @@

Constructor takes an object as argument with following available properties (all optional)

* _legacy_ : _boolean_, if _false_ will connect to Bittrex beta WSS endpoint (default = _true_)

* _useCloudScraper_ : _boolean_, if _false_ Cloud Scraper will not be used (default = _true_)

* _auth.key_ : _string_, Bittrex API key (only needed to subscribe to user orders) (not supported by _legacy_ endpoint)
* _auth.key_ : _string_, Bittrex API key (only needed to subscribe to user orders)

* _auth.secret_ : _string_, Bittrex API secret (only needed to subscribe to user orders) (not supported by _legacy_ endpoint)
* _auth.secret_ : _string_, Bittrex API secret (only needed to subscribe to user orders)

* _retryDelay_ : _integer_, delay in milliseconds before reconnecting upon disconnection or connection failure (default = _10000_)

Expand All @@ -30,8 +28,14 @@ Constructor takes an object as argument with following available properties (all

* _watchdog.markets.reconnect_ : _boolean_, if true a reconnection will occur upon detecting timeout (default = _true_)

* _watchdog.orders.enabled_ : _boolean_, if true library will re-subscribe for orders periodically (default = _true_)

* _watchdog.orders.period_ : _integer_, delay (in _seconds_) after which re-subscription should be performed (default = _1800_, 30min)

# Watchdog

## Tickers & Markets

When watchdog is enabled, it will only be activated if subscriptions exist. If client unsubscribe from all _markets_ or all _tickers_, it will be automatically disabled and re-enabled once new subscriptions exist

If a watchdog is enabled and _timeout_ is detected, _timeout_ event will be triggered. If _reconnect_ is _false_ for this watchdog, client will need to reconnect manually
Expand All @@ -40,6 +44,12 @@ Watchdog will check for timeout every _timeout / 10_. This means that will be de

Do not set timeout value *too low* : setting value to _5 min_ will ensure timeout will be detected between _5 min_ and _5 min 30 sec_, while checking for timeout _every 30 seconds_

## Orders

When _watchdog.orders.enabled_ is _true_, a new subscription for orders will be sent to Bittrex, N seconds (_watchdog.orders.period_) after the last subscription

NB: re-subscription only be triggered if a subscription for orders exist (ie: if _subscribeToOrders_ was called by client)

# Reconnection

Method _reconnect(immediate)_ should be called upon receiving _terminated_ event
Expand Down Expand Up @@ -206,9 +216,13 @@ When watchdog detected that Bittrex stopped sending data. If _watchdog_ was conf

* _lastTimestamp_ : unix timestamp (in ms) of last received data

NB: will only be sent for _tickers_ & _markets_

### watchdog

Will be emitted everytime watchdog checks if a timeout occurred
### Tickers & markets

For _tickers_ and _markets_ watchdogs, event will be emitted everytime watchdog checks if a timeout occurred.

```
{
Expand All @@ -224,6 +238,24 @@ Will be emitted everytime watchdog checks if a timeout occurred

* _lastTimestamp_ : unix timestamp (in ms) of last received data

#### Orders

For _orders_ watchdog, event will be emitted everytime, an _automatic_ re-subscription occurs

```
{
"connectionId":string,
"dataType":string,
"lastTimestamp":integer
}
```

* _connectionId_ : id of _SignalR_ connection

* _dataType_ : _orders_

* _lastTimestamp_ : unix timestamp (in ms) of last automatic re-subscription

## Tickers & markets events

### ticker
Expand Down
4 changes: 1 addition & 3 deletions examples/subscribe_to_markets.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@ let client = new SignalRClient({
}
},
// use cloud scraper to bypass Cloud Fare (default)
useCloudScraper:true,
// use legacy endpoint (default) (set to false to use beta endpoint)
legacy:true
useCloudScraper:true
});

//-- event handlers
Expand Down
11 changes: 8 additions & 3 deletions examples/subscribe_to_orders.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,15 @@ let client = new SignalRClient({
key:"abcdef",
secret: "123456"
},
watchdog:{
// automatically re-subscribe for orders every 30min (this is enabled by default)
orders:{
enabled:true,
period:1800
}
},
// use cloud scraper to bypass Cloud Fare (default)
useCloudScraper:true,
// subscribing to orders is not supported by legacy endpoint (we need to use the beta API)
legacy:false
useCloudScraper:true
});

//-- event handlers
Expand Down
4 changes: 1 addition & 3 deletions examples/subscribe_to_tickers.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ let client = new SignalRClient({
// websocket will be automatically reconnected if server does not respond to ping after 10s
pingTimeout:10000,
// use cloud scraper to bypass Cloud Fare (default)
useCloudScraper:true,
// use legacy endpoint (default) (set to false to use beta endpoint)
legacy:true
useCloudScraper:true
});

//-- event handlers
Expand Down
91 changes: 88 additions & 3 deletions lib/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,15 @@ constructor(options)
reconnect:true,
lastTimestamp:0,
timer:null
},
// used to re-subscribe periodically
orders:{
// defaults to 30 min
period:1800000,
// whether or not we should re-subscribe automatically
enabled:true,
lastTimestamp:0,
timer:null
}
};

Expand Down Expand Up @@ -188,6 +197,17 @@ constructor(options)
this._watchdog.markets.reconnect = false;
}
}
if (undefined !== options.watchdog.orders)
{
if (undefined !== options.watchdog.orders.period)
{
this._watchdog.orders.period = options.watchdog.orders.period * 1000;
}
if (undefined !== options.watchdog.orders.enabled && false === options.watchdog.orders.enabled)
{
this._watchdog.orders.enabled = false;
}
}
}
// retry count
if (undefined !== options.retryCount)
Expand Down Expand Up @@ -776,6 +796,11 @@ subscribeToOrders(resubscribe, connect)
{
return;
}
// cancel watchdog since a new one will be automatically started
if (resubscribe)
{
this._clearWatchdogTimer('orders');
}
let timestamp = Date.now() / 1000.0;
let changes = {
subscribe:[{entity:'orders'}]
Expand All @@ -800,7 +825,7 @@ unsubscribeFromOrders()
return false;
}
// ignore if we didn't subscribe previously
if (this._subscriptions.orders.subscribed)
if (!this._subscriptions.orders.subscribed)
{
return;
}
Expand Down Expand Up @@ -1004,6 +1029,57 @@ _initializeWatchdog()
this._startWatchdogTimer('markets');
}
}
// orders watchdog is enabled
if (this._watchdog.orders.enabled)
{
// no subscriptions => disable watchdog
if (!this._subscriptions.orders.subscribed)
{
if (debug.enabled)
{
debug("Watchdog for 'orders' will be disabled since we don't have a subscription");
}
this._clearWatchdogTimer('orders');
}
else
{
this._startWatchdogTimerForOrders();
}
}
}

/**
* Starts a timer for orders subscription
*
*/
_startWatchdogTimerForOrders()
{
// timer already exists
if (null !== this._watchdog.orders.timer)
{
return;
}
let self = this;
if (debug.enabled)
{
debug("Watchdog for 'orders' will be started since we have a subscription");
}
this._watchdog.orders.timer = setInterval(function(){
// if socket is not connected, do nothing
if (!self.isConnected.call(self))
{
return;
}
self._watchdog.orders.lastTimestamp = new Date().getTime();
if (debug.enabled)
{
debug("About to re-subscribe for 'orders'...");
}
// resubscribe & emit event
self._subscribeToOrders.call(self);
let evt = {connectionId:self._connectionId,dataType:'orders',lastTimestamp:self._watchdog.orders.lastTimestamp}
self.emit('watchdog', evt);
}, this._watchdog.orders.period);
}

/**
Expand Down Expand Up @@ -1042,7 +1118,7 @@ _startWatchdogTimer(type)
{
debug("Last '%s' data was received %dms ago", type, delta);
}
let evt = {connectionId:self._connectionId,dateType:type,lastTimestamp:self._watchdog[type].lastTimestamp}
let evt = {connectionId:self._connectionId,dataType:type,lastTimestamp:self._watchdog[type].lastTimestamp}
self.emit('watchdog', evt);
if (delta > self._watchdog[type].timeout)
{
Expand All @@ -1067,7 +1143,7 @@ _startWatchdogTimer(type)
/**
* Creates a new connection
*
* @param {integer} delay delay in ms before creating the connection (optional, default = no delay)
* @param {integer} delay delay in ms before connecting (optional, default = no delay)
*/
_createConnection(delay)
{
Expand Down Expand Up @@ -1920,6 +1996,15 @@ isConnected()
return this._connection.isConnected()
}

isConnecting()
{
if (null === this._connection)
{
return false;
}
return this._connection.isConnecting()
}

disconnect()
{
if (null === this._connection)
Expand Down
11 changes: 10 additions & 1 deletion lib/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ constructor(options)
this._connectionState = STATE_NEW;
this._connection = null,
this._ws = null;
this._lastMessageId = 0;
this._lastMessageId = 1;
this._callbacks = {};

// for debugging purpose
Expand Down Expand Up @@ -209,6 +209,14 @@ isConnected()
return STATE_CONNECTED == this._connectionState;
}

/**
* Indicates whether or not we're waiting for connection to be established
*/
isConnecting()
{
return STATE_CONNECTING == this._connectionState;
}

/**
* Indicates whether or not connection is new (ie: can be connected)
*/
Expand Down Expand Up @@ -913,6 +921,7 @@ callMethod(method, args, cb)
A:undefined === args ? [] : args,
I:this._lastMessageId++
}
console.log(data);
let payload = JSON.stringify(data);
this._ws.send(payload);
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "bittrex-signalr-client",
"version": "1.1.1",
"version": "1.1.2",
"description": "Node.js implementation of SignalR protocol tailored for Bittrex exchange",
"main": "lib/client.js",
"scripts": {},
Expand Down

0 comments on commit 6f5e4e4

Please sign in to comment.