vrpc 3.0.1 → 3.0.4
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 +58 -25
- package/browser/vrpc.js +1 -1
- package/package.json +1 -1
- package/vrpc/VrpcAdapter.js +147 -92
- package/vrpc/VrpcAgent.js +36 -49
- package/vrpc/VrpcClient.js +27 -9
- package/vrpc/vrpc-agent-js +1 -1
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) {
|
|
@@ -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,16 +600,18 @@ class VrpcAdapter {
|
|
|
607
600
|
}
|
|
608
601
|
|
|
609
602
|
static _unregisterClient (clientId) {
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
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
|
+
VrpcAdapter.getInstance(ik).removeListener(event, listener)
|
|
610
|
+
delete VrpcAdapter._listeners[ik][ek]
|
|
611
|
+
}
|
|
616
612
|
}
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
}
|
|
613
|
+
})
|
|
614
|
+
})
|
|
620
615
|
}
|
|
621
616
|
|
|
622
617
|
static _validate (schema, params) {
|
|
@@ -628,102 +623,162 @@ class VrpcAdapter {
|
|
|
628
623
|
}
|
|
629
624
|
|
|
630
625
|
static _unwrapArguments (json, instanceId) {
|
|
631
|
-
const
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
args = args.slice(1)
|
|
640
|
-
}
|
|
641
|
-
const unwrapped = instanceId ? [func] : []
|
|
626
|
+
const clientId = json.s
|
|
627
|
+
// if we came from a "callAll" we will have an instanceId defined
|
|
628
|
+
// things are different for callAll as we have to dispatch the instanceIds
|
|
629
|
+
const isCallAll = instanceId !== undefined
|
|
630
|
+
const context = isCallAll ? instanceId : json.c
|
|
631
|
+
const args = isCallAll ? json.a.slice(1) : json.a
|
|
632
|
+
const func = isCallAll ? json.a[0] : json.f
|
|
633
|
+
const unwrapped = isCallAll ? [func] : []
|
|
642
634
|
for (const arg of args) {
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
635
|
+
if (typeof arg === 'string') {
|
|
636
|
+
if (arg.startsWith('__f__')) {
|
|
637
|
+
// function callback
|
|
638
|
+
unwrapped.push(
|
|
639
|
+
this._generateCallback({
|
|
640
|
+
clientId,
|
|
641
|
+
isCallAll,
|
|
642
|
+
instanceId: context,
|
|
643
|
+
eventId: arg
|
|
644
|
+
})
|
|
645
|
+
)
|
|
646
|
+
} else if (arg.startsWith('__e__')) {
|
|
647
|
+
// event registration
|
|
648
|
+
if (func === 'on' || func === 'addListener') {
|
|
649
|
+
this._mustTrackClient = true
|
|
650
|
+
const listener = VrpcAdapter._registerListener({
|
|
651
|
+
clientId,
|
|
652
|
+
isCallAll,
|
|
653
|
+
instanceId: context,
|
|
654
|
+
eventId: arg,
|
|
655
|
+
event: args[0]
|
|
656
|
+
})
|
|
657
|
+
if (
|
|
658
|
+
VrpcAdapter.getInstance(context)
|
|
659
|
+
.listeners(arg)
|
|
660
|
+
.includes(listener)
|
|
661
|
+
) {
|
|
662
|
+
return null // skip call as listener is already registered
|
|
663
|
+
}
|
|
664
|
+
unwrapped.push(listener)
|
|
665
|
+
// event un-registration
|
|
666
|
+
} else if (func === 'off' || func === 'removeListener') {
|
|
667
|
+
const listener = VrpcAdapter._unregisterListener({
|
|
668
|
+
clientId,
|
|
669
|
+
instanceId: context,
|
|
670
|
+
eventId: arg
|
|
671
|
+
})
|
|
672
|
+
if (!listener) {
|
|
673
|
+
return null // skip call as others are still interested
|
|
674
|
+
}
|
|
675
|
+
unwrapped.push(listener)
|
|
676
|
+
} else {
|
|
677
|
+
this._mustTrackClient = true
|
|
678
|
+
const listener = VrpcAdapter._registerListener({
|
|
679
|
+
clientId,
|
|
680
|
+
isCallAll,
|
|
681
|
+
instanceId: context,
|
|
682
|
+
eventId: arg,
|
|
683
|
+
event: null
|
|
684
|
+
})
|
|
685
|
+
unwrapped.push(listener)
|
|
657
686
|
}
|
|
658
687
|
} else {
|
|
659
|
-
|
|
660
|
-
}
|
|
661
|
-
// see whether the requested listener is an EventEmitter registration
|
|
662
|
-
if (func === 'on' || func === 'addListener') {
|
|
663
|
-
// if this event is already registered on the given instance
|
|
664
|
-
// avoid a second registration
|
|
665
|
-
if (
|
|
666
|
-
VrpcAdapter._listeners[arg].event &&
|
|
667
|
-
VrpcAdapter._listeners[arg].instances.has(context)
|
|
668
|
-
) {
|
|
669
|
-
return null // means that this call won't be forwarded
|
|
670
|
-
}
|
|
671
|
-
VrpcAdapter._listeners[arg].event = args[0]
|
|
672
|
-
VrpcAdapter._listeners[arg].instances.add(context)
|
|
673
|
-
}
|
|
674
|
-
if (func === 'off' || func === 'removeListener') {
|
|
675
|
-
const {
|
|
676
|
-
clients,
|
|
677
|
-
instances,
|
|
678
|
-
listener,
|
|
679
|
-
event
|
|
680
|
-
} = VrpcAdapter._listeners[arg]
|
|
681
|
-
clients.delete(sender)
|
|
682
|
-
instances.delete(context)
|
|
683
|
-
if (clients.size === 0) {
|
|
684
|
-
delete VrpcAdapter._listeners[arg]
|
|
685
|
-
VrpcAdapter.getInstance(context).off(event, listener)
|
|
686
|
-
}
|
|
687
|
-
return null // means that this call won't be forwarded
|
|
688
|
+
unwrapped.push(arg)
|
|
688
689
|
}
|
|
689
690
|
} else {
|
|
690
|
-
//
|
|
691
|
+
// regular argument
|
|
691
692
|
unwrapped.push(arg)
|
|
692
693
|
}
|
|
693
694
|
}
|
|
694
695
|
return unwrapped
|
|
695
696
|
}
|
|
696
697
|
|
|
697
|
-
static
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
698
|
+
static _generateCallback ({ eventId, clientId, instanceId, isCallAll }) {
|
|
699
|
+
return (...innerArgs) => {
|
|
700
|
+
// "callAll" event notifications expect the instanceId as first argument
|
|
701
|
+
const a = isCallAll ? [instanceId, ...innerArgs] : [...innerArgs]
|
|
702
|
+
VrpcAdapter._callback({ a, s: clientId, i: eventId })
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
static _registerListener ({
|
|
707
|
+
eventId,
|
|
708
|
+
clientId,
|
|
709
|
+
instanceId,
|
|
710
|
+
event,
|
|
711
|
+
isCallAll
|
|
712
|
+
}) {
|
|
713
|
+
if (!VrpcAdapter._listeners[instanceId]) {
|
|
714
|
+
VrpcAdapter._listeners[instanceId] = {
|
|
715
|
+
[eventId]: {
|
|
716
|
+
event,
|
|
717
|
+
clients: new Set([clientId]),
|
|
718
|
+
listener: VrpcAdapter._generateListener({
|
|
719
|
+
eventId,
|
|
720
|
+
instanceId,
|
|
721
|
+
isCallAll
|
|
722
|
+
})
|
|
704
723
|
}
|
|
705
724
|
}
|
|
725
|
+
} else if (!VrpcAdapter._listeners[instanceId][eventId]) {
|
|
726
|
+
VrpcAdapter._listeners[instanceId][eventId] = {
|
|
727
|
+
event,
|
|
728
|
+
clients: new Set([clientId]),
|
|
729
|
+
listener: VrpcAdapter._generateListener({
|
|
730
|
+
eventId,
|
|
731
|
+
instanceId,
|
|
732
|
+
isCallAll
|
|
733
|
+
})
|
|
734
|
+
}
|
|
735
|
+
} else {
|
|
736
|
+
VrpcAdapter._listeners[instanceId][eventId].clients.add(clientId)
|
|
706
737
|
}
|
|
738
|
+
return VrpcAdapter._listeners[instanceId][eventId].listener
|
|
707
739
|
}
|
|
708
740
|
|
|
709
|
-
static
|
|
741
|
+
static _generateListener ({ eventId, instanceId, isCallAll }) {
|
|
710
742
|
return (...innerArgs) => {
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
VrpcAdapter._callback({ a, s: sender, i: id })
|
|
743
|
+
const a = isCallAll ? [instanceId, ...innerArgs] : [...innerArgs]
|
|
744
|
+
VrpcAdapter._callback({ a, i: eventId })
|
|
714
745
|
}
|
|
715
746
|
}
|
|
716
747
|
|
|
717
|
-
static
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
const
|
|
723
|
-
|
|
748
|
+
static _unregisterListener ({ eventId, clientId, instanceId }) {
|
|
749
|
+
if (
|
|
750
|
+
VrpcAdapter._listeners[instanceId] &&
|
|
751
|
+
VrpcAdapter._listeners[instanceId][eventId]
|
|
752
|
+
) {
|
|
753
|
+
const { listener, clients } = VrpcAdapter._listeners[instanceId][eventId]
|
|
754
|
+
clients.delete(clientId)
|
|
755
|
+
if (clients.size === 0) {
|
|
756
|
+
delete VrpcAdapter._listeners[instanceId][eventId]
|
|
757
|
+
if (Object.keys(VrpcAdapter._listeners[instanceId]).length === 0) {
|
|
758
|
+
delete VrpcAdapter._listeners[instanceId]
|
|
759
|
+
}
|
|
760
|
+
return listener
|
|
761
|
+
}
|
|
724
762
|
}
|
|
725
763
|
}
|
|
726
764
|
|
|
765
|
+
static _removeAllListeners (event, clientId, instanceId) {
|
|
766
|
+
const eventIds = VrpcAdapter._listeners[instanceId]
|
|
767
|
+
if (!eventIds) return
|
|
768
|
+
Object.entries(eventIds).forEach(([ek, ev]) => {
|
|
769
|
+
if (ev.event === event && ev.clients.has(clientId)) {
|
|
770
|
+
ev.clients.delete(clientId)
|
|
771
|
+
if (ev.clients.size === 0) {
|
|
772
|
+
VrpcAdapter.getInstance(instanceId).removeListener(
|
|
773
|
+
ev.event,
|
|
774
|
+
ev.listener
|
|
775
|
+
)
|
|
776
|
+
delete VrpcAdapter._listeners[instanceId][ek]
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
})
|
|
780
|
+
}
|
|
781
|
+
|
|
727
782
|
static _handlePromise (json, promise) {
|
|
728
783
|
try {
|
|
729
784
|
const cid = VrpcAdapter._correlationId++ % Number.MAX_SAFE_INTEGER
|
package/vrpc/VrpcAgent.js
CHANGED
|
@@ -48,7 +48,7 @@ class VrpcAgent extends EventEmitter {
|
|
|
48
48
|
})
|
|
49
49
|
parser.add_argument('-d', '--domain', {
|
|
50
50
|
help: 'Domain name',
|
|
51
|
-
default: domain || '
|
|
51
|
+
default: domain || 'vrpc'
|
|
52
52
|
})
|
|
53
53
|
parser.add_argument('-t', '--token', {
|
|
54
54
|
help: 'access token',
|
|
@@ -92,10 +92,10 @@ 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
|
|
98
|
-
* @param {String} [obj.domain='
|
|
97
|
+
* @param {String} [obj.token] Access token
|
|
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)
|
|
@@ -104,7 +104,7 @@ class VrpcAgent extends EventEmitter {
|
|
|
104
104
|
*
|
|
105
105
|
* @example
|
|
106
106
|
* const agent = new Agent({
|
|
107
|
-
* domain: '
|
|
107
|
+
* domain: 'vrpc'
|
|
108
108
|
* agent: 'myAgent'
|
|
109
109
|
* })
|
|
110
110
|
*/
|
|
@@ -112,7 +112,7 @@ class VrpcAgent extends EventEmitter {
|
|
|
112
112
|
username,
|
|
113
113
|
password,
|
|
114
114
|
token,
|
|
115
|
-
domain = '
|
|
115
|
+
domain = 'vrpc',
|
|
116
116
|
agent = VrpcAgent._generateAgentName(),
|
|
117
117
|
broker = 'mqtts://vrpc.io:8883',
|
|
118
118
|
log = 'console',
|
|
@@ -130,7 +130,6 @@ class VrpcAgent extends EventEmitter {
|
|
|
130
130
|
this._broker = broker
|
|
131
131
|
this._qos = bestEffort ? 0 : 1
|
|
132
132
|
this._version = version
|
|
133
|
-
this._isReconnect = false
|
|
134
133
|
if (log === 'console') {
|
|
135
134
|
this._log = console
|
|
136
135
|
this._log.debug = () => {}
|
|
@@ -169,12 +168,15 @@ class VrpcAgent extends EventEmitter {
|
|
|
169
168
|
.createHash('md5')
|
|
170
169
|
.update(this._domain + this._agent)
|
|
171
170
|
.digest('hex')
|
|
172
|
-
.
|
|
171
|
+
.substring(0, 20)
|
|
173
172
|
let username = this._username
|
|
174
173
|
let password = this._password
|
|
175
174
|
if (this._token) {
|
|
176
|
-
username =
|
|
175
|
+
username = `${this._domain}:${this._agent}`
|
|
177
176
|
password = this._token
|
|
177
|
+
} else if (!this._password) {
|
|
178
|
+
username = `${this._domain}:${this._agent}`
|
|
179
|
+
password = this._generateToken()
|
|
178
180
|
}
|
|
179
181
|
this._options = {
|
|
180
182
|
username,
|
|
@@ -194,12 +196,7 @@ class VrpcAgent extends EventEmitter {
|
|
|
194
196
|
this._log.info(`Agent : ${this._agent}`)
|
|
195
197
|
this._log.info(`Broker : ${this._broker}`)
|
|
196
198
|
this._log.info('Connecting to MQTT server...')
|
|
197
|
-
|
|
198
|
-
if (wasEnded) return
|
|
199
|
-
this._client = mqtt.connect(this._broker, {
|
|
200
|
-
...this._options,
|
|
201
|
-
clean: false
|
|
202
|
-
})
|
|
199
|
+
this._client = mqtt.connect(this._broker, this._options)
|
|
203
200
|
this._client.on('connect', this._handleConnect.bind(this))
|
|
204
201
|
this._client.on('reconnect', this._handleReconnect.bind(this))
|
|
205
202
|
this._client.on('error', this._handleError.bind(this))
|
|
@@ -238,7 +235,6 @@ class VrpcAgent extends EventEmitter {
|
|
|
238
235
|
}
|
|
239
236
|
}
|
|
240
237
|
await new Promise(resolve => this._client.end(false, {}, resolve))
|
|
241
|
-
await this._clearPersistedSession()
|
|
242
238
|
} catch (err) {
|
|
243
239
|
this._log.error(err, `Problem during disconnecting agent: ${err.message}`)
|
|
244
240
|
}
|
|
@@ -250,10 +246,31 @@ class VrpcAgent extends EventEmitter {
|
|
|
250
246
|
.createHash('md5')
|
|
251
247
|
.update(path.resolve())
|
|
252
248
|
.digest('hex')
|
|
253
|
-
.
|
|
249
|
+
.substring(0, 4)
|
|
254
250
|
return `${username}-${pathId}@${os.hostname()}-${os.platform()}-js`
|
|
255
251
|
}
|
|
256
252
|
|
|
253
|
+
_generateToken () {
|
|
254
|
+
const uid =
|
|
255
|
+
this._domain +
|
|
256
|
+
this._agent +
|
|
257
|
+
os.userInfo().username +
|
|
258
|
+
path.resolve() +
|
|
259
|
+
os.arch() +
|
|
260
|
+
os.homedir() +
|
|
261
|
+
os.hostname() +
|
|
262
|
+
os.platform() +
|
|
263
|
+
os.release() +
|
|
264
|
+
os.totalmem() +
|
|
265
|
+
os.type() +
|
|
266
|
+
JSON.stringify(os.networkInterfaces()) +
|
|
267
|
+
JSON.stringify(os.cpus().map(({ model }) => model))
|
|
268
|
+
return crypto
|
|
269
|
+
.createHash('md5')
|
|
270
|
+
.update(uid)
|
|
271
|
+
.digest('hex')
|
|
272
|
+
}
|
|
273
|
+
|
|
257
274
|
_validateDomain (domain) {
|
|
258
275
|
if (!domain) throw new Error('The domain must be specified')
|
|
259
276
|
if (domain.match(/[+/#*]/)) {
|
|
@@ -281,27 +298,6 @@ class VrpcAgent extends EventEmitter {
|
|
|
281
298
|
})
|
|
282
299
|
}
|
|
283
300
|
|
|
284
|
-
/**
|
|
285
|
-
* @return {Boolean} true if `agent.end()` was explicitly called
|
|
286
|
-
*/
|
|
287
|
-
async _clearPersistedSession () {
|
|
288
|
-
// Clear potentially existing persisted sessions
|
|
289
|
-
const client = mqtt.connect(this._broker, { ...this._options, clean: true })
|
|
290
|
-
client.on('error', err => this.emit('error', err))
|
|
291
|
-
client.on('offline', () => this.emit('offline'))
|
|
292
|
-
client.on('reconnect', () => this.emit('reconnect'))
|
|
293
|
-
return new Promise(resolve => {
|
|
294
|
-
client.on('connect', () => {
|
|
295
|
-
client.end(false, {}, () => resolve(false))
|
|
296
|
-
})
|
|
297
|
-
// Will be triggered if the user called 'agent.end()'
|
|
298
|
-
this.once('end', () => {
|
|
299
|
-
client.end()
|
|
300
|
-
resolve(true)
|
|
301
|
-
})
|
|
302
|
-
})
|
|
303
|
-
}
|
|
304
|
-
|
|
305
301
|
_mqttPublish (topic, message, options) {
|
|
306
302
|
this._client.publish(
|
|
307
303
|
topic,
|
|
@@ -371,6 +367,8 @@ class VrpcAgent extends EventEmitter {
|
|
|
371
367
|
resolve()
|
|
372
368
|
} else {
|
|
373
369
|
this._client.once('connect', resolve)
|
|
370
|
+
// Will be triggered if the user called 'agent.end()'
|
|
371
|
+
this.once('end', resolve)
|
|
374
372
|
}
|
|
375
373
|
})
|
|
376
374
|
}
|
|
@@ -409,16 +407,6 @@ class VrpcAgent extends EventEmitter {
|
|
|
409
407
|
|
|
410
408
|
_handleConnect () {
|
|
411
409
|
this._log.info('[OK]')
|
|
412
|
-
if (this._isReconnect) {
|
|
413
|
-
this._publishAgentInfoMessage()
|
|
414
|
-
const classes = this._getClasses()
|
|
415
|
-
classes.forEach(className => {
|
|
416
|
-
this._publishClassInfoMessage(className)
|
|
417
|
-
})
|
|
418
|
-
this.emit('connect')
|
|
419
|
-
this._isReconnect = false
|
|
420
|
-
return
|
|
421
|
-
}
|
|
422
410
|
try {
|
|
423
411
|
const topics = this._generateTopics()
|
|
424
412
|
if (topics.length > 0) this._mqttSubscribe(topics)
|
|
@@ -666,7 +654,6 @@ class VrpcAgent extends EventEmitter {
|
|
|
666
654
|
}
|
|
667
655
|
|
|
668
656
|
_handleReconnect () {
|
|
669
|
-
this._isReconnect = true
|
|
670
657
|
this._log.warn(`Reconnecting to ${this._broker}`)
|
|
671
658
|
this.emit('reconnect')
|
|
672
659
|
}
|
package/vrpc/VrpcClient.js
CHANGED
|
@@ -59,9 +59,9 @@ class VrpcClient extends EventEmitter {
|
|
|
59
59
|
*
|
|
60
60
|
* @constructor
|
|
61
61
|
* @param {Object} options
|
|
62
|
-
* @param {String} options.
|
|
63
|
-
* @param {String} options.
|
|
64
|
-
* @param {String} options.
|
|
62
|
+
* @param {String} [options.username] MQTT username
|
|
63
|
+
* @param {String} [options.password] MQTT password (if no token is provided)
|
|
64
|
+
* @param {String} [options.token] Access token
|
|
65
65
|
* @param {String} options.domain Sets the domain
|
|
66
66
|
* @param {String} [options.agent="*"] Sets default agent
|
|
67
67
|
* @param {String} [options.broker="mqtts://vrpc.io:8883"] Broker url in form: `<scheme>://<host>:<port>`
|
|
@@ -70,14 +70,14 @@ class VrpcClient extends EventEmitter {
|
|
|
70
70
|
* @param {Boolean} [options.bestEffort=false] If true, message will be sent with best effort, i.e. no caching if offline
|
|
71
71
|
* @example
|
|
72
72
|
* const client = new VrpcClient({
|
|
73
|
-
* domain: '
|
|
73
|
+
* domain: 'vrpc',
|
|
74
74
|
* broker: 'mqtt://vrpc.io'
|
|
75
75
|
* })
|
|
76
76
|
*/
|
|
77
77
|
constructor ({
|
|
78
78
|
token,
|
|
79
|
-
username,
|
|
80
79
|
password,
|
|
80
|
+
username,
|
|
81
81
|
domain,
|
|
82
82
|
agent = '*',
|
|
83
83
|
broker = 'mqtts://vrpc.io:8883',
|
|
@@ -152,7 +152,7 @@ class VrpcClient extends EventEmitter {
|
|
|
152
152
|
let username = this._username
|
|
153
153
|
let password = this._password
|
|
154
154
|
if (this._token) {
|
|
155
|
-
username =
|
|
155
|
+
username = username || this._generateUserName()
|
|
156
156
|
password = this._token
|
|
157
157
|
}
|
|
158
158
|
const options = {
|
|
@@ -660,10 +660,13 @@ class VrpcClient extends EventEmitter {
|
|
|
660
660
|
return new Promise(resolve => this._client.end(false, {}, resolve))
|
|
661
661
|
}
|
|
662
662
|
|
|
663
|
+
_generateUserName () {
|
|
664
|
+
return `${this._domain}:client@${os.hostname()}-${os.platform()}-js`
|
|
665
|
+
}
|
|
666
|
+
|
|
663
667
|
_createMqttClientId () {
|
|
664
668
|
const clientInfo =
|
|
665
669
|
os.arch() +
|
|
666
|
-
JSON.stringify(os.cpus()) +
|
|
667
670
|
os.homedir() +
|
|
668
671
|
os.hostname() +
|
|
669
672
|
JSON.stringify(os.networkInterfaces()) +
|
|
@@ -694,6 +697,12 @@ class VrpcClient extends EventEmitter {
|
|
|
694
697
|
this._log.warn(
|
|
695
698
|
`Could not publish MQTT message because: ${err.message}`
|
|
696
699
|
)
|
|
700
|
+
if (err.message === 'client disconnecting') {
|
|
701
|
+
// Workaround for an already reported bug in MQTT.js (#1284)
|
|
702
|
+
this._log.info('Forcing reconnect now...')
|
|
703
|
+
this._client.disconnecting = false
|
|
704
|
+
this._client.end(true, {}, () => this._client.reconnect())
|
|
705
|
+
}
|
|
697
706
|
}
|
|
698
707
|
}
|
|
699
708
|
)
|
|
@@ -708,6 +717,12 @@ class VrpcClient extends EventEmitter {
|
|
|
708
717
|
this._log.warn(
|
|
709
718
|
`Could not subscribe to topic: ${topic} because: ${err.message}`
|
|
710
719
|
)
|
|
720
|
+
if (err.message === 'client disconnecting') {
|
|
721
|
+
// Workaround for an already reported bug in MQTT.js (#1284)
|
|
722
|
+
this._log.info('Forcing reconnect now...')
|
|
723
|
+
this._client.disconnecting = false
|
|
724
|
+
this._client.end(true, {}, () => this._client.reconnect())
|
|
725
|
+
}
|
|
711
726
|
} else {
|
|
712
727
|
if (granted.length === 0) {
|
|
713
728
|
this._log.debug(`Already subscribed to: ${topic}`)
|
|
@@ -933,7 +948,8 @@ class VrpcClient extends EventEmitter {
|
|
|
933
948
|
if (typeof ret === 'string' && ret.substring(0, 5) === '__p__') {
|
|
934
949
|
this._eventEmitter.once(ret, promiseData => {
|
|
935
950
|
// TODO improve error message here, like above
|
|
936
|
-
if (promiseData.e)
|
|
951
|
+
if (promiseData.e)
|
|
952
|
+
reject(new Error(`[vrpc ${agent}-${c}-${f}]: ${promiseData.e}`))
|
|
937
953
|
else resolve(promiseData.r)
|
|
938
954
|
})
|
|
939
955
|
} else {
|
|
@@ -1068,7 +1084,9 @@ class VrpcClient extends EventEmitter {
|
|
|
1068
1084
|
: `${this._domain}/${agent}/${className}/${event}`
|
|
1069
1085
|
const id = `__e__${topic}`
|
|
1070
1086
|
if (this._cachedSubscriptions[topic]) {
|
|
1071
|
-
const index = this._cachedSubscriptions[topic].findIndex(
|
|
1087
|
+
const index = this._cachedSubscriptions[topic].findIndex(
|
|
1088
|
+
x => x.callback === callback
|
|
1089
|
+
)
|
|
1072
1090
|
if (index === -1) {
|
|
1073
1091
|
this._log.warn(`Failed removing event listener ${id}`)
|
|
1074
1092
|
return null
|