crowdtoken-demo-wallet
Version:
ERC20 Token wallet utilize SafeMath, DAOs & Web3
259 lines (224 loc) • 6.62 kB
JavaScript
'use strict'
const { EventEmitter } = require('events')
const debug = require('debug')('bitfinex:ws')
const crypto = require('crypto')
const WebSocket = require('ws')
const { isSnapshot } = require('./lib/helper.js')
const normalizeOrderBook = require('./lib/normalizeOrderbooks.js')
function passThrough (d) { return d }
/**
* Handles communitaction with Bitfinex WebSocket API.
* @param {string} APIKey
* @param {string} APISecret
* @param {object} Options
* @event
* @class
*/
class BitfinexWS2 extends EventEmitter {
constructor (apiKey, apiSecret, opts = {}) {
super()
this.apiKey = apiKey
this.apiSecret = apiSecret
this.websocketURI = opts.websocketURI || 'wss://api.bitfinex.com/ws/2'
this.transformer = opts.transformer || passThrough
}
open () {
this.ws = new WebSocket(this.websocketURI)
this.ws.on('message', this.onMessage.bind(this))
this.ws.on('open', this.onOpen.bind(this))
this.ws.on('error', this.onError.bind(this))
this.ws.on('close', this.onClose.bind(this))
}
onMessage (msg, flags) {
msg = JSON.parse(msg)
debug('Received message: %j', msg)
debug('Emited message event')
this.emit('message', msg, flags)
if (!Array.isArray(msg) && msg.event) {
if (msg.event === 'subscribed') {
debug('Subscription report received')
// Inform the user the new event name that will be triggered
const data = {
channel: msg.channel,
chanId: msg.chanId,
symbol: msg.symbol
}
// https://github.com/bitfinexcom/bitfinex-api-node/issues/37
if (msg.prec) {
data.prec = msg.prec
}
// Save to event map
this.channelMap[msg.chanId] = data
debug('Emitting \'subscribed\' %j', data)
/**
* @event BitfinexWS#subscribed
* @type {object}
* @property {string} channel - Channel type
* @property {string} symbol - Symbol of the asset in question (either a trading pair or a funding currency)
* @property {number} chanId - Channel ID sended by Bitfinex
*/
this.emit('subscribed', data)
} else if (msg.event === 'auth' && msg.status !== 'OK') {
this.emit('error', msg)
debug('Emitting \'error\' %j', msg)
} else if (msg.event === 'auth') {
this.channelMap[msg.chanId] = {
channel: 'auth'
}
debug('Emitting \'%s\' %j', msg.event, msg)
/**
* @event BitfinexWS#auth
*/
this.emit(msg.event, msg)
} else {
debug('Emitting \'%s\' %j', msg.event, msg)
this.emit(msg.event, msg)
}
} else {
this.handleChannel(msg)
}
}
handleChannel (msg) {
debug('Received data from a channel')
// First element of Array is the channelId, the rest is the info.
const channelId = msg.shift() // Pop the first element
const event = this.channelMap[channelId]
if (!event) return
debug('Message in \'%s\' channel', event.channel)
if (event.channel === 'book') {
this._processBookEvent(msg, event)
} else if (event.channel === 'trades') {
this._processTradeEvent(msg, event)
} else if (event.channel === 'ticker') {
this._processTickerEvent(msg, event)
} else if (event.channel === 'auth') {
this._processUserEvent(msg)
} else {
debug('Message in unknown channel')
}
}
_processUserEvent (msg) {
if (msg[0] === 'hb') { // HeatBeart
debug('Received HeatBeart in user channel')
return
}
let event = msg[0]
const data = msg[1]
if (event === 'n') { // Notification
event = data[1]
this.emit(event, data)
debug('Emitting \'%s\', %j', event, data)
} else if (data.length) { // Update
debug('Emitting \'%s\', %j', event, data)
this.emit(event, data)
}
}
_processTickerEvent (msg, event) {
if (msg[0] === 'hb') { // HeatBeart
debug('Received HeatBeart in %s ticker channel', event.symbol)
return
}
msg = msg[0]
const res = this.transformer(msg, 'ticker', event.symbol)
debug('Emitting ticker, %s, %j', event.symbol, res)
this.emit('ticker', event.symbol, res)
}
_processBookEvent (msg, event) {
if (msg[0] === 'hb') { // HeatBeart
debug('Received HeatBeart in %s book channel', event.symbol)
return
}
msg = msg[0]
msg = normalizeOrderBook(msg, event.prec)
const res = this.transformer(msg, 'orderbook', event.symbol)
debug('Emitting orderbook, %s, %j', event.symbol, res)
this.emit('orderbook', event.symbol, res)
}
_processTradeEvent (msg, event) {
if (msg[0] === 'hb') { // HeatBeart
debug('Received HeatBeart in %s trade channel', event.symbol)
return
}
if (isSnapshot(msg)) {
msg = msg[0]
}
const res = this.transformer(msg, 'trades', event.symbol)
debug('Emitting trade, %s, %j', event.symbol, res)
this.emit('trade', event.symbol, res)
}
close () {
this.ws.close()
}
onOpen () {
this.channelMap = {} // Map channels IDs to events
debug('Connection opening, emitting open')
this.emit('open')
}
onError (error) {
this.emit('error', error)
}
onClose () {
this.emit('close')
}
send (msg) {
debug('Sending %j', msg)
this.ws.send(JSON.stringify(msg))
}
subscribeOrderBook (symbol = 'tBTCUSD', precision = 'P0', length = '25') {
this.send({
event: 'subscribe',
channel: 'book',
symbol,
len: length,
prec: precision
})
}
subscribeTrades (symbol = 'BTCUSD') {
this.send({
event: 'subscribe',
channel: 'trades',
symbol
})
}
subscribeTicker (symbol = 'tBTCUSD') {
this.send({
event: 'subscribe',
channel: 'ticker',
symbol
})
}
unsubscribe (chanId) {
this.send({
event: 'unsubscribe',
chanId
})
}
submitOrder (order) {
this.send(order)
}
cancelOrder (orderId) {
this.send([0, 'oc', null, {
id: orderId
}])
}
config (flags) {
this.send({
flags,
'event': 'conf'
})
}
auth (calc = 0) {
const authNonce = (new Date()).getTime() * 1000
const payload = 'AUTH' + authNonce + authNonce
const signature = crypto.createHmac('sha384', this.apiSecret).update(payload).digest('hex')
this.send({
event: 'auth',
apiKey: this.apiKey,
authSig: signature,
authPayload: payload,
authNonce: +authNonce + 1,
calc
})
}
}
module.exports = BitfinexWS2