vrpc 3.0.2 → 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 +67 -26
- package/browser/vrpc.js +1 -1
- package/package.json +1 -1
- package/vrpc/VrpcAdapter.js +151 -95
- package/vrpc/VrpcAgent.js +72 -51
- package/vrpc/VrpcClient.js +73 -13
- package/vrpc/VrpcNative.js +36 -4
package/package.json
CHANGED
package/vrpc/VrpcAdapter.js
CHANGED
|
@@ -390,7 +390,7 @@ class VrpcAdapter {
|
|
|
390
390
|
}
|
|
391
391
|
|
|
392
392
|
static _call (json) {
|
|
393
|
-
|
|
393
|
+
this._mustTrackClient = false // reset client tracking flag
|
|
394
394
|
switch (json.f) {
|
|
395
395
|
case '__createIsolated__':
|
|
396
396
|
VrpcAdapter._handleCreateIsolated(json)
|
|
@@ -408,10 +408,9 @@ class VrpcAdapter {
|
|
|
408
408
|
// this call may have the side-effect of taking a listener on board
|
|
409
409
|
VrpcAdapter._handleCall(json)
|
|
410
410
|
}
|
|
411
|
-
const after = Object.keys(VrpcAdapter._listeners).length
|
|
412
411
|
// if we took a listener on board we must tell our caller such that
|
|
413
412
|
// things can be cleaned up later.
|
|
414
|
-
return
|
|
413
|
+
return this._mustTrackClient
|
|
415
414
|
}
|
|
416
415
|
|
|
417
416
|
static _handleCreateIsolated (json) {
|
|
@@ -500,7 +499,7 @@ class VrpcAdapter {
|
|
|
500
499
|
}
|
|
501
500
|
|
|
502
501
|
static sanitizeEventListenerReturnValues (ret) {
|
|
503
|
-
return typeof ret === 'object' &&
|
|
502
|
+
return ret && typeof ret === 'object' &&
|
|
504
503
|
ret._events !== undefined &&
|
|
505
504
|
ret._eventsCount !== undefined
|
|
506
505
|
? true
|
|
@@ -593,13 +592,7 @@ class VrpcAdapter {
|
|
|
593
592
|
if (VrpcAdapter._isFunction(entry.removeAllListeners)) {
|
|
594
593
|
entry.removeAllListeners()
|
|
595
594
|
}
|
|
596
|
-
|
|
597
|
-
VrpcAdapter._listeners
|
|
598
|
-
)) {
|
|
599
|
-
if (instance === instanceId) {
|
|
600
|
-
VrpcAdapter._listeners[key] = { clients }
|
|
601
|
-
}
|
|
602
|
-
}
|
|
595
|
+
delete VrpcAdapter._listeners[instanceId]
|
|
603
596
|
VrpcAdapter._instances.delete(instanceId)
|
|
604
597
|
return true
|
|
605
598
|
}
|
|
@@ -607,18 +600,21 @@ class VrpcAdapter {
|
|
|
607
600
|
}
|
|
608
601
|
|
|
609
602
|
static _unregisterClient (clientId) {
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
VrpcAdapter.getInstance(
|
|
617
|
-
|
|
603
|
+
Object.entries(VrpcAdapter._listeners).forEach(([ik, iv]) => {
|
|
604
|
+
Object.entries(iv).forEach(([ek, ev]) => {
|
|
605
|
+
const { clients, listener, event } = ev
|
|
606
|
+
if (clients.has(clientId)) {
|
|
607
|
+
clients.delete(clientId)
|
|
608
|
+
if (clients.size === 0) {
|
|
609
|
+
const instance = VrpcAdapter.getInstance(ik)
|
|
610
|
+
if (instance && instance.removeListener) {
|
|
611
|
+
instance.removeListener(event, listener)
|
|
612
|
+
}
|
|
613
|
+
delete VrpcAdapter._listeners[ik][ek]
|
|
614
|
+
}
|
|
618
615
|
}
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
}
|
|
616
|
+
})
|
|
617
|
+
})
|
|
622
618
|
}
|
|
623
619
|
|
|
624
620
|
static _validate (schema, params) {
|
|
@@ -630,102 +626,162 @@ class VrpcAdapter {
|
|
|
630
626
|
}
|
|
631
627
|
|
|
632
628
|
static _unwrapArguments (json, instanceId) {
|
|
633
|
-
const
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
args = args.slice(1)
|
|
642
|
-
}
|
|
643
|
-
const unwrapped = instanceId ? [func] : []
|
|
629
|
+
const clientId = json.s
|
|
630
|
+
// if we came from a "callAll" we will have an instanceId defined
|
|
631
|
+
// things are different for callAll as we have to dispatch the instanceIds
|
|
632
|
+
const isCallAll = instanceId !== undefined
|
|
633
|
+
const context = isCallAll ? instanceId : json.c
|
|
634
|
+
const args = isCallAll ? json.a.slice(1) : json.a
|
|
635
|
+
const func = isCallAll ? json.a[0] : json.f
|
|
636
|
+
const unwrapped = isCallAll ? [func] : []
|
|
644
637
|
for (const arg of args) {
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
638
|
+
if (typeof arg === 'string') {
|
|
639
|
+
if (arg.startsWith('__f__')) {
|
|
640
|
+
// function callback
|
|
641
|
+
unwrapped.push(
|
|
642
|
+
this._generateCallback({
|
|
643
|
+
clientId,
|
|
644
|
+
isCallAll,
|
|
645
|
+
instanceId: context,
|
|
646
|
+
eventId: arg
|
|
647
|
+
})
|
|
648
|
+
)
|
|
649
|
+
} else if (arg.startsWith('__e__')) {
|
|
650
|
+
// event registration
|
|
651
|
+
if (func === 'on' || func === 'addListener') {
|
|
652
|
+
this._mustTrackClient = true
|
|
653
|
+
const listener = VrpcAdapter._registerListener({
|
|
654
|
+
clientId,
|
|
655
|
+
isCallAll,
|
|
656
|
+
instanceId: context,
|
|
657
|
+
eventId: arg,
|
|
658
|
+
event: args[0]
|
|
659
|
+
})
|
|
660
|
+
if (
|
|
661
|
+
VrpcAdapter.getInstance(context)
|
|
662
|
+
.listeners(arg)
|
|
663
|
+
.includes(listener)
|
|
664
|
+
) {
|
|
665
|
+
return null // skip call as listener is already registered
|
|
666
|
+
}
|
|
667
|
+
unwrapped.push(listener)
|
|
668
|
+
// event un-registration
|
|
669
|
+
} else if (func === 'off' || func === 'removeListener') {
|
|
670
|
+
const listener = VrpcAdapter._unregisterListener({
|
|
671
|
+
clientId,
|
|
672
|
+
instanceId: context,
|
|
673
|
+
eventId: arg
|
|
674
|
+
})
|
|
675
|
+
if (!listener) {
|
|
676
|
+
return null // skip call as others are still interested
|
|
677
|
+
}
|
|
678
|
+
unwrapped.push(listener)
|
|
679
|
+
} else {
|
|
680
|
+
this._mustTrackClient = true
|
|
681
|
+
const listener = VrpcAdapter._registerListener({
|
|
682
|
+
clientId,
|
|
683
|
+
isCallAll,
|
|
684
|
+
instanceId: context,
|
|
685
|
+
eventId: arg,
|
|
686
|
+
event: null
|
|
687
|
+
})
|
|
688
|
+
unwrapped.push(listener)
|
|
659
689
|
}
|
|
660
690
|
} else {
|
|
661
|
-
|
|
662
|
-
}
|
|
663
|
-
// see whether the requested listener is an EventEmitter registration
|
|
664
|
-
if (func === 'on' || func === 'addListener') {
|
|
665
|
-
// if this event is already registered on the given instance
|
|
666
|
-
// avoid a second registration
|
|
667
|
-
if (
|
|
668
|
-
VrpcAdapter._listeners[arg].event &&
|
|
669
|
-
VrpcAdapter._listeners[arg].instances.has(context)
|
|
670
|
-
) {
|
|
671
|
-
return null // means that this call won't be forwarded
|
|
672
|
-
}
|
|
673
|
-
VrpcAdapter._listeners[arg].event = args[0]
|
|
674
|
-
VrpcAdapter._listeners[arg].instances.add(context)
|
|
675
|
-
}
|
|
676
|
-
if (func === 'off' || func === 'removeListener') {
|
|
677
|
-
const {
|
|
678
|
-
clients,
|
|
679
|
-
instances,
|
|
680
|
-
listener,
|
|
681
|
-
event
|
|
682
|
-
} = VrpcAdapter._listeners[arg]
|
|
683
|
-
clients.delete(sender)
|
|
684
|
-
instances.delete(context)
|
|
685
|
-
if (clients.size === 0) {
|
|
686
|
-
delete VrpcAdapter._listeners[arg]
|
|
687
|
-
VrpcAdapter.getInstance(context).off(event, listener)
|
|
688
|
-
}
|
|
689
|
-
return null // means that this call won't be forwarded
|
|
691
|
+
unwrapped.push(arg)
|
|
690
692
|
}
|
|
691
693
|
} else {
|
|
692
|
-
//
|
|
694
|
+
// regular argument
|
|
693
695
|
unwrapped.push(arg)
|
|
694
696
|
}
|
|
695
697
|
}
|
|
696
698
|
return unwrapped
|
|
697
699
|
}
|
|
698
700
|
|
|
699
|
-
static
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
701
|
+
static _generateCallback ({ eventId, clientId, instanceId, isCallAll }) {
|
|
702
|
+
return (...innerArgs) => {
|
|
703
|
+
// "callAll" event notifications expect the instanceId as first argument
|
|
704
|
+
const a = isCallAll ? [instanceId, ...innerArgs] : [...innerArgs]
|
|
705
|
+
VrpcAdapter._callback({ a, s: clientId, i: eventId })
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
static _registerListener ({
|
|
710
|
+
eventId,
|
|
711
|
+
clientId,
|
|
712
|
+
instanceId,
|
|
713
|
+
event,
|
|
714
|
+
isCallAll
|
|
715
|
+
}) {
|
|
716
|
+
if (!VrpcAdapter._listeners[instanceId]) {
|
|
717
|
+
VrpcAdapter._listeners[instanceId] = {
|
|
718
|
+
[eventId]: {
|
|
719
|
+
event,
|
|
720
|
+
clients: new Set([clientId]),
|
|
721
|
+
listener: VrpcAdapter._generateListener({
|
|
722
|
+
eventId,
|
|
723
|
+
instanceId,
|
|
724
|
+
isCallAll
|
|
725
|
+
})
|
|
706
726
|
}
|
|
707
727
|
}
|
|
728
|
+
} else if (!VrpcAdapter._listeners[instanceId][eventId]) {
|
|
729
|
+
VrpcAdapter._listeners[instanceId][eventId] = {
|
|
730
|
+
event,
|
|
731
|
+
clients: new Set([clientId]),
|
|
732
|
+
listener: VrpcAdapter._generateListener({
|
|
733
|
+
eventId,
|
|
734
|
+
instanceId,
|
|
735
|
+
isCallAll
|
|
736
|
+
})
|
|
737
|
+
}
|
|
738
|
+
} else {
|
|
739
|
+
VrpcAdapter._listeners[instanceId][eventId].clients.add(clientId)
|
|
708
740
|
}
|
|
741
|
+
return VrpcAdapter._listeners[instanceId][eventId].listener
|
|
709
742
|
}
|
|
710
743
|
|
|
711
|
-
static
|
|
744
|
+
static _generateListener ({ eventId, instanceId, isCallAll }) {
|
|
712
745
|
return (...innerArgs) => {
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
VrpcAdapter._callback({ a, s: sender, i: id })
|
|
746
|
+
const a = isCallAll ? [instanceId, ...innerArgs] : [...innerArgs]
|
|
747
|
+
VrpcAdapter._callback({ a, i: eventId })
|
|
716
748
|
}
|
|
717
749
|
}
|
|
718
750
|
|
|
719
|
-
static
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
const
|
|
725
|
-
|
|
751
|
+
static _unregisterListener ({ eventId, clientId, instanceId }) {
|
|
752
|
+
if (
|
|
753
|
+
VrpcAdapter._listeners[instanceId] &&
|
|
754
|
+
VrpcAdapter._listeners[instanceId][eventId]
|
|
755
|
+
) {
|
|
756
|
+
const { listener, clients } = VrpcAdapter._listeners[instanceId][eventId]
|
|
757
|
+
clients.delete(clientId)
|
|
758
|
+
if (clients.size === 0) {
|
|
759
|
+
delete VrpcAdapter._listeners[instanceId][eventId]
|
|
760
|
+
if (Object.keys(VrpcAdapter._listeners[instanceId]).length === 0) {
|
|
761
|
+
delete VrpcAdapter._listeners[instanceId]
|
|
762
|
+
}
|
|
763
|
+
return listener
|
|
764
|
+
}
|
|
726
765
|
}
|
|
727
766
|
}
|
|
728
767
|
|
|
768
|
+
static _removeAllListeners (event, clientId, instanceId) {
|
|
769
|
+
const eventIds = VrpcAdapter._listeners[instanceId]
|
|
770
|
+
if (!eventIds) return
|
|
771
|
+
Object.entries(eventIds).forEach(([ek, ev]) => {
|
|
772
|
+
if (ev.event === event && ev.clients.has(clientId)) {
|
|
773
|
+
ev.clients.delete(clientId)
|
|
774
|
+
if (ev.clients.size === 0) {
|
|
775
|
+
VrpcAdapter.getInstance(instanceId).removeListener(
|
|
776
|
+
ev.event,
|
|
777
|
+
ev.listener
|
|
778
|
+
)
|
|
779
|
+
delete VrpcAdapter._listeners[instanceId][ek]
|
|
780
|
+
}
|
|
781
|
+
}
|
|
782
|
+
})
|
|
783
|
+
}
|
|
784
|
+
|
|
729
785
|
static _handlePromise (json, promise) {
|
|
730
786
|
try {
|
|
731
787
|
const cid = VrpcAdapter._correlationId++ % Number.MAX_SAFE_INTEGER
|
package/vrpc/VrpcAgent.js
CHANGED
|
@@ -92,15 +92,16 @@ class VrpcAgent extends EventEmitter {
|
|
|
92
92
|
*
|
|
93
93
|
* @constructor
|
|
94
94
|
* @param {Object} obj
|
|
95
|
-
* @param {String} [obj.username] MQTT username
|
|
95
|
+
* @param {String} [obj.username] MQTT username
|
|
96
96
|
* @param {String} [obj.password] MQTT password (if no token is provided)
|
|
97
|
-
* @param {String} [obj.token] Access token
|
|
97
|
+
* @param {String} [obj.token] Access token
|
|
98
98
|
* @param {String} [obj.domain='vrpc'] The domain under which the agent-provided code is reachable
|
|
99
99
|
* @param {String} [obj.agent='<user>-<pathId>@<hostname>-<platform>-js'] This agent's name
|
|
100
100
|
* @param {String} [obj.broker='mqtts://vrpc.io:8883'] Broker url in form: `<scheme>://<host>:<port>`
|
|
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,7 +132,13 @@ class VrpcAgent extends EventEmitter {
|
|
|
130
132
|
this._broker = broker
|
|
131
133
|
this._qos = bestEffort ? 0 : 1
|
|
132
134
|
this._version = version
|
|
133
|
-
this.
|
|
135
|
+
this._mqttClientId =
|
|
136
|
+
mqttClientId ||
|
|
137
|
+
`va3${crypto
|
|
138
|
+
.createHash('md5')
|
|
139
|
+
.update(this._domain + this._agent)
|
|
140
|
+
.digest('hex')
|
|
141
|
+
.substring(0, 20)}`
|
|
134
142
|
if (log === 'console') {
|
|
135
143
|
this._log = console
|
|
136
144
|
this._log.debug = () => {}
|
|
@@ -165,22 +173,21 @@ class VrpcAgent extends EventEmitter {
|
|
|
165
173
|
* rejects
|
|
166
174
|
*/
|
|
167
175
|
async serve () {
|
|
168
|
-
const md5 = crypto
|
|
169
|
-
.createHash('md5')
|
|
170
|
-
.update(this._domain + this._agent)
|
|
171
|
-
.digest('hex')
|
|
172
|
-
.substr(0, 20)
|
|
173
176
|
let username = this._username
|
|
174
177
|
let password = this._password
|
|
175
178
|
if (this._token) {
|
|
179
|
+
username = `${this._domain}/${this._agent}`
|
|
176
180
|
password = this._token
|
|
181
|
+
} else if (!this._password) {
|
|
182
|
+
username = `${this._domain}/${this._agent}`
|
|
183
|
+
password = this._generateToken()
|
|
177
184
|
}
|
|
178
185
|
this._options = {
|
|
179
186
|
username,
|
|
180
187
|
password,
|
|
181
188
|
keepalive: 30,
|
|
182
189
|
connectTimeout: 10 * 1000,
|
|
183
|
-
clientId:
|
|
190
|
+
clientId: this._mqttClientId,
|
|
184
191
|
rejectUnauthorized: false,
|
|
185
192
|
will: {
|
|
186
193
|
topic: `${this._baseTopic}/__agentInfo__`,
|
|
@@ -193,12 +200,7 @@ class VrpcAgent extends EventEmitter {
|
|
|
193
200
|
this._log.info(`Agent : ${this._agent}`)
|
|
194
201
|
this._log.info(`Broker : ${this._broker}`)
|
|
195
202
|
this._log.info('Connecting to MQTT server...')
|
|
196
|
-
|
|
197
|
-
if (wasEnded) return
|
|
198
|
-
this._client = mqtt.connect(this._broker, {
|
|
199
|
-
...this._options,
|
|
200
|
-
clean: false
|
|
201
|
-
})
|
|
203
|
+
this._client = mqtt.connect(this._broker, this._options)
|
|
202
204
|
this._client.on('connect', this._handleConnect.bind(this))
|
|
203
205
|
this._client.on('reconnect', this._handleReconnect.bind(this))
|
|
204
206
|
this._client.on('error', this._handleError.bind(this))
|
|
@@ -237,7 +239,6 @@ class VrpcAgent extends EventEmitter {
|
|
|
237
239
|
}
|
|
238
240
|
}
|
|
239
241
|
await new Promise(resolve => this._client.end(false, {}, resolve))
|
|
240
|
-
await this._clearPersistedSession()
|
|
241
242
|
} catch (err) {
|
|
242
243
|
this._log.error(err, `Problem during disconnecting agent: ${err.message}`)
|
|
243
244
|
}
|
|
@@ -249,10 +250,31 @@ class VrpcAgent extends EventEmitter {
|
|
|
249
250
|
.createHash('md5')
|
|
250
251
|
.update(path.resolve())
|
|
251
252
|
.digest('hex')
|
|
252
|
-
.
|
|
253
|
+
.substring(0, 4)
|
|
253
254
|
return `${username}-${pathId}@${os.hostname()}-${os.platform()}-js`
|
|
254
255
|
}
|
|
255
256
|
|
|
257
|
+
_generateToken () {
|
|
258
|
+
const uid =
|
|
259
|
+
this._domain +
|
|
260
|
+
this._agent +
|
|
261
|
+
os.userInfo().username +
|
|
262
|
+
path.resolve() +
|
|
263
|
+
os.arch() +
|
|
264
|
+
os.homedir() +
|
|
265
|
+
os.hostname() +
|
|
266
|
+
os.platform() +
|
|
267
|
+
os.release() +
|
|
268
|
+
os.totalmem() +
|
|
269
|
+
os.type() +
|
|
270
|
+
JSON.stringify(os.networkInterfaces()) +
|
|
271
|
+
JSON.stringify(os.cpus().map(({ model }) => model))
|
|
272
|
+
return crypto
|
|
273
|
+
.createHash('md5')
|
|
274
|
+
.update(uid)
|
|
275
|
+
.digest('hex')
|
|
276
|
+
}
|
|
277
|
+
|
|
256
278
|
_validateDomain (domain) {
|
|
257
279
|
if (!domain) throw new Error('The domain must be specified')
|
|
258
280
|
if (domain.match(/[+/#*]/)) {
|
|
@@ -280,27 +302,6 @@ class VrpcAgent extends EventEmitter {
|
|
|
280
302
|
})
|
|
281
303
|
}
|
|
282
304
|
|
|
283
|
-
/**
|
|
284
|
-
* @return {Boolean} true if `agent.end()` was explicitly called
|
|
285
|
-
*/
|
|
286
|
-
async _clearPersistedSession () {
|
|
287
|
-
// Clear potentially existing persisted sessions
|
|
288
|
-
const client = mqtt.connect(this._broker, { ...this._options, clean: true })
|
|
289
|
-
client.on('error', err => this.emit('error', err))
|
|
290
|
-
client.on('offline', () => this.emit('offline'))
|
|
291
|
-
client.on('reconnect', () => this.emit('reconnect'))
|
|
292
|
-
return new Promise(resolve => {
|
|
293
|
-
client.on('connect', () => {
|
|
294
|
-
client.end(false, {}, () => resolve(false))
|
|
295
|
-
})
|
|
296
|
-
// Will be triggered if the user called 'agent.end()'
|
|
297
|
-
this.once('end', () => {
|
|
298
|
-
client.end()
|
|
299
|
-
resolve(true)
|
|
300
|
-
})
|
|
301
|
-
})
|
|
302
|
-
}
|
|
303
|
-
|
|
304
305
|
_mqttPublish (topic, message, options) {
|
|
305
306
|
this._client.publish(
|
|
306
307
|
topic,
|
|
@@ -323,9 +324,38 @@ class VrpcAgent extends EventEmitter {
|
|
|
323
324
|
(err, granted) => {
|
|
324
325
|
if (err) {
|
|
325
326
|
this._log.warn(
|
|
326
|
-
`Could not subscribe to topic '${topic}', because: ${err.message}`
|
|
327
|
+
`Could not subscribe to topic(s) '${topic}', because: ${err.message}`
|
|
327
328
|
)
|
|
328
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
|
+
}
|
|
329
359
|
if (granted.length === 0) {
|
|
330
360
|
this._log.debug(`Already subscribed to topic '${topic}'`)
|
|
331
361
|
}
|
|
@@ -370,6 +400,8 @@ class VrpcAgent extends EventEmitter {
|
|
|
370
400
|
resolve()
|
|
371
401
|
} else {
|
|
372
402
|
this._client.once('connect', resolve)
|
|
403
|
+
// Will be triggered if the user called 'agent.end()'
|
|
404
|
+
this.once('end', resolve)
|
|
373
405
|
}
|
|
374
406
|
})
|
|
375
407
|
}
|
|
@@ -408,16 +440,6 @@ class VrpcAgent extends EventEmitter {
|
|
|
408
440
|
|
|
409
441
|
_handleConnect () {
|
|
410
442
|
this._log.info('[OK]')
|
|
411
|
-
if (this._isReconnect) {
|
|
412
|
-
this._publishAgentInfoMessage()
|
|
413
|
-
const classes = this._getClasses()
|
|
414
|
-
classes.forEach(className => {
|
|
415
|
-
this._publishClassInfoMessage(className)
|
|
416
|
-
})
|
|
417
|
-
this.emit('connect')
|
|
418
|
-
this._isReconnect = false
|
|
419
|
-
return
|
|
420
|
-
}
|
|
421
443
|
try {
|
|
422
444
|
const topics = this._generateTopics()
|
|
423
445
|
if (topics.length > 0) this._mqttSubscribe(topics)
|
|
@@ -665,7 +687,6 @@ class VrpcAgent extends EventEmitter {
|
|
|
665
687
|
}
|
|
666
688
|
|
|
667
689
|
_handleReconnect () {
|
|
668
|
-
this._isReconnect = true
|
|
669
690
|
this._log.warn(`Reconnecting to ${this._broker}`)
|
|
670
691
|
this.emit('reconnect')
|
|
671
692
|
}
|