vrpc 2.5.1 → 3.0.0-alpha.3

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.
@@ -10,9 +10,9 @@ __\/\\\_______\/\\\__/\\\///////\\\___\/\\\/////////\\\____/\\\////////__
10
10
  ________\///________\///________\///__\///___________________\/////////__
11
11
 
12
12
 
13
- Non-intrusively binds code and provides access in form of asynchronous remote
13
+ Non-intrusively adapts code and provides access in form of asynchronous remote
14
14
  procedure calls (RPC).
15
- Author: Dr. Burkhard C. Heisen (https://github.com/bheisen/vrpc)
15
+ Author: Dr. Burkhard C. Heisen (https://github.com/heisenware/vrpc)
16
16
 
17
17
 
18
18
  Licensed under the MIT License <http://opensource.org/licenses/MIT>.
@@ -39,16 +39,19 @@ SOFTWARE.
39
39
 
40
40
  const os = require('os')
41
41
  const crypto = require('crypto')
42
+ const { nanoid } = require('nanoid')
42
43
  const mqtt = require('mqtt')
43
44
  const EventEmitter = require('events')
44
45
 
46
+ const VRPC_PROTOCOL_VERSION = 3
47
+
45
48
  /**
46
49
  * Client capable of creating proxy objects and remotely calling
47
50
  * functions as provided through one or more (distributed) agents.
48
51
  *
49
52
  * @extends EventEmitter
50
53
  */
51
- class VrpcRemote extends EventEmitter {
54
+ class VrpcClient extends EventEmitter {
52
55
  /**
53
56
  * Constructs a remote client, able to communicate with any distributed agents
54
57
  *
@@ -66,7 +69,7 @@ class VrpcRemote extends EventEmitter {
66
69
  * @param {Object} [options.log=console] Log object (must support debug, info, warn, and error level)
67
70
  * @param {Boolean} [options.bestEffort=false] If true, message will be sent with best effort, i.e. no caching if offline
68
71
  * @example
69
- * const client = new VrpcRemote({
72
+ * const client = new VrpcClient({
70
73
  * domain: 'public.vrpc',
71
74
  * broker: 'mqtt://vrpc.io'
72
75
  * })
@@ -86,11 +89,15 @@ class VrpcRemote extends EventEmitter {
86
89
  // domain sanity check
87
90
  if (!domain) throw new Error('The domain must be specified')
88
91
  if (domain.match(/[+/#*]/)) {
89
- throw new Error('The domain must NOT contain any of those characters: "+", "/", "#", "*"')
92
+ throw new Error(
93
+ 'The domain must NOT contain any of those characters: "+", "/", "#", "*"'
94
+ )
90
95
  }
91
96
  // agent sanity check
92
97
  if (agent.match(/[+/#]/)) {
93
- throw new Error('The agent must NOT contain any of those characters: "+", "/", "#"')
98
+ throw new Error(
99
+ 'The agent must NOT contain any of those characters: "+", "/", "#"'
100
+ )
94
101
  }
95
102
  this._token = token
96
103
  this._username = username
@@ -101,12 +108,13 @@ class VrpcRemote extends EventEmitter {
101
108
  this._timeout = timeout
102
109
  this._qos = this._qos = bestEffort ? 0 : 1
103
110
 
104
- this._instance = crypto.randomBytes(2).toString('hex')
111
+ this._instance = nanoid(8)
105
112
  this._mqttClientId = this._createMqttClientId()
106
113
  this._vrpcClientId = this._createVrpcClientId()
107
114
  this._agents = {}
108
115
  this._eventEmitter = new EventEmitter()
109
116
  this._invokeId = 0
117
+ this._proxyId = 0
110
118
  this._client = null
111
119
  this._cachedSubscriptions = new Map()
112
120
  this._proxies = {}
@@ -118,6 +126,15 @@ class VrpcRemote extends EventEmitter {
118
126
  }
119
127
  }
120
128
 
129
+ /**
130
+ * Provides a unique id for this client instance
131
+ *
132
+ * @returns {String} clientId
133
+ */
134
+ getClientId () {
135
+ return this._vrpcClientId
136
+ }
137
+
121
138
  /**
122
139
  * Actually connects to the MQTT broker.
123
140
  *
@@ -154,15 +171,15 @@ class VrpcRemote extends EventEmitter {
154
171
  if (password === undefined) delete options.password
155
172
  this._client = mqtt.connect(this._broker, options)
156
173
 
157
- this._client.on('error', (err) => {
174
+ this._client.on('error', err => {
158
175
  this.emit('error', err)
159
176
  })
160
177
 
161
- this._client.stream.on('error', (err) => {
178
+ this._client.stream.on('error', err => {
162
179
  this.emit('error', err)
163
180
  })
164
181
 
165
- this.on('error', (err) => {
182
+ this.on('error', err => {
166
183
  this._log.debug(`Encountered MQTT error: ${err.message}`)
167
184
  })
168
185
 
@@ -194,7 +211,7 @@ class VrpcRemote extends EventEmitter {
194
211
  this._agents[agent].hostname = hostname
195
212
  this._agents[agent].version = version
196
213
  this.emit('agent', { domain, agent, status, hostname, version })
197
- // ClassInfo message
214
+ // ClassInfo message
198
215
  } else if (instance === '__classInfo__') {
199
216
  // Json properties: { klass, instances, memberFunctions, staticFunctions }
200
217
  const json = JSON.parse(message.toString())
@@ -212,24 +229,23 @@ class VrpcRemote extends EventEmitter {
212
229
  staticFunctions,
213
230
  meta
214
231
  } = json
215
- if (removed.length !== 0) this.emit('instanceGone', removed, { domain, agent, className })
216
- if (added.length !== 0) this.emit('instanceNew', added, { domain, agent, className })
217
- this.emit(
218
- 'class',
219
- {
220
- domain,
221
- agent,
222
- className,
223
- instances,
224
- memberFunctions,
225
- staticFunctions,
226
- meta
227
- }
228
- )
229
- // RPC message
232
+ if (removed.length !== 0)
233
+ this.emit('instanceGone', removed, { domain, agent, className })
234
+ if (added.length !== 0)
235
+ this.emit('instanceNew', added, { domain, agent, className })
236
+ this.emit('class', {
237
+ domain,
238
+ agent,
239
+ className,
240
+ instances,
241
+ memberFunctions,
242
+ staticFunctions,
243
+ meta
244
+ })
245
+ // RPC message
230
246
  } else {
231
- const { id, data } = JSON.parse(message.toString())
232
- this._eventEmitter.emit(id, data)
247
+ const { i, a, e, r } = JSON.parse(message.toString())
248
+ this._eventEmitter.emit(i, { a, e, r })
233
249
  }
234
250
  })
235
251
  await new Promise((resolve, reject) => {
@@ -243,11 +259,6 @@ class VrpcRemote extends EventEmitter {
243
259
  })
244
260
  }
245
261
 
246
- async connected () {
247
- this._indicateDeprecation('VrpcRemote.connected(): This API usage is deprecated, use `connect()` instead.')
248
- return this.connect()
249
- }
250
-
251
262
  /**
252
263
  * Creates a new remote instance and provides a proxy to it.
253
264
  *
@@ -296,23 +307,20 @@ class VrpcRemote extends EventEmitter {
296
307
  */
297
308
  async create ({
298
309
  className,
299
- instance,
310
+ instance = nanoid(8),
300
311
  args = [],
301
312
  agent = this._agent,
302
- cacheProxy = false
313
+ cacheProxy = false,
314
+ isIsolated = false
303
315
  } = {}) {
304
316
  if (agent === '*') throw new Error('Agent must be specified')
305
- const data = instance ? { _1: instance } : {}
306
- const offset = instance ? 2 : 1
307
- args.forEach((value, index) => {
308
- data[`_${index + offset}`] = value
309
- })
310
317
  const json = {
311
- context: className,
312
- method: instance ? '__createNamed__' : '__create__',
313
- id: `${this._instance}-${this._invokeId++ % Number.MAX_SAFE_INTEGER}`,
314
- sender: `${this._domain}/${os.hostname()}/${this._instance}`,
315
- data
318
+ c: className,
319
+ f: isIsolated ? '__createIsolated__' : '__createShared__',
320
+ i: `${this._instance}-${this._invokeId++ % Number.MAX_SAFE_INTEGER}`,
321
+ s: `${this._domain}/${os.hostname()}/${this._instance}`,
322
+ a: [instance, ...args],
323
+ v: VRPC_PROTOCOL_VERSION
316
324
  }
317
325
  const proxy = await this._getProxy(agent, className, json)
318
326
  if (instance && cacheProxy) this._proxies[instance] = proxy
@@ -328,36 +336,15 @@ class VrpcRemote extends EventEmitter {
328
336
  *
329
337
  * @param {String} instance The instance to be retrieved
330
338
  * @param {Object} [options] Explicitly define agent and class
331
- * @param {String} options.className Name of the instance's class
332
- * @param {String} options.agent Agent name. If not provided class default is used
333
- * @param {bool} options.noWait If true immediately fail if instance could not be found in local cache
339
+ * @param {String} [options.className] Name of the instance's class
340
+ * @param {String} [options.agent] Agent name. If not provided class default is used as priority hit
341
+ * @param {bool} [options.noWait=false] If true immediately fail if instance could not be found in local cache
334
342
  * @returns {Promise<Proxy>} Proxy object reflecting the remotely existing instance
335
343
  */
336
- async getInstance (instance, options) {
344
+ async getInstance (instance, options = {}) {
337
345
  if (this._proxies[instance]) return this._proxies[instance]
338
- if (typeof instance === 'string') {
339
- const {
340
- agent,
341
- className,
342
- instance: instanceString
343
- } = await this._getInstanceData(instance, options)
344
- return this._createProxy(agent, className, instanceString)
345
- } else { // deprecate this
346
- this._indicateDeprecation(
347
- 'VrpcRemote.getInstance(): ' +
348
- 'Using an object as single argument is deprecated, ' +
349
- 'use "getInstance(instance, options)" instead.'
350
- )
351
- const fakedOptions = { ...instance }
352
- const fakedInstance = fakedOptions.instance
353
- delete fakedOptions.instance
354
- const {
355
- agent,
356
- className,
357
- instance: instanceString
358
- } = await this._getInstanceData(fakedInstance, fakedOptions)
359
- return this._createProxy(agent, className, instanceString)
360
- }
346
+ const { agent, className } = await this._getInstanceData(instance, options)
347
+ return this._createProxy(agent, className, instance)
361
348
  }
362
349
 
363
350
  /**
@@ -369,29 +356,18 @@ class VrpcRemote extends EventEmitter {
369
356
  * @param {String} instance The instance to be deleted
370
357
  * @param {Object} [options] Explicitly define agent and class
371
358
  * @param {String} options.className Name of the instance's class
372
- * @param {String} options.agent Agent name. If not provided class default is used
359
+ * @param {String} options.agent Agent name. If not provided class default is used as priority hit
373
360
  * @returns {Promise<Boolean>} true if successful, false otherwise
374
361
  */
375
- async delete (instance, options) {
376
- let instanceData = { agent: this._agent }
377
- if (typeof instance === 'string') {
378
- instanceData = await this._getInstanceData(instance)
379
- if (options) instanceData = { ...options, ...instanceData }
380
- } else { // deprecate this
381
- this._indicateDeprecation(
382
- 'VrpcRemote.delete(): ' +
383
- 'Using an object as single argument is deprecated, ' +
384
- 'use "delete(instance, options)" instead.'
385
- )
386
- instanceData = { ...instanceData, ...instance }
387
- }
388
- const { agent, className, instance: instanceString } = instanceData
362
+ async delete (instance, options = {}) {
363
+ const { agent, className } = await this._getInstanceData(instance, options)
389
364
  const json = {
390
- context: className,
391
- method: '__delete__',
392
- id: `${this._instance}-${this._invokeId++ % Number.MAX_SAFE_INTEGER}`,
393
- sender: `${this._domain}/${os.hostname()}/${this._instance}`,
394
- data: { _1: instanceString }
365
+ c: className,
366
+ f: '__delete__',
367
+ i: `${this._instance}-${this._invokeId++ % Number.MAX_SAFE_INTEGER}`,
368
+ s: `${this._domain}/${os.hostname()}/${this._instance}`,
369
+ a: [instance],
370
+ v: VRPC_PROTOCOL_VERSION
395
371
  }
396
372
  const topic = `${this._domain}/${agent}/${className}/__static__/__delete__`
397
373
  this._mqttPublish(topic, JSON.stringify(json))
@@ -415,12 +391,15 @@ class VrpcRemote extends EventEmitter {
415
391
  args = [],
416
392
  agent = this._agent
417
393
  } = {}) {
394
+ const wrapped = this._wrapArguments(className, functionName, ...args)
395
+ if (!wrapped) return // Skipping remote call -> handled locally
418
396
  const json = {
419
- context: className,
420
- method: functionName,
421
- id: `${this._instance}-${this._invokeId++ % Number.MAX_SAFE_INTEGER}`,
422
- sender: this._vrpcClientId,
423
- data: this._packData(className, functionName, ...args)
397
+ c: className,
398
+ f: functionName,
399
+ i: `${this._instance}-${this._invokeId++ % Number.MAX_SAFE_INTEGER}`,
400
+ s: this._vrpcClientId,
401
+ a: wrapped,
402
+ v: VRPC_PROTOCOL_VERSION
424
403
  }
425
404
  const topic = `${this._domain}/${agent}/${className}/__static__/${functionName}`
426
405
  await this._waitUntilClassIsOnline(agent, className)
@@ -430,19 +409,23 @@ class VrpcRemote extends EventEmitter {
430
409
 
431
410
  /**
432
411
  * Calls the same function on all instances of a given class and returns an
433
- * aggregated result.
412
+ * aggregated result. It as well allows for batch event and callback
413
+ * registrations. In this case the instanceId of the emitter is injected as
414
+ * first argument of any event callback.
434
415
  *
435
416
  * NOTE: When no agent was specified as class default and no agent is
436
417
  * specified when calling this function, callAll will act on the requested
437
- * class across all available agents. The same is true when explicitly using
438
- * a wildcard (*) as agent value.
418
+ * class across all available agents. The same is true when explicitly using a
419
+ * wildcard (*) as agent value.
439
420
  *
440
421
  * @param {Object} options
441
422
  * @param {String} options.className Name of the static function's class
442
- * @param {Array} [options.args] Positional arguments of the static function call
443
- * @param {String} [options.agent] Agent name. If not provided class default is used
444
- * @returns {Promise<Object[]>} An array of objects `{ id, val, err }` carrying
445
- * the instance id, the return value and potential errors
423
+ * @param {Array} [options.args] Positional arguments of the static function
424
+ * call
425
+ * @param {String} [options.agent] Agent name. If not provided class default
426
+ * is used
427
+ * @returns {Promise<Object[]>} An array of objects `{ id, val, err }`
428
+ * carrying the instance id, the return value and potential errors
446
429
  */
447
430
  async callAll ({
448
431
  className,
@@ -450,20 +433,26 @@ class VrpcRemote extends EventEmitter {
450
433
  args = [],
451
434
  agent = this._agent
452
435
  } = {}) {
453
- const data = { _1: functionName }
454
- args.forEach((value, index) => (data[`_${index + 2}`] = value))
455
436
  const json = {
456
- context: className,
457
- method: functionName,
458
- id: `${this._instance}-${this._invokeId++ % Number.MAX_SAFE_INTEGER}`,
459
- sender: this._vrpcClientId,
460
- data
437
+ c: className,
438
+ f: functionName,
439
+ i: `${this._instance}-${this._invokeId++ % Number.MAX_SAFE_INTEGER}`,
440
+ s: this._vrpcClientId,
441
+ a: [],
442
+ v: VRPC_PROTOCOL_VERSION
461
443
  }
462
444
  if (agent === '*') {
463
445
  const result = []
464
446
  const agents = this.getAvailableAgents()
465
447
  for (const x of agents) {
466
448
  const topic = `${this._domain}/${x}/${className}/__static__/__callAll__`
449
+ const wrapped = this._wrapArguments(
450
+ `${x}-${className}`,
451
+ functionName,
452
+ ...args
453
+ )
454
+ if (!wrapped) continue // using cache
455
+ json.a = [functionName, ...wrapped]
467
456
  await this._waitUntilClassIsOnline(x, className)
468
457
  this._mqttPublish(topic, JSON.stringify(json))
469
458
  const tmp = await this._handleAgentAnswer(json)
@@ -472,41 +461,22 @@ class VrpcRemote extends EventEmitter {
472
461
  return result
473
462
  }
474
463
  const topic = `${this._domain}/${agent}/${className}/__static__/__callAll__`
464
+ const wrapped = this._wrapArguments(
465
+ `${agent}-${className}`,
466
+ functionName,
467
+ ...args
468
+ )
469
+ if (!wrapped) return // using cache
470
+ json.a = [functionName, ...wrapped]
475
471
  await this._waitUntilClassIsOnline(agent, className)
476
472
  this._mqttPublish(topic, JSON.stringify(json))
477
473
  return this._handleAgentAnswer(json)
478
474
  }
479
475
 
480
- /**
481
- * Retrieves all agents, instances, classes, member and static
482
- * functions potentially available for remote control.
483
- * @deprecated
484
- * @returns {Object} SystemInformation
485
- * ```ts
486
- * type SystemInformation = {
487
- * [domain].agents[agent].status: string, // 'offline' or 'online'
488
- * [domain].agents[agent].hostname: string,
489
- * [domain].agents[agent].version: string,
490
- * [domain].agents[agent].classes[className].instances: string[],
491
- * [domain].agents[agent].classes[className].memberFunctions: string[],
492
- * [domain].agents[agent].classes[className].staticFunctions: string[],
493
- * [domain].agents[agent].classes[className].meta?: MetaData
494
- * }
495
- * ```
496
- */
497
- getAvailabilities () {
498
- this._indicateDeprecation(
499
- 'VrpcRemote.getAvailabilities(): ' +
500
- 'This function is deprecated and will be removed soon, ' +
501
- 'use `getSystemInformation()` instead.'
502
- )
503
- return { [this._domain]: { agents: this._agents } }
504
- }
505
-
506
476
  /**
507
477
  * Retrieves all information about the currently available components.
508
478
  *
509
- * @returns {Object} SystemInformation
479
+ * @returns {Object} SystemInformation
510
480
  * ```ts
511
481
  * type SystemInformation = {
512
482
  * [agent].status: string, // 'offline' or 'online'
@@ -523,21 +493,6 @@ class VrpcRemote extends EventEmitter {
523
493
  return this._agents
524
494
  }
525
495
 
526
- /**
527
- * Retrieves all domains on which agents can be remote controlled
528
- *
529
- * @deprecated
530
- * @returns {Array} Array of domain names
531
- */
532
- getAvailableDomains () {
533
- this._indicateDeprecation(
534
- 'VrpcRemote.getAvailableDomains(): ' +
535
- 'this function will be removed in the next major release, as the client' +
536
- 'works with a single domain anyways'
537
- )
538
- return [this._domain]
539
- }
540
-
541
496
  /**
542
497
  * Retrieves all available agents.
543
498
  *
@@ -545,19 +500,7 @@ class VrpcRemote extends EventEmitter {
545
500
  * @param {Boolean} [options.mustBeOnline=true] Only retrieve currently online agents
546
501
  * @returns {Array} Array of agent names.
547
502
  */
548
- getAvailableAgents (options = {}) {
549
- /// DEPRECATION INFORMATION AND WORKAROUND - TO BE REMOVED IN 3.x
550
- // `options = {}` was `domain = this._domain` before
551
- if (typeof options === 'string') {
552
- this._indicateDeprecation(
553
- 'VrpcRemote.getAvailableAgents(): ' +
554
- 'Providing a domain here has no effect and will be an error in future.'
555
- )
556
- options = { mustBeOnline: true }
557
- }
558
- ///
559
-
560
- const { mustBeOnline = true } = options
503
+ getAvailableAgents ({ mustBeOnline = true } = {}) {
561
504
  const agents = []
562
505
  if (mustBeOnline) {
563
506
  // loop agents
@@ -578,31 +521,7 @@ class VrpcRemote extends EventEmitter {
578
521
  * @param {Boolean} [options.mustBeOnline=true] Only retrieve currently online classes
579
522
  * @returns {Array} Array of class names.
580
523
  */
581
- getAvailableClasses (options = { agent: this._agent, mustBeOnline: true }, domain) {
582
- /// DEPRECATION INFORMATION AND WORKAROUND - TO BE REMOVED IN 3.x
583
- let agent = this._agent
584
- let mustBeOnline = true
585
- // `options = {}` was `agent = this._agent` before
586
- if (typeof options === 'string') {
587
- this._indicateDeprecation(
588
- 'VrpcRemote.getAvailableClasses(): ' +
589
- 'setting the agent as string argument is deprecated.`' +
590
- 'Use `{ agent: <myAgent> }` instead.'
591
- )
592
- agent = options
593
- } else {
594
- agent = options.agent
595
- mustBeOnline = options.mustBeOnline
596
- }
597
- // was `domain = this._domain` before
598
- if (domain) {
599
- this._indicateDeprecation(
600
- 'VrpcRemote.getAvailableClasses(): ' +
601
- 'Providing a domain here has no effect and will be an error in future.'
602
- )
603
- }
604
- ///
605
-
524
+ getAvailableClasses ({ agent = this._agent, mustBeOnline = true } = {}) {
606
525
  if (agent === '*') throw new Error('Agent must be specified')
607
526
  if (!this._agents[agent]) return []
608
527
  const { classes, status } = this._agents[agent]
@@ -613,41 +532,17 @@ class VrpcRemote extends EventEmitter {
613
532
  /**
614
533
  * Retrieves all (named) instances on specific class and agent.
615
534
  *
616
- * @param {String} className Class name
617
535
  * @param {Object} [options]
536
+ * @param {String} options.className Class name
618
537
  * @param {String} [options.agent] Agent name. If not provided class default is used
619
538
  * @param {Boolean} [options.mustBeOnline=true] Only retrieve currently online classes
620
539
  * @returns {Array} Array of instance names
621
540
  */
622
- getAvailableInstances (
541
+ getAvailableInstances ({
623
542
  className,
624
- options = { agent: this._agent, mustBeOnline: true },
625
- domain
626
- ) {
627
- /// DEPRECATION INFORMATION AND WORKAROUND - TO BE REMOVED IN 3.x
628
- let agent = this._agent
629
- let mustBeOnline = true
630
- // `options = {}` was `agent = this._agent` before
631
- if (typeof options === 'string') {
632
- this._indicateDeprecation(
633
- 'VrpcRemote.getAvailableInstances(): ' +
634
- 'Setting the agent as string argument is deprecated.`' +
635
- 'Use `{ agent: <myAgent> }` instead.'
636
- )
637
- agent = options
638
- } else {
639
- agent = options.agent
640
- mustBeOnline = options.mustBeOnline
641
- }
642
- // was `domain = this._domain` before
643
- if (domain) {
644
- this._indicateDeprecation(
645
- 'VrpcRemote.getAvailableInstances(): ' +
646
- 'Providing a domain here has no effect and will be an error in future.'
647
- )
648
- }
649
- ///
650
-
543
+ agent = this._agent,
544
+ mustBeOnline = true
545
+ } = {}) {
651
546
  if (agent === '*') throw new Error('Agent must be specified')
652
547
  if (!this._agents[agent]) return []
653
548
  const { classes, status } = this._agents[agent]
@@ -658,41 +553,17 @@ class VrpcRemote extends EventEmitter {
658
553
  /**
659
554
  * Retrieves all member functions of specific class and agent.
660
555
  *
661
- * @param {String} className Class name
662
556
  * @param {Object} [options]
557
+ * @param {String} options.className Class name
663
558
  * @param {String} [options.agent] Agent name. If not provided class default is used
664
559
  * @param {Boolean} [options.mustBeOnline=true] Only retrieve currently online classes
665
560
  * @returns {Array} Array of member function names
666
561
  */
667
- getAvailableMemberFunctions (
562
+ getAvailableMemberFunctions ({
668
563
  className,
669
- options = { agent: this._agent, mustBeOnline: true },
670
- domain
671
- ) {
672
- /// DEPRECATION INFORMATION AND WORKAROUND - TO BE REMOVED IN 3.x
673
- let agent = this._agent
674
- let mustBeOnline = true
675
- // `options = {}` was `agent = this._agent` before
676
- if (typeof options === 'string') {
677
- this._indicateDeprecation(
678
- 'VrpcRemote.getAvailableMemberFunctions(): ' +
679
- 'Setting the agent as string argument is deprecated.`' +
680
- 'Use `{ agent: <myAgent> }` instead.'
681
- )
682
- agent = options
683
- } else {
684
- agent = options.agent
685
- mustBeOnline = options.mustBeOnline
686
- }
687
- // was `domain = this._domain` before
688
- if (domain) {
689
- this._indicateDeprecation(
690
- 'VrpcRemote.getAvailableMemberFunctions(): ' +
691
- 'Providing a domain here has no effect and will be an error in future.'
692
- )
693
- }
694
- ///
695
-
564
+ agent = this._agent,
565
+ mustBeOnline = true
566
+ } = {}) {
696
567
  if (agent === '*') throw new Error('Agent must be specified')
697
568
  if (!this._agents[agent]) return []
698
569
  const { classes, status } = this._agents[agent]
@@ -705,41 +576,17 @@ class VrpcRemote extends EventEmitter {
705
576
  /**
706
577
  * Retrieves all static functions of specific class and agent.
707
578
  *
708
- * @param {String} className Class name
709
579
  * @param {Object} [options]
580
+ * @param {String} options.className Class name
710
581
  * @param {String} [options.agent] Agent name. If not provided class default is used
711
582
  * @param {Boolean} [options.mustBeOnline=true] Only retrieve currently online classes
712
583
  * @returns {Array} Array of static function names
713
584
  */
714
- getAvailableStaticFunctions (
585
+ getAvailableStaticFunctions ({
715
586
  className,
716
- options = { agent: this._agent, mustBeOnline: true },
717
- domain
718
- ) {
719
- /// DEPRECATION INFORMATION AND WORKAROUND - TO BE REMOVED IN 3.x
720
- let agent = this._agent
721
- let mustBeOnline = true
722
- // `options = {}` was `agent = this._agent` before
723
- if (typeof options === 'string') {
724
- this._indicateDeprecation(
725
- 'VrpcRemote.getAvailableStaticFunctions(): ' +
726
- 'Setting the agent as string argument is deprecated.`' +
727
- 'Use `{ agent: <myAgent> }` instead.'
728
- )
729
- agent = options
730
- } else {
731
- agent = options.agent
732
- mustBeOnline = options.mustBeOnline
733
- }
734
- // was `domain = this._domain` before
735
- if (domain) {
736
- this._indicateDeprecation(
737
- 'VrpcRemote.getAvailableStaticFunctions(): ' +
738
- 'Providing a domain here has no effect and will be an error in future.'
739
- )
740
- }
741
- ///
742
-
587
+ agent = this._agent,
588
+ mustBeOnline = true
589
+ } = {}) {
743
590
  if (agent === '*') throw new Error('Agent must be specified')
744
591
  if (!this._agents[agent]) return []
745
592
  const { classes, status } = this._agents[agent]
@@ -757,10 +604,7 @@ class VrpcRemote extends EventEmitter {
757
604
  * @param {String} options.agent Agent name. If not provided class default is used
758
605
  * @returns {Promise} Promise that resolves once re-connected
759
606
  */
760
- async reconnectWithToken (
761
- token,
762
- { agent = this._agent } = {}
763
- ) {
607
+ async reconnectWithToken (token, { agent = this._agent } = {}) {
764
608
  this._token = token
765
609
  this._agent = agent
766
610
  this._client.end(() => this.connect())
@@ -799,19 +643,29 @@ class VrpcRemote extends EventEmitter {
799
643
  async end () {
800
644
  this._mqttPublish(
801
645
  `${this._vrpcClientId}/__clientInfo__`,
802
- JSON.stringify({ status: 'offline' })
646
+ JSON.stringify({ status: 'offline', v: VRPC_PROTOCOL_VERSION })
803
647
  )
804
648
  return new Promise(resolve => this._client.end(false, {}, resolve))
805
649
  }
806
650
 
807
651
  _createMqttClientId () {
808
- const clientInfo = os.arch() + JSON.stringify(os.cpus()) + os.homedir() +
809
- os.hostname() + JSON.stringify(os.networkInterfaces()) + os.platform() +
810
- os.release() + os.totalmem() + os.type()
652
+ const clientInfo =
653
+ os.arch() +
654
+ JSON.stringify(os.cpus()) +
655
+ os.homedir() +
656
+ os.hostname() +
657
+ JSON.stringify(os.networkInterfaces()) +
658
+ os.platform() +
659
+ os.release() +
660
+ os.totalmem() +
661
+ os.type()
811
662
  // console.log('ClientInfo:', clientInfo)
812
- const md5 = crypto.createHash('md5').update(clientInfo).digest('hex').substr(0, 13)
813
- // FIXME (3.x): use vrpcp -> vrpcc
814
- return `vrpcp${this._instance}X${md5}` // 5 + 4 + 1 + 13 = 23 (max clientId)
663
+ const md5 = crypto
664
+ .createHash('md5')
665
+ .update(clientInfo)
666
+ .digest('hex')
667
+ .substr(0, 12)
668
+ return `vc3${this._instance}${md5}` // 3 + 8 + 12 = 23 (max clientId)
815
669
  }
816
670
 
817
671
  _createVrpcClientId () {
@@ -819,29 +673,44 @@ class VrpcRemote extends EventEmitter {
819
673
  }
820
674
 
821
675
  _mqttPublish (topic, message, options) {
822
- this._client.publish(topic, message, { qos: this._qos, ...options }, (err) => {
823
- if (err) {
824
- this._log.warn(`Could not publish MQTT message because: ${err.message}`)
676
+ this._client.publish(
677
+ topic,
678
+ message,
679
+ { qos: this._qos, ...options },
680
+ err => {
681
+ if (err) {
682
+ this._log.warn(
683
+ `Could not publish MQTT message because: ${err.message}`
684
+ )
685
+ }
825
686
  }
826
- })
687
+ )
827
688
  }
828
689
 
829
690
  _mqttSubscribe (topic, options) {
830
- this._client.subscribe(topic, { qos: this._qos, ...options }, (err, granted) => {
831
- if (err) {
832
- this._log.warn(`Could not subscribe to topic: ${topic} because: ${err.message}`)
833
- } else {
834
- if (granted.length === 0) {
835
- this._log.debug(`Already subscribed to: ${topic}`)
691
+ this._client.subscribe(
692
+ topic,
693
+ { qos: this._qos, ...options },
694
+ (err, granted) => {
695
+ if (err) {
696
+ this._log.warn(
697
+ `Could not subscribe to topic: ${topic} because: ${err.message}`
698
+ )
699
+ } else {
700
+ if (granted.length === 0) {
701
+ this._log.debug(`Already subscribed to: ${topic}`)
702
+ }
836
703
  }
837
704
  }
838
- })
705
+ )
839
706
  }
840
707
 
841
708
  _mqttUnsubscribe (topic, options) {
842
- this._client.unsubscribe(topic, options, (err) => {
709
+ this._client.unsubscribe(topic, options, err => {
843
710
  if (err) {
844
- this._log.warn(`Could not unsubscribe from topic: ${topic} because: ${err.message}`)
711
+ this._log.warn(
712
+ `Could not unsubscribe from topic: ${topic} because: ${err.message}`
713
+ )
845
714
  }
846
715
  })
847
716
  }
@@ -853,25 +722,22 @@ class VrpcRemote extends EventEmitter {
853
722
  }
854
723
 
855
724
  async _getProxy (agent, className, json) {
856
- const { method } = json
857
- const topic = `${this._domain}/${agent}/${className}/__static__/${method}`
725
+ const { f, i } = json
726
+ const topic = `${this._domain}/${agent}/${className}/__static__/${f}`
858
727
  await this._waitUntilClassIsOnline(agent, className)
859
728
  this._mqttPublish(topic, JSON.stringify(json))
860
729
  return new Promise((resolve, reject) => {
861
730
  const msg = `Proxy creation for class "${className}" on agent "${agent}" and domain "${this._domain}" timed out (> ${this._timeout} ms)`
862
- const timer = setTimeout(
863
- () => {
864
- this._eventEmitter.removeAllListeners(json.id)
865
- reject(new Error(msg))
866
- },
867
- this._timeout
868
- )
869
- this._eventEmitter.once(json.id, data => {
731
+ const timer = setTimeout(() => {
732
+ this._eventEmitter.removeAllListeners(i)
733
+ reject(new Error(msg))
734
+ }, this._timeout)
735
+ this._eventEmitter.once(i, ({ e, r }) => {
870
736
  clearTimeout(timer)
871
- if (data.e) {
872
- reject(new Error(data.e))
737
+ if (e) {
738
+ reject(new Error(e))
873
739
  } else {
874
- const proxy = this._createProxy(agent, className, data.r)
740
+ const proxy = this._createProxy(agent, className, r)
875
741
  resolve(proxy)
876
742
  }
877
743
  })
@@ -891,7 +757,11 @@ class VrpcRemote extends EventEmitter {
891
757
  }
892
758
  timer = setTimeout(() => {
893
759
  this.removeListener('class', checkClass)
894
- reject(new Error(`Proxy creation for class "${className}" on agent "${agent}" and domain "${this._domain}" timed out (> ${this._timeout} ms)`))
760
+ reject(
761
+ new Error(
762
+ `Proxy creation for class "${className}" on agent "${agent}" and domain "${this._domain}" timed out (> ${this._timeout} ms)`
763
+ )
764
+ )
895
765
  }, this._timeout)
896
766
  this.on('class', checkClass)
897
767
  })
@@ -907,10 +777,11 @@ class VrpcRemote extends EventEmitter {
907
777
 
908
778
  _createProxy (agent, className, instance) {
909
779
  const targetTopic = `${this._domain}/${agent}/${className}/${instance}`
910
- const proxyId = crypto.randomBytes(2).toString('hex')
780
+ const proxyId = `${this._instance}-${this._proxyId++}`
911
781
  const proxy = {
912
- _targetId: instance,
913
- _proxyId: proxyId
782
+ vrpcClientId: this._vrpcClientId,
783
+ vrpcInstanceId: instance,
784
+ vrpcProxyId: proxyId
914
785
  }
915
786
  let functions = this._agents[agent].classes[className].memberFunctions
916
787
  // Strip off argument signature
@@ -924,37 +795,38 @@ class VrpcRemote extends EventEmitter {
924
795
  // Build proxy
925
796
  uniqueFuncs.forEach(name => {
926
797
  proxy[name] = async (...args) => {
798
+ const wrapped = this._wrapArguments(proxyId, name, ...args)
799
+ if (!wrapped) return // Skipping remote call -> handled locally
927
800
  try {
928
801
  const json = {
929
- context: instance,
930
- method: name,
931
- id: `${this._instance}-${this._invokeId++ % Number.MAX_SAFE_INTEGER}`,
932
- sender: this._vrpcClientId,
933
- data: this._packData(proxyId, name, ...args)
802
+ c: instance,
803
+ f: name,
804
+ i: `${this._instance}-${this._invokeId++ %
805
+ Number.MAX_SAFE_INTEGER}`,
806
+ s: this._vrpcClientId,
807
+ a: wrapped,
808
+ v: VRPC_PROTOCOL_VERSION
934
809
  }
935
- // Skipping remote call -> handled locally
936
- if (json.data === null) return
937
810
  this._mqttPublish(`${targetTopic}/${name}`, JSON.stringify(json))
938
811
  return this._handleAgentAnswer(json)
939
812
  } catch (err) {
940
- throw new Error(`Could not remotely call "${name}" because: ${err.message}`)
813
+ throw new Error(
814
+ `Could not remotely call "${name}" because: ${err.message}`
815
+ )
941
816
  }
942
817
  }
943
818
  })
944
819
  return proxy
945
820
  }
946
821
 
947
- async _handleAgentAnswer ({ id, context, method }) {
822
+ async _handleAgentAnswer ({ i, c, f }) {
948
823
  return new Promise((resolve, reject) => {
949
- const msg = `Function call "${context}::${method}()" timed out (> ${this._timeout} ms)`
950
- const timer = setTimeout(
951
- () => {
952
- this._eventEmitter.removeAllListeners(id)
953
- reject(new Error(msg))
954
- },
955
- this._timeout
956
- )
957
- this._eventEmitter.once(id, data => {
824
+ const msg = `Function call "${c}::${f}()" timed out (> ${this._timeout} ms)`
825
+ const timer = setTimeout(() => {
826
+ this._eventEmitter.removeAllListeners(i)
827
+ reject(new Error(msg))
828
+ }, this._timeout)
829
+ this._eventEmitter.once(i, data => {
958
830
  clearTimeout(timer)
959
831
  if (data.e) {
960
832
  reject(new Error(data.e))
@@ -976,7 +848,7 @@ class VrpcRemote extends EventEmitter {
976
848
 
977
849
  async _waitForInstance (instance, options = {}) {
978
850
  return new Promise((resolve, reject) => {
979
- const handler = (timer) => (instances, { agent, className }) => {
851
+ const handler = timer => (instances, { agent, className }) => {
980
852
  if (instances.includes(instance)) {
981
853
  if (options.agent && agent !== options.agent) return
982
854
  if (options.className && className !== options.className) return
@@ -985,75 +857,64 @@ class VrpcRemote extends EventEmitter {
985
857
  resolve({ agent, className, instance })
986
858
  }
987
859
  }
988
- const timer = setTimeout(
989
- () => {
990
- this.removeListener('instanceNew', handler(timer))
991
- const msg = `Could not find instance: ${instance} (> ${this._timeout} ms)`
992
- reject(new Error(msg))
993
- },
994
- this._timeout
995
- )
860
+ const timer = setTimeout(() => {
861
+ this.removeListener('instanceNew', handler(timer))
862
+ const msg = `Could not find instance: ${instance} (> ${this._timeout} ms)`
863
+ reject(new Error(msg))
864
+ }, this._timeout)
996
865
  this.on('instanceNew', handler(timer))
997
866
  })
998
867
  }
999
868
 
1000
- _packData (proxyId, functionName, ...args) {
1001
- const data = {}
869
+ _wrapArguments (remoteId, functionName, ...args) {
870
+ const wrapped = []
1002
871
  let isHandledLocally = false
1003
- args.forEach((value, index) => {
872
+ args.forEach((x, i) => {
1004
873
  // Check whether provided argument is a function
1005
- if (this._isFunction(value)) {
874
+ if (this._isFunction(x)) {
1006
875
  // Check special case of an event emitter registration
1007
876
  // We test three conditions:
1008
877
  // 1) functionName must be "on"
1009
878
  // 2) callback is second argument
1010
879
  // 3) first argument was string
1011
- if (functionName === 'on' &&
1012
- index === 1 &&
1013
- typeof args[0] === 'string'
1014
- ) {
1015
- const id = this._addEventSubscription(proxyId, args[0], value)
880
+ if (functionName === 'on' && i === 1 && typeof args[0] === 'string') {
881
+ const id = this._addEventSubscription(remoteId, args[0], x)
1016
882
  if (!id) isHandledLocally = true
1017
- data[`_${index + 1}`] = id
883
+ wrapped.push(id)
1018
884
  } else if (
1019
885
  (functionName === 'off' || functionName === 'removeListener') &&
1020
- index === 1 &&
886
+ i === 1 &&
1021
887
  typeof args[0] === 'string'
1022
888
  ) {
1023
- const id = this._removeEventSubscription(proxyId, args[0], value)
889
+ const id = this._removeEventSubscription(remoteId, args[0], x)
1024
890
  if (!id) isHandledLocally = true
1025
- data[`_${index + 1}`] = id
1026
- // Regular function callback
891
+ wrapped.push(id)
892
+ // Regular function callback
1027
893
  } else {
1028
- const id = `__f__${proxyId}-${functionName}-${index}-${this._invokeId++ % Number.MAX_SAFE_INTEGER}`
1029
- data[`_${index + 1}`] = id
1030
- this._eventEmitter.once(id, data => {
1031
- const args = Object.keys(data).sort()
1032
- .filter(x => x[0] === '_')
1033
- .map(x => data[x])
1034
- value.apply(null, args) // This is the actual function call
894
+ const id = `__f__${remoteId}-${functionName}-${i}-${this._invokeId++ %
895
+ Number.MAX_SAFE_INTEGER}`
896
+ wrapped.push(id)
897
+ this._eventEmitter.once(id, ({ a }) => {
898
+ x.apply(null, a) // This is the actual function call
1035
899
  })
1036
900
  }
1037
- } else if (this._isEmitter(value)) {
1038
- const { emitter, event } = value
1039
- const id = `__f__${proxyId}-${functionName}-${index}-${event}`
1040
- data[`_${index + 1}`] = id
1041
- this._eventEmitter.on(id, data => {
1042
- const args = Object.keys(data).sort()
1043
- .filter(x => x[0] === '_')
1044
- .map(x => data[x])
1045
- emitter.emit(event, ...args)
901
+ } else if (this._isEmitter(x)) {
902
+ const { emitter, event } = x
903
+ const id = `__f__${remoteId}-${functionName}-${i}-${event}`
904
+ wrapped.push(id)
905
+ this._eventEmitter.on(id, ({ a }) => {
906
+ emitter.emit(event, ...a)
1046
907
  })
1047
908
  } else {
1048
- data[`_${index + 1}`] = value
909
+ wrapped.push(x)
1049
910
  }
1050
911
  })
1051
912
  if (isHandledLocally) return null
1052
- return data
913
+ return wrapped
1053
914
  }
1054
915
 
1055
- _addEventSubscription (proxyId, event, callback) {
1056
- const id = `__f__${proxyId}-${event}`
916
+ _addEventSubscription (remoteId, event, callback) {
917
+ const id = `__f__${remoteId}-${event}`
1057
918
  if (this._cachedSubscriptions.has(id)) {
1058
919
  this._cachedSubscriptions.get(id).on(id, callback)
1059
920
  return
@@ -1061,17 +922,14 @@ class VrpcRemote extends EventEmitter {
1061
922
  const emitter = new EventEmitter()
1062
923
  emitter.on(id, callback)
1063
924
  this._cachedSubscriptions.set(id, emitter)
1064
- this._eventEmitter.on(id, (data) => {
1065
- const args = Object.keys(data).sort()
1066
- .filter(x => x[0] === '_')
1067
- .map(x => data[x])
1068
- emitter.emit(id, ...args)
925
+ this._eventEmitter.on(id, ({ a }) => {
926
+ emitter.emit(id, ...a)
1069
927
  })
1070
928
  return id
1071
929
  }
1072
930
 
1073
- _removeEventSubscription (proxyId, event, callback) {
1074
- const id = `__f__${proxyId}-${event}`
931
+ _removeEventSubscription (remoteId, event, callback) {
932
+ const id = `__f__${remoteId}-${event}`
1075
933
  if (this._cachedSubscriptions.has(id)) {
1076
934
  const emitter = this._cachedSubscriptions.get(id)
1077
935
  emitter.removeListener(id, callback)
@@ -1092,8 +950,10 @@ class VrpcRemote extends EventEmitter {
1092
950
  _isFunction (variable) {
1093
951
  const getType = {}
1094
952
  const type = getType.toString.call(variable)
1095
- return variable &&
953
+ return (
954
+ variable &&
1096
955
  (type === '[object Function]' || type === '[object AsyncFunction]')
956
+ )
1097
957
  }
1098
958
 
1099
959
  _isEmitter (variable) {
@@ -1106,16 +966,33 @@ class VrpcRemote extends EventEmitter {
1106
966
  )
1107
967
  }
1108
968
 
1109
- async _getInstanceData (instance, options = {}) {
969
+ async _getInstanceData (instance, options) {
1110
970
  const instanceData = this._getInstanceFromCache(instance, options)
1111
971
  if (!instanceData) {
1112
- if (options.noWait) throw new Error(`Could not find instance: ${instance}`)
972
+ if (options.noWait) {
973
+ throw new Error(`Could not find instance: ${instance}`)
974
+ }
1113
975
  return this._waitForInstance(instance, options)
1114
976
  }
1115
977
  return instanceData
1116
978
  }
1117
979
 
1118
980
  _getInstanceFromCache (instance, options = {}) {
981
+ // when no agent is specified, but an explicit class default exists give
982
+ // such instances priority in being found
983
+ if (!options.agent && this._agent !== '*') {
984
+ const { classes, status } = this._agents[this._agent]
985
+ if (!classes || status === 'offline') {
986
+ for (const className in classes) {
987
+ if (options.className && className !== options.className) continue
988
+ const { instances } = classes[className]
989
+ if (!instances) continue
990
+ if (instances.includes(instance)) {
991
+ return { agent, className, instance }
992
+ }
993
+ }
994
+ }
995
+ }
1119
996
  // loop agents
1120
997
  for (const agent in this._agents) {
1121
998
  if (options.agent && agent !== options.agent) continue
@@ -1148,7 +1025,7 @@ class VrpcRemote extends EventEmitter {
1148
1025
  * This event is fired whenever an agent is added or removed, or whenever
1149
1026
  * an agent changes its status (switches between online or offline).
1150
1027
  *
1151
- * @event VrpcRemote#agent
1028
+ * @event VrpcClient#agent
1152
1029
  * @param {Object} info
1153
1030
  * @param {String} info.domain - Domain name
1154
1031
  * @param {String} info.agent - Agent name
@@ -1163,7 +1040,7 @@ class VrpcRemote extends EventEmitter {
1163
1040
  * Emitted whenever a class is added or removed, or when instances
1164
1041
  * or functions of this class have changed.
1165
1042
  *
1166
- * @event VrpcRemote#class
1043
+ * @event VrpcClient#class
1167
1044
  * @param {Object} info
1168
1045
  * @param {String} info.domain - Domain name
1169
1046
  * @param {String} info.agent - Agent name
@@ -1175,57 +1052,57 @@ class VrpcRemote extends EventEmitter {
1175
1052
  */
1176
1053
 
1177
1054
  /**
1178
- * Event 'instanceNew'
1179
- *
1180
- * Emitted whenever a new instance was created.
1181
- *
1182
- * @event VrpcRemote#instanceNew
1183
- *
1184
- * @param {Array.<String>} addedInstances - An array of newly added instances
1185
- * @param {Object} info
1186
- * @param {String} info.domain - Domain name
1187
- * @param {String} info.agent - Agent name
1188
- * @param {String} info.className - Class name
1189
- */
1055
+ * Event 'instanceNew'
1056
+ *
1057
+ * Emitted whenever a new instance was created.
1058
+ *
1059
+ * @event VrpcClient#instanceNew
1060
+ *
1061
+ * @param {Array.<String>} addedInstances - An array of newly added instances
1062
+ * @param {Object} info
1063
+ * @param {String} info.domain - Domain name
1064
+ * @param {String} info.agent - Agent name
1065
+ * @param {String} info.className - Class name
1066
+ */
1190
1067
 
1191
1068
  /**
1192
- * Event 'instanceGone'
1193
- *
1194
- * Emitted whenever a new instance was removed.
1195
- *
1196
- * @event VrpcRemote#instanceGone
1197
- *
1198
- * @param {Array.<String>} removedInstances - An array of removed instances
1199
- * @param {Object} info
1200
- * @param {String} info.domain - Domain name
1201
- * @param {String} info.agent - Agent name
1202
- * @param {String} info.className - Class name
1203
- */
1069
+ * Event 'instanceGone'
1070
+ *
1071
+ * Emitted whenever a new instance was removed.
1072
+ *
1073
+ * @event VrpcClient#instanceGone
1074
+ *
1075
+ * @param {Array.<String>} removedInstances - An array of removed instances
1076
+ * @param {Object} info
1077
+ * @param {String} info.domain - Domain name
1078
+ * @param {String} info.agent - Agent name
1079
+ * @param {String} info.className - Class name
1080
+ */
1204
1081
 
1205
1082
  /**
1206
1083
  * Event 'connect'
1207
1084
  *
1208
1085
  * Emitted on successful (re)connection (i.e. connack rc=0).
1209
1086
  *
1210
- * @event VrpcRemote#connect
1087
+ * @event VrpcClient#connect
1211
1088
  * @type {Object}
1212
1089
  * @property {Boolean} sessionPresent - A session from a previous connection is already present
1213
- */
1090
+ */
1214
1091
 
1215
1092
  /**
1216
1093
  * Event 'reconnect'
1217
1094
  *
1218
1095
  * Emitted when a reconnect starts.
1219
1096
  *
1220
- * @event VrpcRemote#reconnect
1221
- */
1097
+ * @event VrpcClient#reconnect
1098
+ */
1222
1099
 
1223
1100
  /**
1224
1101
  * Event 'close'
1225
1102
  *
1226
1103
  * Emitted after a disconnection.
1227
1104
  *
1228
- * @event VrpcRemote#close
1105
+ * @event VrpcClient#close
1229
1106
  */
1230
1107
 
1231
1108
  /**
@@ -1233,7 +1110,7 @@ class VrpcRemote extends EventEmitter {
1233
1110
  *
1234
1111
  * Emitted when the client goes offline.
1235
1112
  *
1236
- * @event VrpcRemote#offline
1113
+ * @event VrpcClient#offline
1237
1114
  */
1238
1115
 
1239
1116
  /**
@@ -1248,7 +1125,7 @@ class VrpcRemote extends EventEmitter {
1248
1125
  * - EADDRINUSE
1249
1126
  * - ENOTFOUND
1250
1127
  *
1251
- * @event VrpcRemote#error
1128
+ * @event VrpcClient#error
1252
1129
  * @type {Object} Error
1253
1130
  */
1254
1131
 
@@ -1258,7 +1135,7 @@ class VrpcRemote extends EventEmitter {
1258
1135
  * Emitted when mqtt.Client#end() is called. If a callback was passed to
1259
1136
  * mqtt.Client#end(), this event is emitted once the callback returns.
1260
1137
  *
1261
- * @event VrpcRemote#end
1138
+ * @event VrpcClient#end
1262
1139
  */
1263
1140
 
1264
- module.exports = VrpcRemote
1141
+ module.exports = VrpcClient