@nxtedition/deepstream.io-client-js 24.3.4 → 25.0.1

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nxtedition/deepstream.io-client-js",
3
- "version": "24.3.4",
3
+ "version": "25.0.1",
4
4
  "description": "the javascript client for deepstream.io",
5
5
  "homepage": "http://deepstream.io",
6
6
  "type": "module",
@@ -1,6 +1,6 @@
1
1
  import * as C from '../constants/constants.js'
2
2
  import * as messageBuilder from '../message/message-builder.js'
3
- import messageParser from '../message/message-parser.js'
3
+ import { convertTyped } from '../message/message-parser.js'
4
4
  import MulticastListener from '../utils/multicast-listener.js'
5
5
  import UnicastListener from '../utils/unicast-listener.js'
6
6
  import EventEmitter from 'component-emitter2'
@@ -143,7 +143,7 @@ EventHandler.prototype._$handle = function (message) {
143
143
 
144
144
  if (message.action === C.ACTIONS.EVENT) {
145
145
  if (message.data && message.data.length === 2) {
146
- this._emitter.emit(name, messageParser.convertTyped(data, this._client))
146
+ this._emitter.emit(name, convertTyped(data, this._client))
147
147
  } else {
148
148
  this._emitter.emit(name)
149
149
  }
@@ -1,10 +1,11 @@
1
1
  import * as utils from '../utils/utils.js'
2
- import messageParser from './message-parser.js'
2
+ import { convertTyped } from './message-parser.js'
3
3
  import * as messageBuilder from './message-builder.js'
4
4
  import * as C from '../constants/constants.js'
5
5
  import xxhash from 'xxhash-wasm'
6
6
  import FixedQueue from '../utils/fixed-queue.js'
7
7
  import Emitter from 'component-emitter2'
8
+ import varint from 'varint'
8
9
 
9
10
  const BrowserWebSocket = globalThis.WebSocket || globalThis.MozWebSocket
10
11
  const NodeWebSocket = utils.isNode ? await import('ws').then((x) => x.default) : null
@@ -23,12 +24,8 @@ const Connection = function (client, url, options) {
23
24
  this._tooManyAuthAttempts = false
24
25
  this._connectionAuthenticationTimeout = false
25
26
  this._challengeDenied = false
26
- this._message = {
27
- raw: null,
28
- topic: null,
29
- action: null,
30
- data: null,
31
- }
27
+ this._decoder = new TextDecoder()
28
+ this._encoder = new TextEncoder()
32
29
  this._recvQueue = new FixedQueue()
33
30
  this._reconnectTimeout = null
34
31
  this._reconnectionAttempt = 0
@@ -106,9 +103,8 @@ Connection.prototype._createEndpoint = function () {
106
103
  this._endpoint.onerror = this._onError.bind(this)
107
104
  this._endpoint.onclose = this._onClose.bind(this)
108
105
 
109
- const decoder = new TextDecoder()
110
106
  this._endpoint.onmessage = ({ data }) => {
111
- this._onMessage(typeof data === 'string' ? data : decoder.decode(data))
107
+ this._onMessage(data)
112
108
  }
113
109
  }
114
110
 
@@ -117,12 +113,7 @@ Connection.prototype.send = function (message) {
117
113
 
118
114
  if (message.length > maxPacketSize) {
119
115
  const err = new Error(`Packet to big: ${message.length} > ${maxPacketSize}`)
120
- this._client._$onError(
121
- C.TOPIC.CONNECTION,
122
- C.EVENT.CONNECTION_ERROR,
123
- err,
124
- message.split(C.MESSAGE_PART_SEPERATOR).map((x) => x.slice(0, 256))
125
- )
116
+ this._client._$onError(C.TOPIC.CONNECTION, C.EVENT.CONNECTION_ERROR, err, message)
126
117
  return false
127
118
  }
128
119
 
@@ -170,7 +161,7 @@ Connection.prototype._sendAuthParams = function () {
170
161
  this._setState(C.CONNECTION_STATE.AUTHENTICATING)
171
162
  const authMessage = messageBuilder.getMsg(C.TOPIC.AUTH, C.ACTIONS.REQUEST, [
172
163
  this._authParams,
173
- '24.3.1', // TODO (fix): How to read from package.json?
164
+ '25.0.0', // TODO (fix): How to read from package.json?
174
165
  utils.isNode
175
166
  ? `Node/${process.version}`
176
167
  : globalThis.navigator && globalThis.navigator.userAgent,
@@ -215,13 +206,60 @@ Connection.prototype._onClose = function () {
215
206
  }
216
207
  }
217
208
 
218
- Connection.prototype._onMessage = function (data) {
219
- // Remove MESSAGE_SEPERATOR if exists.
220
- if (data.charCodeAt(data.length - 1) === 30) {
221
- data = data.slice(0, -1)
209
+ Connection.prototype._onMessage = function (raw) {
210
+ if (typeof raw === 'string') {
211
+ raw = this._encoder.encode(raw)
212
+ } else if (!utils.isNode) {
213
+ raw = new Uint8Array(raw)
214
+ }
215
+
216
+ const len = raw.byteLength
217
+
218
+ const start = 0
219
+
220
+ let pos = start
221
+
222
+ let headerSize = 0
223
+ if (raw[pos] >= 128) {
224
+ headerSize = raw[pos] - 128
225
+ pos += headerSize
226
+ }
227
+
228
+ // TODO (perf): Use numbers instead of string..
229
+ const topic = String.fromCharCode(raw[pos++])
230
+ pos++
231
+
232
+ let action = ''
233
+ while (pos < len && raw[pos] !== 31) {
234
+ // TODO (perf): Use numbers instead of string..
235
+ action += String.fromCharCode(raw[pos++])
222
236
  }
237
+ pos++
223
238
 
224
- this._recvQueue.push(data)
239
+ // TODO (fix): Validate topic and action
240
+
241
+ let data
242
+
243
+ // TODO (fix): Don't stringify binary data...
244
+
245
+ if (headerSize > 0) {
246
+ data = []
247
+ let headerPos = start + 1
248
+ while (headerPos < headerSize) {
249
+ const len = varint.decode(raw, headerPos)
250
+ headerPos += varint.decode.bytes
251
+ if (len === 0) {
252
+ break
253
+ }
254
+ data.push(this._decoder.decode(raw.subarray(pos, pos + len - 1)))
255
+ pos += len
256
+ }
257
+ } else {
258
+ data =
259
+ pos < len ? this._decoder.decode(raw.subarray(pos, len)).split(C.MESSAGE_PART_SEPERATOR) : []
260
+ }
261
+
262
+ this._recvQueue.push({ topic, action, data })
225
263
  if (!this._processingRecv) {
226
264
  this._processingRecv = true
227
265
  this._schedule(this._recvMessages)
@@ -245,20 +283,19 @@ Connection.prototype._recvMessages = function (deadline) {
245
283
  continue
246
284
  }
247
285
 
248
- if (this._logger) {
249
- this._logger.trace(message, 'receive')
286
+ if (message === C.TOPIC.ERROR) {
287
+ this._client._$onError(C.TOPIC.ERROR, message.action, new Error('Message error'), message)
288
+ continue
250
289
  }
251
290
 
252
- messageParser.parseMessage(message, this._client, this._message)
253
-
254
- this.emit('recv', this._message)
291
+ this.emit('recv', message)
255
292
 
256
- if (this._message.topic === C.TOPIC.CONNECTION) {
257
- this._handleConnectionResponse(this._message)
258
- } else if (this._message.topic === C.TOPIC.AUTH) {
259
- this._handleAuthResponse(this._message)
293
+ if (message.topic === C.TOPIC.CONNECTION) {
294
+ this._handleConnectionResponse(message)
295
+ } else if (message.topic === C.TOPIC.AUTH) {
296
+ this._handleAuthResponse(message)
260
297
  } else {
261
- this._client._$onMessage(this._message)
298
+ this._client._$onMessage(message)
262
299
  }
263
300
  }
264
301
 
@@ -315,7 +352,7 @@ Connection.prototype._getAuthData = function (data) {
315
352
  if (data === undefined) {
316
353
  return null
317
354
  } else {
318
- return messageParser.convertTyped(data, this._client)
355
+ return convertTyped(data, this._client)
319
356
  }
320
357
  }
321
358
 
@@ -1,10 +1,6 @@
1
1
  import * as C from '../constants/constants.js'
2
2
 
3
- const MessageParser = function () {
4
- this._actions = this._getActions()
5
- }
6
-
7
- MessageParser.prototype.convertTyped = function (value, client) {
3
+ export function convertTyped(value, client) {
8
4
  const type = value.charAt(0)
9
5
 
10
6
  if (type === C.TYPES.STRING) {
@@ -44,48 +40,3 @@ MessageParser.prototype.convertTyped = function (value, client) {
44
40
 
45
41
  return undefined
46
42
  }
47
-
48
- MessageParser.prototype._getActions = function () {
49
- const actions = {}
50
-
51
- for (const key in C.ACTIONS) {
52
- actions[C.ACTIONS[key]] = key
53
- }
54
-
55
- return actions
56
- }
57
-
58
- MessageParser.prototype.parseMessage = function (message, client, result) {
59
- const parts = message.split(C.MESSAGE_PART_SEPERATOR)
60
-
61
- if (parts.length < 2) {
62
- client._$onError(
63
- C.TOPIC.ERROR,
64
- C.EVENT.MESSAGE_PARSE_ERROR,
65
- new Error('Insufficiant message parts')
66
- )
67
- return null
68
- }
69
-
70
- if (parts[0] === C.TOPIC.ERROR) {
71
- client._$onError(C.TOPIC.ERROR, parts[1], new Error('Message error'), message)
72
- return null
73
- }
74
-
75
- if (this._actions[parts[1]] === undefined) {
76
- client._$onError(
77
- C.TOPIC.ERROR,
78
- C.EVENT.MESSAGE_PARSE_ERROR,
79
- new Error('Unknown action'),
80
- message
81
- )
82
- return null
83
- }
84
-
85
- result.raw = message
86
- result.topic = parts[0]
87
- result.action = parts[1]
88
- result.data = parts.splice(2)
89
- }
90
-
91
- export default new MessageParser()
@@ -1,7 +1,7 @@
1
1
  import jsonPath from '@nxtedition/json-path'
2
2
  import * as utils from '../utils/utils.js'
3
3
  import * as C from '../constants/constants.js'
4
- import messageParser from '../message/message-parser.js'
4
+ import { convertTyped } from '../message/message-parser.js'
5
5
  import xuid from 'xuid'
6
6
  import invariant from 'invariant'
7
7
  import cloneDeep from 'lodash.clonedeep'
@@ -470,7 +470,7 @@ class Record {
470
470
  const prevState = this._state
471
471
 
472
472
  this._state =
473
- hasProvider && messageParser.convertTyped(hasProvider, this._handler._client)
473
+ hasProvider && convertTyped(hasProvider, this._handler._client)
474
474
  ? C.RECORD_STATE.PROVIDER
475
475
  : this._version.charAt(0) === 'I'
476
476
  ? C.RECORD_STATE.STALE
@@ -1,6 +1,6 @@
1
1
  import * as C from '../constants/constants.js'
2
2
  import RpcResponse from './rpc-response.js'
3
- import messageParser from '../message/message-parser.js'
3
+ import { convertTyped } from '../message/message-parser.js'
4
4
  import * as messageBuilder from '../message/message-builder.js'
5
5
  import xuid from 'xuid'
6
6
 
@@ -111,7 +111,7 @@ RpcHandler.prototype._respond = function (message) {
111
111
  if (callback) {
112
112
  let promise
113
113
  try {
114
- promise = Promise.resolve(callback(messageParser.convertTyped(data, this._client), response))
114
+ promise = Promise.resolve(callback(convertTyped(data, this._client), response))
115
115
  } catch (err) {
116
116
  promise = Promise.reject(err)
117
117
  }
@@ -156,7 +156,7 @@ RpcHandler.prototype._$handle = function (message) {
156
156
  })
157
157
  )
158
158
  } else {
159
- rpc.callback(null, messageParser.convertTyped(data, this._client))
159
+ rpc.callback(null, convertTyped(data, this._client))
160
160
  }
161
161
  }
162
162
  }