Skip to content

Commit 98eee5c

Browse files
JacobPlasterJacobPlaster
authored andcommitted
ws2: maintain string copy of the orderbook for checksums
1 parent 7d17b68 commit 98eee5c

1 file changed

Lines changed: 49 additions & 15 deletions

File tree

lib/transports/ws2.js

Lines changed: 49 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ const _pick = require('lodash/pick')
1414
const _isEqual = require('lodash/isEqual')
1515
const { genAuthSig, nonce } = require('bfx-api-node-util')
1616
const getMessagePayload = require('../util/ws2')
17+
const LosslessJSON = require('lossless-json')
1718

1819
const {
1920
BalanceInfo,
@@ -104,6 +105,7 @@ class WSv2 extends EventEmitter {
104105
this._packetWDTimeout = null
105106
this._packetWDLastTS = 0
106107
this._orderBooks = {}
108+
this._losslessOrderBooks = {}
107109
this._candles = {}
108110

109111
/**
@@ -553,22 +555,22 @@ class WSv2 extends EventEmitter {
553555
}
554556

555557
/**
556-
* @param {string} msgJSON
558+
* @param {string} rawMsg
557559
* @param {string} flags
558560
* @private
559561
*/
560-
_onWSMessage (msgJSON, flags) {
561-
debug('recv msg: %s', msgJSON)
562+
_onWSMessage (rawMsg, flags) {
563+
debug('recv msg: %s', rawMsg)
562564

563565
this._packetWDLastTS = Date.now()
564566
this._resetPacketWD()
565567

566568
let msg
567569

568570
try {
569-
msg = JSON.parse(msgJSON)
571+
msg = JSON.parse(rawMsg)
570572
} catch (e) {
571-
this.emit('error', `invalid message JSON: ${msgJSON}`)
573+
this.emit('error', `invalid message JSON: ${rawMsg}`)
572574
return
573575
}
574576

@@ -585,19 +587,20 @@ class WSv2 extends EventEmitter {
585587
this.emit('message', msg, flags)
586588

587589
if (Array.isArray(msg)) {
588-
this._handleChannelMessage(msg)
590+
this._handleChannelMessage(msg, rawMsg)
589591
} else if (msg.event) {
590-
this._handleEventMessage(msg)
592+
this._handleEventMessage(msg, rawMsg)
591593
} else {
592594
debug('recv unidentified message: %j', msg)
593595
}
594596
}
595597

596598
/**
597599
* @param {array} msg
600+
* @param {string} rawMsg
598601
* @private
599602
*/
600-
_handleChannelMessage (msg) {
603+
_handleChannelMessage (msg, rawMsg) {
601604
const [chanId, type] = msg
602605
const channelData = this._channelMap[chanId]
603606

@@ -614,7 +617,7 @@ class WSv2 extends EventEmitter {
614617
return this._handleOBChecksumMessage(msg, channelData)
615618
}
616619

617-
return this._handleOBMessage(msg, channelData)
620+
return this._handleOBMessage(msg, channelData, rawMsg)
618621
} else if (channelData.channel === 'trades') {
619622
return this._handleTradeMessage(msg, channelData)
620623
} else if (channelData.channel === 'ticker') {
@@ -669,15 +672,17 @@ class WSv2 extends EventEmitter {
669672
*
670673
* @param {Array|Array[]} msg
671674
* @param {Object} chanData - entry from _channelMap
675+
* @param {string} rawMsg
672676
* @private
673677
*/
674-
_handleOBMessage (msg, chanData) {
678+
_handleOBMessage (msg, chanData, rawMsg) {
679+
675680
const { symbol, prec } = chanData
676681
const raw = prec === 'R0'
677682
let data = getMessagePayload(msg)
678683

679684
if (this._manageOrderBooks) {
680-
const err = this._updateManagedOB(symbol, data, raw)
685+
const err = this._updateManagedOB(symbol, data, raw, rawMsg)
681686

682687
if (err) {
683688
this.emit('error', err)
@@ -710,11 +715,24 @@ class WSv2 extends EventEmitter {
710715
* @return {Error} err - null on success
711716
* @private
712717
*/
713-
_updateManagedOB (symbol, data, raw) {
718+
_updateManagedOB (symbol, data, raw, rawMsg) {
719+
// parse raw string with lossless parse which takes
720+
// the exact strict values rather than converting to floats
721+
// [0.00001, [1, 2, 3]] -> ['0.00001', ['1', '2', '3']]
722+
const rawLossless = LosslessJSON.parse(rawMsg, (key, value) => {
723+
if (value && value.isLosslessNumber) {
724+
return value.toString()
725+
}
726+
else {
727+
return value;
728+
}
729+
})
730+
const losslessUpdate = rawLossless[1]
714731
// Snapshot, new OB. Note that we don't protect against duplicates, as they
715732
// could come in on re-sub
716733
if (Array.isArray(data[0])) {
717734
this._orderBooks[symbol] = data
735+
this._losslessOrderBooks[symbol] = losslessUpdate
718736
return null
719737
}
720738

@@ -724,7 +742,7 @@ class WSv2 extends EventEmitter {
724742
}
725743

726744
OrderBook.updateArrayOBWith(this._orderBooks[symbol], data, raw)
727-
745+
OrderBook.updateArrayOBWith(this._losslessOrderBooks[symbol], losslessUpdate, raw)
728746
return null
729747
}
730748

@@ -735,7 +753,7 @@ class WSv2 extends EventEmitter {
735753
* @return {Error} err - null if none
736754
*/
737755
_verifyManagedOBChecksum (symbol, prec, cs) {
738-
const ob = this._orderBooks[symbol]
756+
const ob = this._losslessOrderBooks[symbol]
739757

740758
if (!ob) return null
741759

@@ -762,6 +780,21 @@ class WSv2 extends EventEmitter {
762780
return new OrderBook(this._orderBooks[symbol])
763781
}
764782

783+
/**
784+
* Returns an up-to-date lossless copy of the order book for the specified symbol, or
785+
* null if no OB is managed for that symbol. All amounts and prices are in original
786+
* string format.
787+
* Set `manageOrderBooks: true` in the constructor to use.
788+
*
789+
* @param {string} symbol
790+
* @return {OrderBook} ob - null if not found
791+
*/
792+
getLosslessOB (symbol) {
793+
if (!this._losslessOrderBooks[symbol]) return null
794+
795+
return new OrderBook(this._losslessOrderBooks[symbol])
796+
}
797+
765798
/**
766799
* @param {Array} msg
767800
* @param {Object} chanData
@@ -1045,9 +1078,10 @@ class WSv2 extends EventEmitter {
10451078

10461079
/**
10471080
* @param {Object} msg
1081+
* @param {string} rawMsg
10481082
* @private
10491083
*/
1050-
_handleEventMessage (msg) {
1084+
_handleEventMessage (msg, rawMsg) {
10511085
if (msg.event === 'auth') {
10521086
return this._handleAuthEvent(msg)
10531087
} else if (msg.event === 'subscribed') {

0 commit comments

Comments
 (0)