vrpc 3.0.3 → 3.1.1
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/browser/vrpc.js +1 -1
- package/package.json +1 -1
- package/vrpc/VrpcAdapter.js +165 -99
- package/vrpc/VrpcAgent.js +72 -56
- package/vrpc/VrpcClient.js +64 -12
- package/vrpc/VrpcNative.js +36 -4
- package/CHANGELOG.md +0 -774
package/vrpc/VrpcClient.js
CHANGED
|
@@ -59,7 +59,7 @@ class VrpcClient extends EventEmitter {
|
|
|
59
59
|
*
|
|
60
60
|
* @constructor
|
|
61
61
|
* @param {Object} options
|
|
62
|
-
* @param {String} [options.username
|
|
62
|
+
* @param {String} [options.username] MQTT username
|
|
63
63
|
* @param {String} [options.password] MQTT password (if no token is provided)
|
|
64
64
|
* @param {String} [options.token] Access token
|
|
65
65
|
* @param {String} options.domain Sets the domain
|
|
@@ -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',
|
|
@@ -77,13 +79,15 @@ class VrpcClient extends EventEmitter {
|
|
|
77
79
|
constructor ({
|
|
78
80
|
token,
|
|
79
81
|
password,
|
|
80
|
-
username
|
|
82
|
+
username,
|
|
81
83
|
domain,
|
|
82
84
|
agent = '*',
|
|
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()
|
|
@@ -152,7 +163,7 @@ class VrpcClient extends EventEmitter {
|
|
|
152
163
|
let username = this._username
|
|
153
164
|
let password = this._password
|
|
154
165
|
if (this._token) {
|
|
155
|
-
username = username ||
|
|
166
|
+
username = username || this._generateUserName()
|
|
156
167
|
password = this._token
|
|
157
168
|
}
|
|
158
169
|
const options = {
|
|
@@ -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__`
|
|
@@ -660,14 +671,13 @@ class VrpcClient extends EventEmitter {
|
|
|
660
671
|
return new Promise(resolve => this._client.end(false, {}, resolve))
|
|
661
672
|
}
|
|
662
673
|
|
|
663
|
-
|
|
664
|
-
return `${
|
|
674
|
+
_generateUserName () {
|
|
675
|
+
return `${this._domain}:client@${os.hostname()}-${os.platform()}-js`
|
|
665
676
|
}
|
|
666
677
|
|
|
667
678
|
_createMqttClientId () {
|
|
668
679
|
const clientInfo =
|
|
669
680
|
os.arch() +
|
|
670
|
-
JSON.stringify(os.cpus()) +
|
|
671
681
|
os.homedir() +
|
|
672
682
|
os.hostname() +
|
|
673
683
|
JSON.stringify(os.networkInterfaces()) +
|
|
@@ -685,7 +695,8 @@ class VrpcClient extends EventEmitter {
|
|
|
685
695
|
}
|
|
686
696
|
|
|
687
697
|
_createVrpcClientId () {
|
|
688
|
-
|
|
698
|
+
const identity = this._identity || this._instance
|
|
699
|
+
return `${this._domain}/${os.hostname()}/${identity}`
|
|
689
700
|
}
|
|
690
701
|
|
|
691
702
|
_mqttPublish (topic, message, options) {
|
|
@@ -698,6 +709,12 @@ class VrpcClient extends EventEmitter {
|
|
|
698
709
|
this._log.warn(
|
|
699
710
|
`Could not publish MQTT message because: ${err.message}`
|
|
700
711
|
)
|
|
712
|
+
if (err.message === 'client disconnecting') {
|
|
713
|
+
// Workaround for an already reported bug in MQTT.js (#1284)
|
|
714
|
+
this._log.info('Forcing reconnect now...')
|
|
715
|
+
this._client.disconnecting = false
|
|
716
|
+
this._client.end(true, {}, () => this._client.reconnect())
|
|
717
|
+
}
|
|
701
718
|
}
|
|
702
719
|
}
|
|
703
720
|
)
|
|
@@ -710,9 +727,44 @@ class VrpcClient extends EventEmitter {
|
|
|
710
727
|
(err, granted) => {
|
|
711
728
|
if (err) {
|
|
712
729
|
this._log.warn(
|
|
713
|
-
`Could not subscribe to topic: ${topic} because: ${err.message}`
|
|
730
|
+
`Could not subscribe to topic(s): '${topic}', because: ${err.message}`
|
|
714
731
|
)
|
|
732
|
+
if (err.message === 'client disconnecting') {
|
|
733
|
+
// Workaround for an already reported bug in MQTT.js (#1284)
|
|
734
|
+
this._log.info('Forcing reconnect now...')
|
|
735
|
+
this._client.disconnecting = false
|
|
736
|
+
this._client.end(true, {}, () => this._client.reconnect())
|
|
737
|
+
}
|
|
715
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
|
+
}
|
|
716
768
|
if (granted.length === 0) {
|
|
717
769
|
this._log.debug(`Already subscribed to: ${topic}`)
|
|
718
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
|