bfx-api-node-ws1 1.0.0 → 1.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.eslintrc ADDED
@@ -0,0 +1,3 @@
1
+ {
2
+ "extends": "standard"
3
+ }
package/.eslintrc.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "parser": "babel-eslint",
3
+ "extends": [
4
+ "standard"
5
+ ],
6
+ "rules": {
7
+ "jsx-quotes": ["error", "prefer-single"],
8
+ "semi": [1, "never"],
9
+ "max-len": 0,
10
+ "import/no-named-as-default": 0,
11
+ "import/no-named-as-default-member": 0
12
+ },
13
+ "settings": {
14
+ "import/resolver": {
15
+ "node": {
16
+ "moduleDirectory": [
17
+ "node_modules",
18
+ "lib"
19
+ ]
20
+ }
21
+ }
22
+ },
23
+ "env": {
24
+ "jest": true
25
+ }
26
+ }
@@ -0,0 +1,13 @@
1
+ #### Issue type
2
+ - [ ] bug
3
+ - [ ] missing functionality
4
+ - [ ] performance
5
+ - [ ] feature request
6
+
7
+ #### Brief description
8
+
9
+ #### Steps to reproduce
10
+ -
11
+
12
+ ##### Additional Notes:
13
+ -
@@ -0,0 +1,17 @@
1
+ ### Description:
2
+ ...
3
+
4
+ ### Breaking changes:
5
+ - [ ]
6
+
7
+ ### New features:
8
+ - [ ]
9
+
10
+ ### Fixes:
11
+ - [ ]
12
+
13
+ ### PR status:
14
+ - [ ] Version bumped
15
+ - [ ] Change-log updated
16
+ - [ ] Tests added or updated
17
+ - [ ] Documentation updated
package/.travis.yml CHANGED
@@ -3,3 +3,10 @@ sudo: false
3
3
  language: node_js
4
4
  node_js:
5
5
  - "stable"
6
+
7
+ install:
8
+ - npm install
9
+
10
+ script:
11
+ - npm run lint
12
+ - npm run unit
package/CHANGELOG ADDED
@@ -0,0 +1,14 @@
1
+ # 1.0.3
2
+ - fix: use relative paths to allow generic mocha execution
3
+ - feature: add isOpen() method
4
+
5
+ # 1.0.2
6
+ - docs: create/update
7
+
8
+ # 1.0.1
9
+ - manifest: bump deps
10
+ - meta: add github issue/pr templates
11
+ - meta: standardize travis config
12
+
13
+ # 1.0.0
14
+ - Initial version
package/README.md CHANGED
@@ -1,7 +1,47 @@
1
- # Bitfinex WSv1 Reference Implementation
1
+ # Bitfinex WSv1 Reference Implementation for Node.JS
2
2
 
