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

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.0",
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,57 @@ 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
+ }
213
+
214
+ raw = new Uint8Array(raw)
215
+ const len = raw.byteLength
216
+
217
+ const start = 0
218
+
219
+ let pos = start
220
+
221
+ let headerSize = 0
222
+ if (raw[pos] >= 128) {
223
+ headerSize = raw[pos] - 128
224
+ pos += headerSize
225
+ }
226
+
227
+ const topic = String.fromCharCode(raw[pos++])
228
+ pos++
229
+
230
+ let action = ''
231
+ while (pos < len && raw[pos] !== 31) {
232
+ action += String.fromCharCode(raw[pos++])
222
233
  }
234
+ pos++
223
235
 
224
- this._recvQueue.push(data)
236
+ // TODO (fix): Validate topic and action
237
+
238
+ let data
239
+
240
+ // TODO (fix): Don't stringify binary data...
241
+
242
+ if (headerSize > 0) {
243
+ data = []
244
+ let headerPos = start + 1
245
+ while (headerPos < headerSize) {
246
+ const len = varint.decode(raw, headerPos)
247
+ headerPos += varint.decode.bytes
248
+ if (len === 0) {
249
+ break
250
+ }
251
+ data.push(this._decoder.decode(raw.subarray(pos, pos + len - 1)))
252
+ pos += len
253
+ }
254
+ } else {
255
+ data =
256
+ pos < len ? this._decoder.decode(raw.subarray(pos, len)).split(C.MESSAGE_PART_SEPERATOR) : []
257
+ }
258
+
259
+ this._recvQueue.push({ topic, action, data })
225
260
  if (!this._processingRecv) {
226
261
  this._processingRecv = true
227
262
  this._schedule(this._recvMessages)
@@ -245,20 +280,19 @@ Connection.prototype._recvMessages = function (deadline) {
245
280
  continue
246
281
  }
247
282
 
248
- if (this._logger) {
249
- this._logger.trace(message, 'receive')
283
+ if (message === C.TOPIC.ERROR) {
284
+ this._client._$onError(C.TOPIC.ERROR, message.action, new Error('Message error'), message)
285
+ continue
250
286
  }
251
287
 
252
- messageParser.parseMessage(message, this._client, this._message)
253
-
254
- this.emit('recv', this._message)
288
+ this.emit('recv', message)
255
289
 
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)
290
+ if (message.topic === C.TOPIC.CONNECTION) {
291
+ this._handleConnectionResponse(message)
292
+ } else if (message.topic === C.TOPIC.AUTH) {
293
+ this._handleAuthResponse(message)
260
294
  } else {
261
- this._client._$onMessage(this._message)
295
+ this._client._$onMessage(message)
262
296
  }
263
297
  }
264
298
 
@@ -315,7 +349,7 @@ Connection.prototype._getAuthData = function (data) {
315
349
  if (data === undefined) {
316
350
  return null
317
351
  } else {
318
- return messageParser.convertTyped(data, this._client)
352
+ return convertTyped(data, this._client)
319
353
  }
320
354
  }
321
355
 
@@ -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
  }