vrpc 3.0.4 → 3.1.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/CHANGELOG.md +19 -0
- package/browser/vrpc.js +1 -1
- package/package.json +1 -1
- package/vrpc/VrpcAdapter.js +5 -2
- package/vrpc/VrpcAgent.js +43 -10
- package/vrpc/VrpcClient.js +47 -6
- package/vrpc/VrpcNative.js +36 -4
package/package.json
CHANGED
package/vrpc/VrpcAdapter.js
CHANGED
|
@@ -499,7 +499,7 @@ class VrpcAdapter {
|
|
|
499
499
|
}
|
|
500
500
|
|
|
501
501
|
static sanitizeEventListenerReturnValues (ret) {
|
|
502
|
-
return typeof ret === 'object' &&
|
|
502
|
+
return ret && typeof ret === 'object' &&
|
|
503
503
|
ret._events !== undefined &&
|
|
504
504
|
ret._eventsCount !== undefined
|
|
505
505
|
? true
|
|
@@ -606,7 +606,10 @@ class VrpcAdapter {
|
|
|
606
606
|
if (clients.has(clientId)) {
|
|
607
607
|
clients.delete(clientId)
|
|
608
608
|
if (clients.size === 0) {
|
|
609
|
-
VrpcAdapter.getInstance(ik)
|
|
609
|
+
const instance = VrpcAdapter.getInstance(ik)
|
|
610
|
+
if (instance && instance.removeListener) {
|
|
611
|
+
instance.removeListener(event, listener)
|
|
612
|
+
}
|
|
610
613
|
delete VrpcAdapter._listeners[ik][ek]
|
|
611
614
|
}
|
|
612
615
|
}
|
package/vrpc/VrpcAgent.js
CHANGED
|
@@ -101,6 +101,7 @@ class VrpcAgent extends EventEmitter {
|
|
|
101
101
|
* @param {Object} [obj.log=console] Log object (must support debug, info, warn, and error level)
|
|
102
102
|
* @param {String} [obj.bestEffort=false] If true, message will be sent with best effort, i.e. no caching if offline
|
|
103
103
|
* @param {String} [obj.version=''] The (user-defined) version of this agent
|
|
104
|
+
* @param {String} [obj.mqttClientId='<generated()>'] Explicitly set the mqtt client id.
|
|
104
105
|
*
|
|
105
106
|
* @example
|
|
106
107
|
* const agent = new Agent({
|
|
@@ -117,7 +118,8 @@ class VrpcAgent extends EventEmitter {
|
|
|
117
118
|
broker = 'mqtts://vrpc.io:8883',
|
|
118
119
|
log = 'console',
|
|
119
120
|
bestEffort = false,
|
|
120
|
-
version = ''
|
|
121
|
+
version = '',
|
|
122
|
+
mqttClientId = null
|
|
121
123
|
} = {}) {
|
|
122
124
|
super()
|
|
123
125
|
this._validateDomain(domain)
|
|
@@ -130,6 +132,13 @@ class VrpcAgent extends EventEmitter {
|
|
|
130
132
|
this._broker = broker
|
|
131
133
|
this._qos = bestEffort ? 0 : 1
|
|
132
134
|
this._version = version
|
|
135
|
+
this._mqttClientId =
|
|
136
|
+
mqttClientId ||
|
|
137
|
+
`va3${crypto
|
|
138
|
+
.createHash('md5')
|
|
139
|
+
.update(this._domain + this._agent)
|
|
140
|
+
.digest('hex')
|
|
141
|
+
.substring(0, 20)}`
|
|
133
142
|
if (log === 'console') {
|
|
134
143
|
this._log = console
|
|
135
144
|
this._log.debug = () => {}
|
|
@@ -164,18 +173,13 @@ class VrpcAgent extends EventEmitter {
|
|
|
164
173
|
* rejects
|
|
165
174
|
*/
|
|
166
175
|
async serve () {
|
|
167
|
-
const md5 = crypto
|
|
168
|
-
.createHash('md5')
|
|
169
|
-
.update(this._domain + this._agent)
|
|
170
|
-
.digest('hex')
|
|
171
|
-
.substring(0, 20)
|
|
172
176
|
let username = this._username
|
|
173
177
|
let password = this._password
|
|
174
178
|
if (this._token) {
|
|
175
|
-
username = `${this._domain}
|
|
179
|
+
username = `${this._domain}/${this._agent}`
|
|
176
180
|
password = this._token
|
|
177
181
|
} else if (!this._password) {
|
|
178
|
-
username = `${this._domain}
|
|
182
|
+
username = `${this._domain}/${this._agent}`
|
|
179
183
|
password = this._generateToken()
|
|
180
184
|
}
|
|
181
185
|
this._options = {
|
|
@@ -183,7 +187,7 @@ class VrpcAgent extends EventEmitter {
|
|
|
183
187
|
password,
|
|
184
188
|
keepalive: 30,
|
|
185
189
|
connectTimeout: 10 * 1000,
|
|
186
|
-
clientId:
|
|
190
|
+
clientId: this._mqttClientId,
|
|
187
191
|
rejectUnauthorized: false,
|
|
188
192
|
will: {
|
|
189
193
|
topic: `${this._baseTopic}/__agentInfo__`,
|
|
@@ -320,9 +324,38 @@ class VrpcAgent extends EventEmitter {
|
|
|
320
324
|
(err, granted) => {
|
|
321
325
|
if (err) {
|
|
322
326
|
this._log.warn(
|
|
323
|
-
`Could not subscribe to topic '${topic}', because: ${err.message}`
|
|
327
|
+
`Could not subscribe to topic(s) '${topic}', because: ${err.message}`
|
|
324
328
|
)
|
|
325
329
|
} else {
|
|
330
|
+
const topicArray = Array.isArray(topic) ? topic : [topic]
|
|
331
|
+
const erroneousGranted = granted
|
|
332
|
+
.filter(x => x.qos === 128)
|
|
333
|
+
.map(x => x.topic)
|
|
334
|
+
if (erroneousGranted.length > 0) {
|
|
335
|
+
err = new Error(
|
|
336
|
+
`Could not subscribe all ${topicArray.length} topic(s) but got error qos=128 on following ${erroneousGranted.length} topic(s): ${erroneousGranted}`
|
|
337
|
+
)
|
|
338
|
+
err.code = 'SUBSCRIBE_FAILED'
|
|
339
|
+
err.subscribeOptions = options
|
|
340
|
+
this._log.error(err)
|
|
341
|
+
this.emit('error', err)
|
|
342
|
+
}
|
|
343
|
+
const reducedQos = granted.filter(x => x.qos < this._qos)
|
|
344
|
+
if (reducedQos.length > 0) {
|
|
345
|
+
err = new Error(
|
|
346
|
+
`Could not subscribe all ${
|
|
347
|
+
topicArray.length
|
|
348
|
+
} topic(s) at desired qos=${
|
|
349
|
+
this._qos
|
|
350
|
+
} but got reduced qos on following ${
|
|
351
|
+
reducedQos.length
|
|
352
|
+
} topic(s): ${JSON.stringify(reducedQos)}`
|
|
353
|
+
)
|
|
354
|
+
err.code = 'SUBSCRIBE_REDUCED_QOS'
|
|
355
|
+
err.subscribeOptions = options
|
|
356
|
+
this._log.warn(err)
|
|
357
|
+
this.emit('error', err)
|
|
358
|
+
}
|
|
326
359
|
if (granted.length === 0) {
|
|
327
360
|
this._log.debug(`Already subscribed to topic '${topic}'`)
|
|
328
361
|
}
|
package/vrpc/VrpcClient.js
CHANGED
|
@@ -68,6 +68,8 @@ class VrpcClient extends EventEmitter {
|
|
|
68
68
|
* @param {Number} [options.timeout=6000] Maximum time in ms to wait for a RPC answer
|
|
69
69
|
* @param {Object} [options.log=console] Log object (must support debug, info, warn, and error level)
|
|
70
70
|
* @param {Boolean} [options.bestEffort=false] If true, message will be sent with best effort, i.e. no caching if offline
|
|
71
|
+
* @param {String} [options.mqttClientId='<generated()>'] Explicitly sets the mqtt client id
|
|
72
|
+
* @param {String} [options.identity] Explicitly sets a vrpc client identity
|
|
71
73
|
* @example
|
|
72
74
|
* const client = new VrpcClient({
|
|
73
75
|
* domain: 'vrpc',
|
|
@@ -83,7 +85,9 @@ class VrpcClient extends EventEmitter {
|
|
|
83
85
|
broker = 'mqtts://vrpc.io:8883',
|
|
84
86
|
timeout = 6 * 1000,
|
|
85
87
|
log = 'console',
|
|
86
|
-
bestEffort = false
|
|
88
|
+
bestEffort = false,
|
|
89
|
+
mqttClientId = null,
|
|
90
|
+
identity = null
|
|
87
91
|
} = {}) {
|
|
88
92
|
super()
|
|
89
93
|
// domain sanity check
|
|
@@ -99,6 +103,12 @@ class VrpcClient extends EventEmitter {
|
|
|
99
103
|
'The agent must NOT contain any of those characters: "+", "/", "#"'
|
|
100
104
|
)
|
|
101
105
|
}
|
|
106
|
+
// identity sanity check
|
|
107
|
+
if (identity && identity.match(/[+/#$]/)) {
|
|
108
|
+
throw new Error(
|
|
109
|
+
'The identity must NOT contain any of those characters: "+", "/", "#", "$"'
|
|
110
|
+
)
|
|
111
|
+
}
|
|
102
112
|
this._token = token
|
|
103
113
|
this._username = username
|
|
104
114
|
this._password = password
|
|
@@ -106,10 +116,11 @@ class VrpcClient extends EventEmitter {
|
|
|
106
116
|
this._domain = domain
|
|
107
117
|
this._broker = broker
|
|
108
118
|
this._timeout = timeout
|
|
119
|
+
this._identity = identity
|
|
109
120
|
this._qos = this._qos = bestEffort ? 0 : 1
|
|
110
121
|
|
|
111
122
|
this._instance = nanoid(8)
|
|
112
|
-
this._mqttClientId = this._createMqttClientId()
|
|
123
|
+
this._mqttClientId = mqttClientId || this._createMqttClientId()
|
|
113
124
|
this._vrpcClientId = this._createVrpcClientId()
|
|
114
125
|
this._agents = {}
|
|
115
126
|
this._eventEmitter = new EventEmitter()
|
|
@@ -324,7 +335,7 @@ class VrpcClient extends EventEmitter {
|
|
|
324
335
|
f: isIsolated ? '__createIsolated__' : '__createShared__',
|
|
325
336
|
a: [instance, ...args],
|
|
326
337
|
i: `${this._instance}-${this._invokeId++ % Number.MAX_SAFE_INTEGER}`,
|
|
327
|
-
s:
|
|
338
|
+
s: this._vrpcClientId,
|
|
328
339
|
v: VRPC_PROTOCOL_VERSION
|
|
329
340
|
}
|
|
330
341
|
const proxy = await this._getProxy(agent, className, json)
|
|
@@ -371,7 +382,7 @@ class VrpcClient extends EventEmitter {
|
|
|
371
382
|
f: '__delete__',
|
|
372
383
|
a: [instance],
|
|
373
384
|
i: `${this._instance}-${this._invokeId++ % Number.MAX_SAFE_INTEGER}`,
|
|
374
|
-
s:
|
|
385
|
+
s: this._vrpcClientId,
|
|
375
386
|
v: VRPC_PROTOCOL_VERSION
|
|
376
387
|
}
|
|
377
388
|
const topic = `${this._domain}/${agent}/${className}/__static__/__delete__`
|
|
@@ -684,7 +695,8 @@ class VrpcClient extends EventEmitter {
|
|
|
684
695
|
}
|
|
685
696
|
|
|
686
697
|
_createVrpcClientId () {
|
|
687
|
-
|
|
698
|
+
const identity = this._identity || this._instance
|
|
699
|
+
return `${this._domain}/${os.hostname()}/${identity}`
|
|
688
700
|
}
|
|
689
701
|
|
|
690
702
|
_mqttPublish (topic, message, options) {
|
|
@@ -715,7 +727,7 @@ class VrpcClient extends EventEmitter {
|
|
|
715
727
|
(err, granted) => {
|
|
716
728
|
if (err) {
|
|
717
729
|
this._log.warn(
|
|
718
|
-
`Could not subscribe to topic: ${topic} because: ${err.message}`
|
|
730
|
+
`Could not subscribe to topic(s): '${topic}', because: ${err.message}`
|
|
719
731
|
)
|
|
720
732
|
if (err.message === 'client disconnecting') {
|
|
721
733
|
// Workaround for an already reported bug in MQTT.js (#1284)
|
|
@@ -724,6 +736,35 @@ class VrpcClient extends EventEmitter {
|
|
|
724
736
|
this._client.end(true, {}, () => this._client.reconnect())
|
|
725
737
|
}
|
|
726
738
|
} else {
|
|
739
|
+
const topicArray = Array.isArray(topic) ? topic : [topic]
|
|
740
|
+
const erroneousGranted = granted
|
|
741
|
+
.filter(x => x.qos === 128)
|
|
742
|
+
.map(x => x.topic)
|
|
743
|
+
if (erroneousGranted.length > 0) {
|
|
744
|
+
err = new Error(
|
|
745
|
+
`Could not subscribe all ${topicArray.length} topic(s) but got error qos=128 on following ${erroneousGranted.length} topic(s): ${erroneousGranted}`
|
|
746
|
+
)
|
|
747
|
+
err.code = 'SUBSCRIBE_FAILED'
|
|
748
|
+
err.subscribeOptions = options
|
|
749
|
+
this._log.error(err)
|
|
750
|
+
this.emit('error', err)
|
|
751
|
+
}
|
|
752
|
+
const reducedQos = granted.filter(x => x.qos < this._qos)
|
|
753
|
+
if (reducedQos.length > 0) {
|
|
754
|
+
err = new Error(
|
|
755
|
+
`Could not subscribe all ${
|
|
756
|
+
topicArray.length
|
|
757
|
+
} topic(s) at desired qos=${
|
|
758
|
+
this._qos
|
|
759
|
+
} but got reduced qos on following ${
|
|
760
|
+
reducedQos.length
|
|
761
|
+
} topic(s): ${JSON.stringify(reducedQos)}`
|
|
762
|
+
)
|
|
763
|
+
err.code = 'SUBSCRIBE_REDUCED_QOS'
|
|
764
|
+
err.subscribeOptions = options
|
|
765
|
+
this._log.warn(err)
|
|
766
|
+
this.emit('error', err)
|
|
767
|
+
}
|
|
727
768
|
if (granted.length === 0) {
|
|
728
769
|
this._log.debug(`Already subscribed to: ${topic}`)
|
|
729
770
|
}
|
package/vrpc/VrpcNative.js
CHANGED
|
@@ -106,12 +106,28 @@ class VrpcNative {
|
|
|
106
106
|
if (functionName.startsWith('vrpcOn')) {
|
|
107
107
|
const id = `__f__${context}-${functionName}`
|
|
108
108
|
wrapped.push(id)
|
|
109
|
-
eventEmitter.on(id, a =>
|
|
109
|
+
eventEmitter.on(id, a => {
|
|
110
|
+
try {
|
|
111
|
+
x.apply(null, a)
|
|
112
|
+
} catch (err) {
|
|
113
|
+
console.error(
|
|
114
|
+
`[VrpcNative ${context}-${functionName}]: Failed to execute callback, because: ${err.message}`
|
|
115
|
+
)
|
|
116
|
+
}
|
|
117
|
+
})
|
|
110
118
|
} else {
|
|
111
119
|
const id = `__f__${context}-${functionName}-${i}-${invokeId++ %
|
|
112
120
|
Number.MAX_SAFE_INTEGER}`
|
|
113
121
|
wrapped.push(id)
|
|
114
|
-
eventEmitter.once(id, a =>
|
|
122
|
+
eventEmitter.once(id, a => {
|
|
123
|
+
try {
|
|
124
|
+
x.apply(null, a)
|
|
125
|
+
} catch (err) {
|
|
126
|
+
console.error(
|
|
127
|
+
`[VrpcNative ${context}-${functionName}]: Failed to execute callback, because: ${err.message}`
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
})
|
|
115
131
|
}
|
|
116
132
|
} else if (VrpcNative._isEmitter(x)) {
|
|
117
133
|
const { emitter, event } = x
|
|
@@ -273,12 +289,28 @@ class VrpcNative {
|
|
|
273
289
|
if (functionName.startsWith('vrpcOn')) {
|
|
274
290
|
const id = `__f__${className}-${functionName}:${args[0]}`
|
|
275
291
|
wrapped.push(id)
|
|
276
|
-
this._eventEmitter.on(id, a =>
|
|
292
|
+
this._eventEmitter.on(id, a => {
|
|
293
|
+
try {
|
|
294
|
+
x.apply(null, a)
|
|
295
|
+
} catch (err) {
|
|
296
|
+
console.error(
|
|
297
|
+
`[VrpcNative ${className}-${functionName}]: Failed to execute callback, because: ${err.message}`
|
|
298
|
+
)
|
|
299
|
+
}
|
|
300
|
+
})
|
|
277
301
|
} else {
|
|
278
302
|
const id = `__f__${className}-${functionName}-${i}-${invokeId++ %
|
|
279
303
|
Number.MAX_SAFE_INTEGER}`
|
|
280
304
|
wrapped.push(id)
|
|
281
|
-
this._eventEmitter.once(id, a =>
|
|
305
|
+
this._eventEmitter.once(id, a => {
|
|
306
|
+
try {
|
|
307
|
+
x.apply(null, a)
|
|
308
|
+
} catch (err) {
|
|
309
|
+
console.error(
|
|
310
|
+
`[VrpcNative ${className}-${functionName}]: Failed to execute callback, because: ${err.message}`
|
|
311
|
+
)
|
|
312
|
+
}
|
|
313
|
+
})
|
|
282
314
|
}
|
|
283
315
|
} else if (VrpcNative._isEmitter(x)) {
|
|
284
316
|
const { emitter, event } = x
|