3
3
  [![Build Status](https://travis-ci.org/bitfinexcom/bfx-api-node-ws1.svg?branch=master)](https://travis-ci.org/bitfinexcom/bfx-api-node-ws1)
4
4
 
5
5
  This repo contains the reference implementation for version 1 of the websocket Bitfinex API. It is deprecated in favour of version 2, and should no longer be used.
6
6
 
7
7
  For the version 2 API library, see [bitfinex-api-node](https://github.com/bitfinexcom/bitfinex-api-node)
8
+
9
+ ### Features
10
+
11
+ * Emits API data as events from the class instance
12
+ * Provides methods for channel management & listening to incoming data
13
+
14
+ ### Installation
15
+
16
+ ```bash
17
+ npm i --save bfx-api-node-ws1
18
+ ```
19
+
20
+ ### Quickstart & Example
21
+
22
+ ```js
23
+ const WSv1 = require('bfx-api-node-ws1')
24
+ const ws = new WSv1()
25
+
26
+ ws.open()
27
+
28
+ ws.on('open', () => {
29
+ ws.subscribeTrades('BTCUSD')
30
+ })
31
+
32
+ ws.on('trades', (pair, trade) => {
33
+ console.log(JSON.stringify({ pair, trade }, null, 2))
34
+ })
35
+ ```
36
+
37
+ ### Docs
38
+
39
+ For JSDoc-generated API documentation, [see `docs/ws1.md`](/docs/ws1.md)
40
+
41
+ ### Contributing
42
+
43
+ 1. Fork it
44
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
45
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
46
+ 4. Push to the branch (`git push origin my-new-feature`)
47
+ 5. Create a new Pull Request
package/docs/.keep ADDED
File without changes
@@ -0,0 +1,114 @@
1
+ <a name="WSv1"></a>
2
+
3
+ ## WSv1
4
+ Communicates with v1 of the Bitfinex WebSocket API
5
+
6
+ **Kind**: global class
7
+
8
+ * [WSv1](#WSv1)
9
+ * [new WSv1()](#new_WSv1_new)
10
+ * [.open()](#WSv1+open)
11
+ * [.close()](#WSv1+close)
12
+ * [.send(msg)](#WSv1+send)
13
+ * [.subscribeOrderBook(pair, precision, length)](#WSv1+subscribeOrderBook)
14
+ * [.subscribeTrades(pair)](#WSv1+subscribeTrades)
15
+ * [.subscribeTicker(pair)](#WSv1+subscribeTicker)
16
+ * [.unsubscribe(chanId)](#WSv1+unsubscribe)
17
+ * [.auth()](#WSv1+auth)
18
+
19
+ <a name="new_WSv1_new"></a>
20
+
21
+ ### new WSv1()
22
+
23
+ | Param | Type | Description |
24
+ | --- | --- | --- |
25
+ | opts.apiKey | <code>sting</code> | |
26
+ | opts.apiSecret | <code>string</code> | |
27
+ | opts.url | <code>string</code> | ws connection url |
28
+
29
+ <a name="WSv1+open"></a>
30
+
31
+ ### wSv1.open()
32
+ Opens a new websocket conection to the configured URL
33
+
34
+ **Kind**: instance method of [<code>WSv1</code>](#WSv1)
35
+ <a name="WSv1+close"></a>
36
+
37
+ ### wSv1.close()
38
+ Close the websocket connection
39
+
40
+ **Kind**: instance method of [<code>WSv1</code>](#WSv1)
41
+ <a name="WSv1+send"></a>
42
+
43
+ ### wSv1.send(msg)
44
+ Send a packet via the ws connection; automatically converted to a JSON
45
+ string.
46
+
47
+ **Kind**: instance method of [<code>WSv1</code>](#WSv1)
48
+
49
+ | Param | Type |
50
+ | --- | --- |
51
+ | msg | <code>\*</code> |
52
+
53
+ <a name="WSv1+subscribeOrderBook"></a>
54
+
55
+ ### wSv1.subscribeOrderBook(pair, precision, length)
56
+ Subscribe to order book updates. Snapshot will be sent as multiple updates.
57
+ Event will be emited as `PAIRNAME_book`.
58
+
59
+ **Kind**: instance method of [<code>WSv1</code>](#WSv1)
60
+ **See**: http://docs.bitfinex.com/#order-books
61
+
62
+ | Param | Type | Default | Description |
63
+ | --- | --- | --- | --- |
64
+ | pair | <code>string</code> | <code>&quot;BTCUSD&quot;</code> | |
65
+ | precision | <code>string</code> | | price aggregation level (P0 (def), P1, P2, P3) |
66
+ | length | <code>string</code> | | number of price points. 25 (default) or 100. |
67
+
68
+ <a name="WSv1+subscribeTrades"></a>
69
+
70
+ ### wSv1.subscribeTrades(pair)
71
+ Subscribe to trades. Snapshot will be sent as multiple updates.
72
+ Event will be emited as `PAIRNAME_trades`.
73
+
74
+ **Kind**: instance method of [<code>WSv1</code>](#WSv1)
75
+ **See**: http://docs.bitfinex.com/#trades75
76
+
77
+ | Param | Type | Default |
78
+ | --- | --- | --- |
79
+ | pair | <code>string</code> | <code>&quot;BTCUSD&quot;</code> |
80
+
81
+ <a name="WSv1+subscribeTicker"></a>
82
+
83
+ ### wSv1.subscribeTicker(pair)
84
+ Subscribe to ticker updates. The ticker is a high level overview of the
85
+ state of the market. It shows you the current best bid and ask, as well as
86
+ the last trade price.
87
+
88
+ Event will be emited as `PAIRNAME_ticker`.
89
+
90
+ **Kind**: instance method of [<code>WSv1</code>](#WSv1)
91
+ **See**: http://docs.bitfinex.com/#ticker76
92
+
93
+ | Param | Type | Default | Description |
94
+ | --- | --- | --- | --- |
95
+ | pair | <code>string</code> | <code>&quot;BTCUSD&quot;</code> | pair |
96
+
97
+ <a name="WSv1+unsubscribe"></a>
98
+
99
+ ### wSv1.unsubscribe(chanId)
100
+ Unsubscribe from a channel.
101
+
102
+ **Kind**: instance method of [<code>WSv1</code>](#WSv1)
103
+
104
+ | Param | Type | Description |
105
+ | --- | --- | --- |
106
+ | chanId | <code>number</code> | ID of the channel received on `subscribed` event |
107
+
108
+ <a name="WSv1+auth"></a>
109
+
110
+ ### wSv1.auth()
111
+ Authenticate the user. Will receive executed traded updates.
112
+
113
+ **Kind**: instance method of [<code>WSv1</code>](#WSv1)
114
+ **See**: http://docs.bitfinex.com/#wallet-updates
package/lib/ws.js CHANGED
@@ -11,11 +11,11 @@ const WS_URL = 'wss://api.bitfinex.com/ws/'
11
11
  /**
12
12
  * Communicates with v1 of the Bitfinex WebSocket API
13
13
  */
14
- module.exports = class WSv1 extends EventEmitter {
14
+ class WSv1 extends EventEmitter {
15
15
  /**
16
16
  * @param {sting} opts.apiKey
17
17
  * @param {string} opts.apiSecret
18
- * @param {string} opts.url - ws connection url
18
+ * @param {string?} opts.url - ws connection url
19
19
  */
20
20
  constructor (opts = { apiKey: '', apiSecret: '', url: WS_URL }) {
21
21
  super()
@@ -26,15 +26,31 @@ module.exports = class WSv1 extends EventEmitter {
26
26
  this._channelMap = {} // map channel IDs to events
27
27
  }
28
28
 
29
+ /**
30
+ * Returns status of websocket
31
+ *
32
+ * @return {boolean} open
33
+ */
34
+ isOpen () {
35
+ return this._ws.isOpen()
36
+ }
37
+
38
+ /**
39
+ * Opens a new websocket conection to the configured URL
40
+ */
29
41
  open () {
30
42
  this._ws = new WebSocket(this._url)
31
-
32
43
  this._ws.on('message', this._onWSMessage.bind(this))
33
44
  this._ws.on('open', this._onWSOpen.bind(this))
34
45
  this._ws.on('error', this._onWSError.bind(this))
35
46
  this._ws.on('close', this._onWSClose.bind(this))
36
47
  }
37
48
 
49
+ /**
50
+ * @param {string} msgJSON
51
+ * @param {number} flags
52
+ * @private
53
+ */
38
54
  _onWSMessage (msgJSON, flags) {
39
55
  let msg
40
56
 
@@ -72,6 +88,10 @@ module.exports = class WSv1 extends EventEmitter {
72
88
  this.emit(msg.event, msg)
73
89
  }
74
90
 
91
+ /**
92
+ * @param {Array|Array[]} msg
93
+ * @private
94
+ */
75
95
  _handleChannel (msg) {
76
96
  // First element of Array is the channelId, the rest is the info.
77
97
  const channelId = msg.shift() // Pop the first element
@@ -98,6 +118,10 @@ module.exports = class WSv1 extends EventEmitter {
98
118
  }
99
119
  }
100
120
 
121
+ /**
122
+ * @param {Array} msg
123
+ * @private
124
+ */
101
125
  _processUserEvent (msg) {
102
126
  const event = msg[0]
103
127
  const data = msg[1]
@@ -113,6 +137,11 @@ module.exports = class WSv1 extends EventEmitter {
113
137
  }
114
138
  }
115
139
 
140
+ /**
141
+ * @param {Array} msg
142
+ * @param {Object} event
143
+ * @private
144
+ */
116
145
  _processTickerEvent (msg, event) {
117
146
  if (msg.length > 9) { // Update
118
147
  // All values are numbers
@@ -134,6 +163,11 @@ module.exports = class WSv1 extends EventEmitter {
134
163
  }
135
164
  }
136
165
 
166
+ /**
167
+ * @param {Array[]} msg
168
+ * @param {Object} event
169
+ * @private
170
+ */
137
171
  _processTradeEvent (msg, event) {
138
172
  if (isSnapshot(msg)) {
139
173
  const snapshot = msg[0].map(el => ({
@@ -169,8 +203,12 @@ module.exports = class WSv1 extends EventEmitter {
169
203
  this.emit('trade', event.pair, update)
170
204
  }
171
205
 
206
+ /**
207
+ * @param {Array[]} msg
208
+ * @param {Object} event
209
+ * @private
210
+ */
172
211
  _processBookEvent (msg, event) {
173
- // TODO: Maybe break this up into snapshot/normal handlers? Also trade event
174
212
  if (!isSnapshot(msg[0]) && msg.length > 2) {
175
213
  let update
176
214
 
@@ -217,23 +255,41 @@ module.exports = class WSv1 extends EventEmitter {
217
255
  }
218
256
  }
219
257
 
258
+ /**
259
+ * Close the websocket connection
260
+ */
220
261
  close () {
221
262
  this._ws.close()
222
263
  }
223
264
 
265
+ /**
266
+ * @private
267
+ */
224
268
  _onWSOpen () {
225
269
  this._channelMap = {}
226
270
  this.emit('open')
227
271
  }
228
272
 
273
+ /**
274
+ * @private
275
+ */
229
276
  _onWSError (error) {
230
277
  this.emit('error', error)
231
278
  }
232
279
 
280
+ /**
281
+ * @private
282
+ */
233
283
  _onWSClose () {
234
284
  this.emit('close')
235
285
  }
236
286
 
287
+ /**
288
+ * Send a packet via the ws connection; automatically converted to a JSON
289
+ * string.
290
+ *
291
+ * @param {*} msg
292
+ */
237
293
  send (msg) {
238
294
  debug('Sending %j', msg)
239
295
  this._ws.send(JSON.stringify(msg))
@@ -243,7 +299,7 @@ module.exports = class WSv1 extends EventEmitter {
243
299
  * Subscribe to order book updates. Snapshot will be sent as multiple updates.
244
300
  * Event will be emited as `PAIRNAME_book`.
245
301
  *
246
- * @param {string} pair - BTCUSD, LTCUSD or LTCBTC. Default BTCUSD
302
+ * @param {string} pair
247
303
  * @param {string} precision - price aggregation level (P0 (def), P1, P2, P3)
248
304
  * @param {string} length - number of price points. 25 (default) or 100.
249
305
  * @see http://docs.bitfinex.com/#order-books
@@ -262,7 +318,7 @@ module.exports = class WSv1 extends EventEmitter {
262
318
  * Subscribe to trades. Snapshot will be sent as multiple updates.
263
319
  * Event will be emited as `PAIRNAME_trades`.
264
320
  *
265
- * @param {string} pair - BTCUSD, LTCUSD or LTCBTC. Default BTCUSD
321
+ * @param {string} pair
266
322
  * @see http://docs.bitfinex.com/#trades75
267
323
  */
268
324
  subscribeTrades (pair = 'BTCUSD') {
@@ -280,7 +336,7 @@ module.exports = class WSv1 extends EventEmitter {
280
336
  *
281
337
  * Event will be emited as `PAIRNAME_ticker`.
282
338
  *
283
- * @param {string} - pair BTCUSD, LTCUSD or LTCBTC. Default BTCUSD
339
+ * @param {string} - pair
284
340
  * @see http://docs.bitfinex.com/#ticker76
285
341
  */
286
342
  subscribeTicker (pair = 'BTCUSD') {
@@ -319,3 +375,5 @@ module.exports = class WSv1 extends EventEmitter {
319
375
  })
320
376
  }
321
377
  }
378
+
379
+ module.exports = WSv1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bfx-api-node-ws1",
3
- "version": "1.0.0",
3
+ "version": "1.0.4",
4
4
  "description": "Legacy WSv1 transport for the Bitfinex Node API",
5
5
  "engines": {
6
6
  "node": ">=7"
@@ -9,7 +9,9 @@
9
9
  "scripts": {
10
10
  "lint": "standard",
11
11
  "test": "npm run lint && npm run unit",
12
- "unit": "NODE_ENV=test mocha -b --recursive"
12
+ "unit": "NODE_ENV=test mocha -b --recursive",
13
+ "docs": "npm run ws1_docs",
14
+ "ws1_docs": "node_modules/jsdoc-to-markdown/bin/cli.js lib/ws.js > docs/ws1_docs.md"
13
15
  },
14
16
  "repository": {
15
17
  "type": "git",
@@ -20,27 +22,31 @@
20
22
  "bitcoin",
21
23
  "BTC"
22
24
  ],
25
+ "author": "Bitfinex",
23
26
  "contributors": [
24
27
  "Josh Rossi <josh@bitfinex.com> (https://www.bitfinex.com)",
25
28
  "Cris Mihalache <cris.m@bitfinex.com> (https://www.bitfinex.com)",
26
29
  "Robert Kowalski <robert@bitfinex.com> (https://www.bitfinex.com)",
27
30
  "Simone Poggi <simone@bitfinex.com> (https://www.bitfinex.com)",
28
- "Paolo Ardoino <paolo@bitfinex.com> (https://www.bitfinex.com)"
31
+ "Paolo Ardoino <paolo@bitfinex.com> (https://www.bitfinex.com)",
32
+ "Jacob Plaster <jacob.plaster@bitfinex.com> (https://www.bitfinex.com)"
29
33
  ],
30
34
  "license": "MIT",
31
35
  "bugs": {
32
36
  "url": "https://github.com/bitfinexcom/bfx-api-node-ws1/issues"
33
37
  },
34
38
  "devDependencies": {
35
- "chai": "^3.4.1",
36
- "mocha": "^3.4.2",
37
- "standard": "^10.0.2"
39
+ "babel-eslint": "^10.0.3",
40
+ "chai": "^4.2.0",
41
+ "jsdoc-to-markdown": "^5.0.1",
42
+ "mocha": "^6.2.0",
43
+ "standard": "^14.1.0"
38
44
  },
39
45
  "dependencies": {
40
- "bluebird": "^3.5.1",
41
- "debug": "^2.2.0",
42
- "lodash": "^4.17.4",
43
- "ws": "^3.0.0",
44
- "bfx-api-node-util": "bitfinexcom/bfx-api-node-util"
46
+ "bfx-api-node-util": "^1.0.10",
47
+ "bluebird": "3.5.5",
48
+ "debug": "4.1.1",
49
+ "lodash": "^4.17.15",
50
+ "ws": "3.0.0"
45
51
  }
46
52
  }
@@ -16,11 +16,11 @@ describe('ws1 channel msg handling', () => {
16
16
  }
17
17
 
18
18
  bfxWs.once('orderbook', (symbol, data) => {
19
- assert.deepEqual(data, { price: 2477.1, orderId: 2919111002, amount: 0.0125 })
19
+ assert.deepStrictEqual(data, { price: 2477.1, orderId: 2919111002, amount: 0.0125 })
20
20
  done()
21
21
  })
22
22
 
23
- bfxWs._handleChannel([ 32755, 2919111002, 2477.1, 0.0125 ])
23
+ bfxWs._handleChannel([32755, 2919111002, 2477.1, 0.0125])
24
24
  })
25
25
 
26
26
  it('ws1 transforms & normalizes well - P1 update', (done) => {
@@ -29,11 +29,11 @@ describe('ws1 channel msg handling', () => {
29
29
  }
30
30
 
31
31
  bfxWs.once('orderbook', (symbol, data) => {
32
- assert.deepEqual(data, { price: 2494, count: 2, amount: 5.9895 })
32
+ assert.deepStrictEqual(data, { price: 2494, count: 2, amount: 5.9895 })
33
33
  done()
34
34
  })
35
35
 
36
- bfxWs._handleChannel([ 182, 2494, 2, 5.9895 ])
36
+ bfxWs._handleChannel([182, 2494, 2, 5.9895])
37
37
  })
38
38
 
39
39
  it('ws1 transforms & normalizes well - P1 snap', (done) => {
@@ -42,14 +42,14 @@ describe('ws1 channel msg handling', () => {
42
42
  }
43
43
 
44
44
  bfxWs.once('orderbook', (symbol, data) => {
45
- assert.deepEqual(data[1], { price: 2494, count: 3, amount: 0.14606853 })
45
+ assert.deepStrictEqual(data[1], { price: 2494, count: 3, amount: 0.14606853 })
46
46
  done()
47
47
  })
48
48
 
49
- const snap = [ 39, [
50
- [ 2495, 2, 0.8744 ],
51
- [ 2494, 3, 0.14606853 ],
52
- [ 2492, 1, 0.4 ]
49
+ const snap = [39, [
50
+ [2495, 2, 0.8744],
51
+ [2494, 3, 0.14606853],
52
+ [2492, 1, 0.4]
53
53
  ]]
54
54
 
55
55
  bfxWs._handleChannel(snap)
@@ -61,17 +61,17 @@ describe('ws1 channel msg handling', () => {
61
61
  }
62
62
 
63
63
  bfxWs.once('orderbook', (symbol, data) => {
64
- assert.deepEqual(
64
+ assert.deepStrictEqual(
65
65
  data[1],
66
66
  { price: 2494.5, orderId: 2919279471, amount: 0.07288 }
67
67
  )
68
68
  done()
69
69
  })
70
70
 
71
- const snap = [ 34513, [
72
- [ 2919278474, 2494.5, 0.07901704 ],
73
- [ 2919279471, 2494.5, 0.07288 ],
74
- [ 2919280093, 2494.5, 0.03644 ]
71
+ const snap = [34513, [
72
+ [2919278474, 2494.5, 0.07901704],
73
+ [2919279471, 2494.5, 0.07288],
74
+ [2919280093, 2494.5, 0.03644]
75
75
  ]]
76
76
 
77
77
  bfxWs._handleChannel(snap)
@@ -8,16 +8,35 @@ const WebSocket = require('ws')
8
8
  const WSv1 = require('../../lib/ws')
9
9
 
10
10
  describe('websocket1 parsing non json', () => {
11
+ let ws = null
12
+ let wss = null
13
+
14
+ afterEach(async () => {
15
+ try { // may fail due to being modified by a test, it's not a problem
16
+ if (ws && ws.isOpen()) {
17
+ await new Promise(resolve => ws.close(resolve))
18
+ }
19
+ } catch (e) {}
20
+
21
+ ws = null
22
+
23
+ if (wss) {
24
+ await new Promise(resolve => wss.close(resolve))
25
+ }
26
+
27
+ wss = null
28
+ })
29
+
11
30
  it('should not crash the client', (done) => {
12
- const bws = new WSv1({
31
+ ws = new WSv1({
13
32
  apiKey: 'dummy',
14
33
  apiSecret: 'dummy',
15
34
  url: `ws://localhost:${PORT}`
16
35
  })
17
36
 
18
- bws.open()
37
+ ws.open()
19
38
 
20
- const wss = new WebSocket.Server({
39
+ wss = new WebSocket.Server({
21
40
  perMessageDeflate: false,
22
41
  port: PORT
23
42
  })
@@ -25,16 +44,13 @@ describe('websocket1 parsing non json', () => {
25
44
  wss.on('connection', function connection (ws) {
26
45
  ws.on('message', function incoming (msg) {
27
46
  msg = JSON.parse(msg)
28
- assert.equal(msg.len, '25')
29
- wss.close()
47
+ assert.strictEqual(msg.len, '25')
30
48
  done()
31
49
  })
32
50
 
33
51
  ws.send("HTTP Code 408 - I'm a Tea Pot")
34
52
  })
35
53
 
36
- bws.on('open', () => {
37
- bws.subscribeOrderBook('BTCUSD', 'R0')
38
- })
54
+ ws.on('open', () => ws.subscribeOrderBook('BTCUSD', 'R0'))
39
55
  })
40
56
  })
@@ -1,112 +1,121 @@
1
1
  /* eslint-env mocha */
2
2
  'use strict'
3
3
 
4
- const PORT = 1337
5
-
6
4
  const assert = require('assert')
7
-
8
5
  const WebSocket = require('ws')
9
- const WSv1 = require('../../lib/ws')
6
+ const _isObject = require('lodash/isObject')
10
7
 
8
+ const WSv1 = require('../../lib/ws')
11
9
  const orderbookR0 = require('../fixtures/response-ws-1-orderbook-R0.json')
12
10
 
13
- const getWSInstance = () => {
14
- return new WSv1({
15
- apiKey: 'dummy',
16
- apiSecret: 'dummy',
17
- url: `ws://localhost:${PORT}`
11
+ const PORT = 1334
12
+ const getWSInstance = (args) => (
13
+ new WSv1({
14
+ url: `ws://localhost:${PORT}`,
15
+ ...args
18
16
  })
19
- }
17
+ )
20
18
 
21
19
  describe('WebSocket v1 integration', () => {
20
+ let ws = null
21
+ let wss = null
22
+
23
+ afterEach(async () => {
24
+ try { // may fail due to being modified by a test, it's not a problem
25
+ if (ws && ws.isOpen()) {
26
+ ws.close()
27
+ }
28
+ } catch (e) {}
29
+
30
+ ws = null
31
+
32
+ if (wss) {
33
+ await new Promise(resolve => wss.close(resolve))
34
+ }
35
+
36
+ wss = null
37
+ })
38
+
22
39
  it('plays ping pong', (done) => {
23
- const wss = new WebSocket.Server({
40
+ wss = new WebSocket.Server({
24
41
  perMessageDeflate: false,
25
42
  port: PORT
26
43
  })
27
44
 
28
- const bws = getWSInstance()
29
- bws.open()
30
-
31
- wss.on('connection', function connection (ws) {
32
- ws.on('message', function incoming (msg) {
45
+ ws = getWSInstance()
46
+ wss.on('connection', (ws) => {
47
+ ws.on('message', (msg) => {
33
48
  ws.send('{"event":"pong"}')
34
49
  })
35
50
  })
36
51
 
37
- bws.on('open', () => {
38
- bws.send({ event: 'ping' })
39
- })
40
-
41
- bws.on('pong', () => {
42
- bws.close()
43
- wss.close(done)
44
- })
52
+ ws.on('open', () => ws.send({ event: 'ping' }))
53
+ ws.on('pong', () => done())
54
+ ws.open()
45
55
  })
46
56
 
47
57
  it('should receive info message', (done) => {
48
- const wss = new WebSocket.Server({
58
+ wss = new WebSocket.Server({
49
59
  perMessageDeflate: false,
50
60
  port: PORT
51
61
  })
52
62
 
53
- const bws = getWSInstance()
54
- bws.open()
63
+ ws = getWSInstance()
55
64
 
56
- wss.on('connection', function connection (ws) {
57
- ws.send('{"event": "info", "version": 1.1 }')
65
+ wss.on('connection', (ws) => {
66
+ ws.send(JSON.stringify({
67
+ event: 'info',
68
+ version: 1.1,
69
+ platform: {
70
+ status: 1
71
+ }
72
+ }))
58
73
  })
59
74
 
60
- bws.on('info', (data) => {
61
- assert.deepEqual(
62
- data,
63
- {
64
- event: 'info',
65
- version: 1.1
66
- }
67
- )
68
- bws.close()
69
- wss.close(done)
75
+ ws.on('info', (data) => {
76
+ assert(_isObject(data.platform))
77
+ assert.strictEqual(data.event, 'info')
78
+ assert.strictEqual(data.version, 1.1)
79
+ assert.strictEqual(data.platform.status, 1)
80
+ done()
70
81
  })
82
+
83
+ ws.open()
71
84
  })
72
85
 
73
86
  it('should emit an error when authorization fails', (done) => {
74
- const wss = new WebSocket.Server({
87
+ wss = new WebSocket.Server({
75
88
  perMessageDeflate: false,
76
89
  port: PORT
77
90
  })
78
91
 
79
- const bws = getWSInstance()
80
- bws.open()
92
+ ws = getWSInstance()
81
93
 
82
- wss.on('connection', function connection (ws) {
83
- ws.on('message', function incoming (msg) {
94
+ wss.on('connection', (ws) => {
95
+ ws.on('message', (msg) => {
84
96
  ws.send('{"event":"auth","status":"FAILED","chanId":0,"code":10100,"msg":"apikey: invalid"}')
85
97
  })
86
98
  })
87
99
 
88
- bws.on('error', (err) => {
89
- assert.equal(err.event, 'auth')
90
- bws.close()
91
- wss.close(done)
100
+ ws.on('error', (err) => {
101
+ assert.strictEqual(err.event, 'auth')
102
+ done()
92
103
  })
93
104
 
94
- bws.on('open', () => {
95
- bws.auth()
96
- })
105
+ ws.on('open', ws.auth.bind(ws))
106
+ ws.open()
97
107
  })
98
108
 
99
- it('should unsubscribe by channelId', function (done) {
100
- const wss = new WebSocket.Server({
109
+ it('should unsubscribe by channelId', (done) => {
110
+ wss = new WebSocket.Server({
101
111
  perMessageDeflate: false,
102
112
  port: PORT
103
113
  })
104
114
 
105
- const bws = getWSInstance()
106
- bws.open()
115
+ ws = getWSInstance()
107
116
 
108
- wss.on('connection', function connection (ws) {
109
- ws.on('message', function incoming (msg) {
117
+ wss.on('connection', (ws) => {
118
+ ws.on('message', (msg) => {
110
119
  msg = JSON.parse(msg)
111
120
  if (msg.event === 'unsubscribe') {
112
121
  ws.send('{"event":"unsubscribed","status":"OK","chanId":4}')
@@ -117,159 +126,157 @@ describe('WebSocket v1 integration', () => {
117
126
  })
118
127
  })
119
128
 
120
- bws.once('subscribed', (data) => {
129
+ ws.once('subscribed', (data) => {
121
130
  const channelId = data.chanId
122
131
 
123
- bws.once('unsubscribed', (data) => {
124
- assert.equal(data.status, 'OK')
125
- assert.equal(data.chanId, channelId)
126
- bws.close()
127
- wss.close(done)
132
+ ws.once('unsubscribed', (data) => {
133
+ assert.strictEqual(data.status, 'OK')
134
+ assert.strictEqual(data.chanId, channelId)
135
+ done()
128
136
  })
129
- bws.unsubscribe(channelId)
130
- })
131
- bws.on('open', () => {
132
- bws.subscribeTicker('BTCUSD')
137
+
138
+ ws.unsubscribe(channelId)
133
139
  })
140
+
141
+ ws.on('open', () => ws.subscribeTicker('BTCUSD'))
142
+ ws.open()
134
143
  })
135
144
 
136
145
  it('should receive a subscribed success messages', (done) => {
137
- const wss = new WebSocket.Server({
146
+ wss = new WebSocket.Server({
138
147
  perMessageDeflate: false,
139
148
  port: PORT
140
149
  })
141
150
 
142
- const bws = getWSInstance()
143
- bws.open()
144
-
145
- wss.on('connection', function connection (ws) {
146
- ws.on('message', function incoming (msg) {
151
+ ws = getWSInstance()
152
+ wss.on('connection', (ws) => {
153
+ ws.on('message', (msg) => {
147
154
  ws.send('{"event":"subscribed","channel":"trades","chanId":4,"pair":"BTCUSD"}')
148
155
  })
149
156
  })
150
157
 
151
- bws.on('subscribed', (data) => {
152
- assert.equal(data.channel, 'trades')
153
- assert.equal(data.pair, 'BTCUSD')
154
- bws.close()
155
- wss.close(done)
156
- })
157
- bws.on('open', () => {
158
- bws.subscribeTrades('BTCUSD')
158
+ ws.on('subscribed', (data) => {
159
+ assert.strictEqual(data.channel, 'trades')
160
+ assert.strictEqual(data.pair, 'BTCUSD')
161
+ done()
159
162
  })
163
+
164
+ ws.on('open', () => ws.subscribeTrades('BTCUSD'))
165
+ ws.open()
160
166
  })
161
167
 
162
168
  it('#orderBook data should have the defined fields', (done) => {
163
- const wss = new WebSocket.Server({
169
+ wss = new WebSocket.Server({
164
170
  perMessageDeflate: false,
165
171
  port: PORT
166
172
  })
167
173
 
168
- wss.on('connection', function connection (ws) {
169
- ws.on('message', function incoming (msg) {
170
- ws.send('{"event":"subscribed","channel":"book","chanId":13242,"prec":"R0","freq":"F0","len":"25","pair":"BTCUSD"}')
174
+ wss.on('connection', (ws) => {
175
+ ws.on('message', (msg) => {
176
+ ws.send(JSON.stringify({
177
+ event: 'subscribed',
178
+ channel: 'book',
179
+ chanId: 13242,
180
+ prec: 'R0',
181
+ freq: 'F0',
182
+ len: '25',
183
+ pair: 'BTCUSD'
184
+ }))
185
+
171
186
  ws.send(JSON.stringify(orderbookR0))
172
187
  })
173
188
  })
174
189
 
175
- const bws = getWSInstance()
176
- bws.open()
177
-
178
- bws.once('orderbook', (pair, data) => {
179
- assert.equal(pair, 'BTCUSD')
180
- assert.equal(typeof data[0].price, 'number')
181
- assert.equal(typeof data[0].orderId, 'number')
182
- assert.equal(typeof data[0].amount, 'number')
183
- assert.equal(data.length, 50)
184
- bws.close()
185
- wss.close(done)
190
+ ws = getWSInstance({ transform: true })
191
+ ws.once('orderbook', (pair, data) => {
192
+ assert.strictEqual(pair, 'BTCUSD')
193
+ assert.strictEqual(typeof data[0].price, 'number')
194
+ assert.strictEqual(typeof data[0].orderId, 'number')
195
+ assert.strictEqual(typeof data[0].amount, 'number')
196
+ assert.strictEqual(data.length, 50)
197
+ done()
186
198
  })
187
- bws.on('open', () => {
188
- bws.subscribeOrderBook('BTCUSD')
189
- })
190
- })
199
+
200
+ ws.on('open', () => ws.subscribeOrderBook('BTCUSD'))
201
+ ws.open()
202
+ }).timeout(10 * 1000)
191
203
 
192
204
  it('#ticker data should have the defined fields', (done) => {
193
- const wss = new WebSocket.Server({
205
+ wss = new WebSocket.Server({
194
206
  perMessageDeflate: false,
195
207
  port: PORT
196
208
  })
197
209
 
198
- wss.on('connection', function connection (ws) {
210
+ wss.on('connection', (ws) => {
199
211
  ws.send('{"event":"info","version":1.1}')
200
- ws.on('message', function incoming (msg) {
212
+ ws.on('message', (msg) => {
201
213
  ws.send('{"event":"subscribed","channel":"ticker","chanId":4,"pair":"BTCUSD"}')
202
214
  ws.send('[4,2169.6,1.93,2169.8,0.0349,100.9,0.0488,2169.6,25479.40978657,2196,2000.1]')
203
215
  })
204
216
  })
205
217
 
206
- const bws = getWSInstance()
207
- bws.open()
208
-
209
- bws.once('ticker', (pair, data) => {
210
- assert.equal(pair, 'BTCUSD')
211
- assert.equal(typeof data.bid, 'number')
212
- assert.equal(typeof data.bidSize, 'number')
213
- assert.equal(typeof data.ask, 'number')
214
- assert.equal(typeof data.askSize, 'number')
215
- assert.equal(typeof data.dailyChange, 'number')
216
- assert.equal(typeof data.dailyChangePerc, 'number')
217
- assert.equal(typeof data.lastPrice, 'number')
218
- assert.equal(typeof data.volume, 'number')
219
- assert.equal(typeof data.high, 'number')
220
- assert.equal(typeof data.low, 'number')
221
- bws.close()
222
- wss.close(done)
223
- })
224
- bws.on('open', () => {
225
- bws.subscribeTicker('BTCUSD')
218
+ ws = getWSInstance()
219
+
220
+ ws.once('ticker', (pair, data) => {
221
+ assert.strictEqual(pair, 'BTCUSD')
222
+ assert.strictEqual(typeof data.bid, 'number')
223
+ assert.strictEqual(typeof data.bidSize, 'number')
224
+ assert.strictEqual(typeof data.ask, 'number')
225
+ assert.strictEqual(typeof data.askSize, 'number')
226
+ assert.strictEqual(typeof data.dailyChange, 'number')
227
+ assert.strictEqual(typeof data.dailyChangePerc, 'number')
228
+ assert.strictEqual(typeof data.lastPrice, 'number')
229
+ assert.strictEqual(typeof data.volume, 'number')
230
+ assert.strictEqual(typeof data.high, 'number')
231
+ assert.strictEqual(typeof data.low, 'number')
232
+ done()
226
233
  })
234
+
235
+ ws.on('open', () => ws.subscribeTicker('BTCUSD'))
236
+ ws.open()
227
237
  })
228
238
 
229
239
  it('#trade data should have the defined fields', (done) => {
230
- const wss = new WebSocket.Server({
240
+ wss = new WebSocket.Server({
231
241
  perMessageDeflate: false,
232
242
  port: PORT
233
243
  })
234
244
 
235
- wss.on('connection', function connection (ws) {
245
+ wss.on('connection', (ws) => {
236
246
  ws.send('{"event":"info","version":1.1}')
237
- ws.on('message', function incoming (msg) {
247
+ ws.on('message', (msg) => {
238
248
  ws.send('{"event":"subscribed","channel":"trades","chanId":33,"pair":"BTCUSD"}')
239
- ws.send(`
240
- [33,[[32970704,1495442718,2169.1,0.03647196],[32970701,1495442718,2169.1,0.01058338],
241
- [32970697,1495442717,2169,-0.0000791],[32970696,1495442717,2169,-0.01054738],
242
- [32970692,1495442716,2169,-0.01063712],[32970683,1495442715,2169,-0.00191556],
243
- [32970682,1495442715,2169,-0.02003456],[32970681,1495442715,2169,-0.02002811],
244
- [32970680,1495442715,2169,-0.01079782],[32970679,1495442715,2169,-0.02002726],
245
- [32970678,1495442715,2169,-0.01079782],[32970662,1495442714,2169,-3.68585828],
246
- [32970654,1495442712,2169,-0.01413205],[32970646,1495442711,2169,-0.01066102],
247
- [32970643,1495442710,2169,-0.02002146],[32970640,1495442709,2169,-0.01727607],
248
- [32970631,1495442708,2169,-0.00984518],[32970629,1495442708,2169,-1.07188465],
249
- [32970618,1495442706,2169,-0.0995877],[32970613,1495442706,2169,-0.015553],
250
- [32970595,1495442702,2169,-0.00864857],[32970593,1495442702,2169,-0.01999732],
251
- [32970592,1495442702,2169,-0.01067048],[32970591,1495442702,2169.1,0.92541262],
252
- [32970590,1495442702,2169.1,0.9787866],[32970589,1495442702,2169,-0.01067048],
253
- [32970573,1495442702,2169,-0.01067048],[32970572,1495442702,2169,-0.0172659],
254
- [32970569,1495442701,2169,-0.02000913],[32970567,1495442701,2169,-0.01413205]]]
255
- `)
249
+ ws.send([
250
+ '[33,[[32970704,1495442718,2169.1,0.03647196],[32970701,1495442718,2169.1,0.01058338],',
251
+ '[32970697,1495442717,2169,-0.0000791],[32970696,1495442717,2169,-0.01054738],',
252
+ '[32970692,1495442716,2169,-0.01063712],[32970683,1495442715,2169,-0.00191556],',
253
+ '[32970682,1495442715,2169,-0.02003456],[32970681,1495442715,2169,-0.02002811],',
254
+ '[32970680,1495442715,2169,-0.01079782],[32970679,1495442715,2169,-0.02002726],',
255
+ '[32970678,1495442715,2169,-0.01079782],[32970662,1495442714,2169,-3.68585828],',
256
+ '[32970654,1495442712,2169,-0.01413205],[32970646,1495442711,2169,-0.01066102],',
257
+ '[32970643,1495442710,2169,-0.02002146],[32970640,1495442709,2169,-0.01727607],',
258
+ '[32970631,1495442708,2169,-0.00984518],[32970629,1495442708,2169,-1.07188465],',
259
+ '[32970618,1495442706,2169,-0.0995877],[32970613,1495442706,2169,-0.015553],',
260
+ '[32970595,1495442702,2169,-0.00864857],[32970593,1495442702,2169,-0.01999732],',
261
+ '[32970592,1495442702,2169,-0.01067048],[32970591,1495442702,2169.1,0.92541262],',
262
+ '[32970590,1495442702,2169.1,0.9787866],[32970589,1495442702,2169,-0.01067048],',
263
+ '[32970573,1495442702,2169,-0.01067048],[32970572,1495442702,2169,-0.0172659],',
264
+ '[32970569,1495442701,2169,-0.02000913],[32970567,1495442701,2169,-0.01413205]]]'
265
+ ].join(''))
256
266
  })
257
267
  })
258
268
 
259
- const bws = getWSInstance()
260
- bws.open()
261
-
262
- bws.once('trade', (pair, data) => {
263
- assert.equal(pair, 'BTCUSD')
264
- assert.equal(typeof data[0].seq, 'number')
265
- assert.equal(typeof data[0].timestamp, 'number')
266
- assert.equal(typeof data[0].price, 'number')
267
- assert.equal(typeof data[0].amount, 'number')
268
- bws.close()
269
- wss.close(done)
270
- })
271
- bws.on('open', () => {
272
- bws.subscribeTrades('BTCUSD')
269
+ ws = getWSInstance()
270
+
271
+ ws.once('trade', (pair, data) => {
272
+ assert.strictEqual(pair, 'BTCUSD')
273
+ assert.strictEqual(typeof data[0].timestamp, 'number')
274
+ assert.strictEqual(typeof data[0].price, 'number')
275
+ assert.strictEqual(typeof data[0].amount, 'number')
276
+ done()
273
277
  })
278
+
279
+ ws.on('open', () => ws.subscribeTrades('BTCUSD'))
280
+ ws.open()
274
281
  })
275
- })
282
+ }).timeout(10 * 1000)