@nxtedition/deepstream.io-client-js 24.3.3 → 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 +1 -1
- package/src/event/event-handler.js +2 -2
- package/src/message/connection.js +66 -32
- package/src/message/message-parser.js +1 -50
- package/src/record/record-handler.js +2 -2
- package/src/record/record.js +3 -9
- package/src/rpc/rpc-handler.js +3 -3
- package/src/utils/multicast-listener.js +9 -4
- package/src/utils/unicast-listener.js +6 -4
package/package.json
CHANGED
|
@@ -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
|
|
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,
|
|
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
|
|
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.
|
|
27
|
-
|
|
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(
|
|
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
|
-
'
|
|
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 (
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
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
|
-
|
|
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 (
|
|
249
|
-
this.
|
|
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
|
-
|
|
253
|
-
|
|
254
|
-
this.emit('recv', this._message)
|
|
288
|
+
this.emit('recv', message)
|
|
255
289
|
|
|
256
|
-
if (
|
|
257
|
-
this._handleConnectionResponse(
|
|
258
|
-
} else if (
|
|
259
|
-
this._handleAuthResponse(
|
|
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(
|
|
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
|
|
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
|
-
|
|
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()
|
|
@@ -207,7 +207,7 @@ class RecordHandler {
|
|
|
207
207
|
}
|
|
208
208
|
}
|
|
209
209
|
|
|
210
|
-
|
|
210
|
+
getKey(name) {
|
|
211
211
|
return name.length <= 8 && this._encoder.encode(name).byteLength === 8
|
|
212
212
|
? name
|
|
213
213
|
: this._connection.hasher.h64(name)
|
|
@@ -226,7 +226,7 @@ class RecordHandler {
|
|
|
226
226
|
let record = this._records.get(name)
|
|
227
227
|
|
|
228
228
|
if (!record) {
|
|
229
|
-
record = new Record(this.
|
|
229
|
+
record = new Record(this.getKey(name), name, this)
|
|
230
230
|
this._stats.records += 1
|
|
231
231
|
this._stats.created += 1
|
|
232
232
|
this._records.set(name, record)
|
package/src/record/record.js
CHANGED
|
@@ -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
|
|
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'
|
|
@@ -13,10 +13,7 @@ class Record {
|
|
|
13
13
|
static STATE = C.RECORD_STATE
|
|
14
14
|
|
|
15
15
|
constructor(key, name, handler) {
|
|
16
|
-
const connection = handler._connection
|
|
17
|
-
|
|
18
16
|
this._handler = handler
|
|
19
|
-
|
|
20
17
|
this._name = name
|
|
21
18
|
this._key = key
|
|
22
19
|
this._version = ''
|
|
@@ -28,10 +25,7 @@ class Record {
|
|
|
28
25
|
|
|
29
26
|
/** @type Map? */ this._updating = null
|
|
30
27
|
/** @type Array? */ this._patching = null
|
|
31
|
-
this._subscribed =
|
|
32
|
-
this._name,
|
|
33
|
-
this._key,
|
|
34
|
-
])
|
|
28
|
+
this._subscribed = false
|
|
35
29
|
}
|
|
36
30
|
|
|
37
31
|
/** @type {string} */
|
|
@@ -476,7 +470,7 @@ class Record {
|
|
|
476
470
|
const prevState = this._state
|
|
477
471
|
|
|
478
472
|
this._state =
|
|
479
|
-
hasProvider &&
|
|
473
|
+
hasProvider && convertTyped(hasProvider, this._handler._client)
|
|
480
474
|
? C.RECORD_STATE.PROVIDER
|
|
481
475
|
: this._version.charAt(0) === 'I'
|
|
482
476
|
? C.RECORD_STATE.STALE
|
package/src/rpc/rpc-handler.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as C from '../constants/constants.js'
|
|
2
2
|
import RpcResponse from './rpc-response.js'
|
|
3
|
-
import
|
|
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(
|
|
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,
|
|
159
|
+
rpc.callback(null, convertTyped(data, this._client))
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
162
|
}
|
|
@@ -56,6 +56,7 @@ class Listener {
|
|
|
56
56
|
// TODO (refactor): Move to class
|
|
57
57
|
const provider = {
|
|
58
58
|
name,
|
|
59
|
+
key: this._handler.getKey(name),
|
|
59
60
|
value$: null,
|
|
60
61
|
sending: false,
|
|
61
62
|
accepted: false,
|
|
@@ -68,7 +69,7 @@ class Listener {
|
|
|
68
69
|
if (this.connected && provider.accepted) {
|
|
69
70
|
this._connection.sendMsg(this._topic, C.ACTIONS.LISTEN_REJECT, [
|
|
70
71
|
this._pattern,
|
|
71
|
-
provider.
|
|
72
|
+
provider.key,
|
|
72
73
|
])
|
|
73
74
|
}
|
|
74
75
|
|
|
@@ -101,7 +102,7 @@ class Listener {
|
|
|
101
102
|
this._connection.sendMsg(
|
|
102
103
|
this._topic,
|
|
103
104
|
accepted ? C.ACTIONS.LISTEN_ACCEPT : C.ACTIONS.LISTEN_REJECT,
|
|
104
|
-
[this._pattern, provider.
|
|
105
|
+
[this._pattern, provider.key]
|
|
105
106
|
)
|
|
106
107
|
|
|
107
108
|
provider.version = null
|
|
@@ -157,7 +158,7 @@ class Listener {
|
|
|
157
158
|
if (provider.version !== version) {
|
|
158
159
|
provider.version = version
|
|
159
160
|
this._connection.sendMsg(C.TOPIC.RECORD, C.ACTIONS.UPDATE, [
|
|
160
|
-
provider.
|
|
161
|
+
provider.key,
|
|
161
162
|
version,
|
|
162
163
|
body,
|
|
163
164
|
])
|
|
@@ -218,7 +219,11 @@ class Listener {
|
|
|
218
219
|
}
|
|
219
220
|
|
|
220
221
|
_error(name, err) {
|
|
221
|
-
this._client._$onError(this._topic, C.EVENT.LISTENER_ERROR, err, [
|
|
222
|
+
this._client._$onError(this._topic, C.EVENT.LISTENER_ERROR, err, [
|
|
223
|
+
this._pattern,
|
|
224
|
+
name,
|
|
225
|
+
this._handler.getKey(name),
|
|
226
|
+
])
|
|
222
227
|
}
|
|
223
228
|
|
|
224
229
|
_reset() {
|
|
@@ -68,27 +68,29 @@ class Listener {
|
|
|
68
68
|
value$ = rxjs.throwError(() => err)
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
const key = this._handler.getKey(name)
|
|
72
|
+
|
|
71
73
|
if (value$) {
|
|
72
74
|
const subscription = value$.pipe(PIPE).subscribe({
|
|
73
75
|
next: (data) => {
|
|
74
76
|
if (data == null) {
|
|
75
|
-
this._connection.sendMsg(this._topic, C.ACTIONS.LISTEN_REJECT, [this._pattern,
|
|
77
|
+
this._connection.sendMsg(this._topic, C.ACTIONS.LISTEN_REJECT, [this._pattern, key])
|
|
76
78
|
this._subscriptions.delete(name)
|
|
77
79
|
subscription.unsubscribe()
|
|
78
80
|
} else {
|
|
79
81
|
const version = `INF-${this._connection.hasher.h64ToString(data)}`
|
|
80
|
-
this._connection.sendMsg(this._topic, C.ACTIONS.UPDATE, [
|
|
82
|
+
this._connection.sendMsg(this._topic, C.ACTIONS.UPDATE, [key, version, data])
|
|
81
83
|
}
|
|
82
84
|
},
|
|
83
85
|
error: (err) => {
|
|
84
86
|
this._error(name, err)
|
|
85
|
-
this._connection.sendMsg(this._topic, C.ACTIONS.LISTEN_REJECT, [this._pattern,
|
|
87
|
+
this._connection.sendMsg(this._topic, C.ACTIONS.LISTEN_REJECT, [this._pattern, key])
|
|
86
88
|
this._subscriptions.delete(name)
|
|
87
89
|
},
|
|
88
90
|
})
|
|
89
91
|
this._subscriptions.set(name, subscription)
|
|
90
92
|
} else {
|
|
91
|
-
this._connection.sendMsg(this._topic, C.ACTIONS.LISTEN_REJECT, [this._pattern,
|
|
93
|
+
this._connection.sendMsg(this._topic, C.ACTIONS.LISTEN_REJECT, [this._pattern, key])
|
|
92
94
|
}
|
|
93
95
|
} else if (message.action === C.ACTIONS.LISTEN_REJECT) {
|
|
94
96
|
const subscription = this._subscriptions.get(name)
|