vrpc 2.5.0 → 3.0.0-alpha.2

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>.
@@ -42,7 +42,6 @@ const path = require('path')
42
42
  const fs = require('fs')
43
43
  const Ajv = require('ajv')
44
44
  const caller = require('caller')
45
- const shortid = require('shortid')
46
45
  const commentParser = require('./comment-parser')
47
46
  const EventEmitter = require('events')
48
47
 
@@ -125,7 +124,7 @@ class VrpcAdapter {
125
124
  * @param {Object} obj The instance to be registered
126
125
  * @param {Object} options
127
126
  * @param {String} options.className Class name of the instance
128
- * @param {Boolean} options.instance Name of the instance
127
+ * @param {String} options.instance Name of the instance
129
128
  * @param {Boolean} [options.onlyPublic=true] If true, only registers
130
129
  * functions that do not begin with an underscore
131
130
  * @param {String} [options.jsdocPath] if provided, parses documentation and
@@ -137,7 +136,9 @@ class VrpcAdapter {
137
136
  ) {
138
137
  let memberFunctions = VrpcAdapter._extractMemberFunctions(obj)
139
138
  if (onlyPublic) {
140
- memberFunctions = memberFunctions.filter(f => !f.startsWith('_'))
139
+ memberFunctions = memberFunctions.filter(f => {
140
+ return !f.startsWith('_')
141
+ })
141
142
  }
142
143
  let meta = null
143
144
  if (jsdocPath) {
@@ -150,10 +151,14 @@ class VrpcAdapter {
150
151
  meta,
151
152
  Klass: {},
152
153
  withNew: false,
153
- staticFunctions: ['__getNamed__'],
154
+ staticFunctions: [],
154
155
  schema: null
155
156
  })
156
- VrpcAdapter._instances.set(instance, { className, instance: obj })
157
+ VrpcAdapter._instances.set(instance, {
158
+ className,
159
+ instance: obj,
160
+ isIsolated: false
161
+ })
157
162
  }
158
163
 
159
164
  static getClasses () {
@@ -298,14 +303,14 @@ class VrpcAdapter {
298
303
  * @typedef {Object.<String, Func>} MetaData Associates meta data to any function
299
304
  */
300
305
 
301
- /**
302
- * @typedef Func
303
- * @param {String} description Function description
304
- * @param {Array.<Param>} params Array of parameter details in order of signature
305
- * @param {Ret} ret Object associating further information to return value
306
- */
306
+ /**
307
+ * @typedef Func
308
+ * @param {String} description Function description
309
+ * @param {Array.<Param>} params Array of parameter details in order of signature
310
+ * @param {Ret} ret Object associating further information to return value
311
+ */
307
312
 
308
- /**
313
+ /**
309
314
  * @typedef {Object} Param
310
315
  * @param {String} name Parameter name
311
316
  * @param {Boolean} optional Whether parameter is optional
@@ -314,12 +319,11 @@ class VrpcAdapter {
314
319
  * @param {Any} [default] The default to be injected when not provided
315
320
  */
316
321
 
317
- /**
318
- * @typedef {Object} Ret
319
- * @param {String} description Return value description
320
- * @param {String} [type] Return value type
321
- */
322
-
322
+ /**
323
+ * @typedef {Object} Ret
324
+ * @param {String} description Return value description
325
+ * @param {String} [type] Return value type
326
+ */
323
327
 
324
328
  static on (eventName, listener) {
325
329
  VrpcAdapter._emitter.on(eventName, listener)
@@ -342,12 +346,7 @@ class VrpcAdapter {
342
346
  static _registerClass (
343
347
  Klass,
344
348
  absJsdocPath = null,
345
- {
346
- onlyPublic = true,
347
- withNew = true,
348
- schema = null,
349
- jsdoc = true
350
- } = {}
349
+ { onlyPublic = true, withNew = true, schema = null, jsdoc = true } = {}
351
350
  ) {
352
351
  // Get all static static functions
353
352
  let staticFunctions = VrpcAdapter._extractStaticFunctions(Klass)
@@ -355,24 +354,29 @@ class VrpcAdapter {
355
354
  staticFunctions = staticFunctions.filter(f => !f.startsWith('_'))
356
355
  }
357
356
  // Inject constructor and destructor
358
- staticFunctions.push('__create__')
359
- staticFunctions.push('__delete__')
360
- staticFunctions.push('__createNamed__')
361
- staticFunctions.push('__getNamed__')
357
+ staticFunctions.push('__createIsolated__')
358
+ staticFunctions.push('__createShared__')
362
359
  staticFunctions.push('__callAll__')
360
+ staticFunctions.push('__delete__')
363
361
  let memberFunctions = VrpcAdapter._extractMemberFunctions(Klass)
364
362
  if (onlyPublic) {
365
- memberFunctions = memberFunctions.filter(f => !f.startsWith('_'))
363
+ memberFunctions = memberFunctions.filter(f => {
364
+ return !f.startsWith('_')
365
+ })
366
366
  }
367
367
  let meta = null
368
368
  if (jsdoc && absJsdocPath) {
369
369
  const content = fs.readFileSync(absJsdocPath).toString('utf8')
370
370
  meta = this._parseComments(content)
371
371
  }
372
- VrpcAdapter._functionRegistry.set(
373
- Klass.name,
374
- { Klass, withNew, staticFunctions, memberFunctions, schema, meta }
375
- )
372
+ VrpcAdapter._functionRegistry.set(Klass.name, {
373
+ Klass,
374
+ withNew,
375
+ staticFunctions,
376
+ memberFunctions,
377
+ schema,
378
+ meta
379
+ })
376
380
  }
377
381
 
378
382
  static _parseComments (content) {
@@ -381,7 +385,9 @@ class VrpcAdapter {
381
385
  comments.forEach(({ tags, description, functionName }) => {
382
386
  if (functionName) {
383
387
  if (tags) {
384
- let params = tags.filter(({ tag }) => tag === 'param' || tag === 'arg' || tag === 'argument')
388
+ let params = tags.filter(
389
+ ({ tag }) => tag === 'param' || tag === 'arg' || tag === 'argument'
390
+ )
385
391
  if (params.length > 0) {
386
392
  params = params.map(({ name, optional, description, type }) => {
387
393
  return { name, optional, description, type }
@@ -389,10 +395,15 @@ class VrpcAdapter {
389
395
  } else {
390
396
  params = []
391
397
  }
392
- let ret = tags.filter(({ tag }) => tag === 'returns' || tag === 'return')
398
+ let ret = tags.filter(
399
+ ({ tag }) => tag === 'returns' || tag === 'return'
400
+ )
393
401
  if (ret.length === 1) {
394
402
  const { source, type } = ret[0]
395
- const description = source.split(' ').splice(2).join(' ')
403
+ const description = source
404
+ .split(' ')
405
+ .splice(2)
406
+ .join(' ')
396
407
  ret = { description, type }
397
408
  } else {
398
409
  ret = null
@@ -407,7 +418,7 @@ class VrpcAdapter {
407
418
  },
408
419
  ...params
409
420
  ]
410
- meta.__createNamed__ = { description, params: modified, ret }
421
+ meta.__createShared__ = { description, params: modified, ret }
411
422
  } else {
412
423
  meta[functionName] = { description, params, ret }
413
424
  }
@@ -418,133 +429,151 @@ class VrpcAdapter {
418
429
  }
419
430
 
420
431
  static _call (json) {
421
- const { context, method, data } = json
422
- const wrappedArgs = VrpcAdapter._wrapCallbacks(json)
423
- // VrpcAdapter._log.debug(`Calling function: ${method} with payload: ${data}`)
424
- switch (method) {
425
- // Special case: ctor
426
- case '__create__':
427
- try {
428
- const instance = VrpcAdapter._create(context, ...wrappedArgs)
429
- const instanceId = shortid.generate()
430
- VrpcAdapter._instances.set(instanceId, { context, instance })
431
- data.r = instanceId
432
- } catch (err) {
433
- data.e = err.message
434
- }
432
+ const before = Object.keys(VrpcAdapter._listeners).length
433
+ switch (json.f) {
434
+ case '__createIsolated__':
435
+ VrpcAdapter._handleCreateIsolated(json)
436
+ break
437
+ case '__createShared__':
438
+ VrpcAdapter._handleCreateShared(json)
439
+ break
440
+ case '__callAll__':
441
+ VrpcAdapter._handleCallAll(json)
435
442
  break
436
- // Special case: dtor
437
443
  case '__delete__':
438
- try {
439
- const instanceId = wrappedArgs[0]
440
- data.r = VrpcAdapter._delete(instanceId)
441
- VrpcAdapter._emitter.emit('delete', {
442
- className: context,
443
- instance: wrappedArgs[0]
444
- })
445
- } catch (err) {
446
- data.e = err.message
447
- }
444
+ VrpcAdapter._handleDelete(json)
448
445
  break
449
- // Special case: named construction
450
- case '__createNamed__':
446
+ default:
447
+ VrpcAdapter._handleCall(json)
448
+ }
449
+ const after = Object.keys(VrpcAdapter._listeners).length
450
+ // if we took a listener on board we must tell our caller such that
451
+ // things can be cleaned up later.
452
+ return after > before
453
+ }
454
+
455
+ static _handleCreateIsolated (json) {
456
+ try {
457
+ const className = json.c
458
+ const [instanceId, ...args] = json.a
459
+ const instance = VrpcAdapter._create(className, instanceId, ...args)
460
+ VrpcAdapter._instances.set(instanceId, {
461
+ instance,
462
+ className,
463
+ isIsolated: true
464
+ })
465
+ json.r = instanceId
466
+ } catch (err) {
467
+ json.e = err.message
468
+ }
469
+ }
470
+
471
+ static _handleCreateShared (json) {
472
+ try {
473
+ const className = json.c
474
+ const [instanceId, ...args] = json.a
475
+ const instance = VrpcAdapter._create(className, instanceId, ...args)
476
+ VrpcAdapter._instances.set(instanceId, {
477
+ instance,
478
+ className,
479
+ isIsolated: false
480
+ })
481
+ json.r = instanceId
482
+ } catch (err) {
483
+ json.e = err.message
484
+ }
485
+ }
486
+
487
+ static _handleCallAll (json) {
488
+ try {
489
+ const calls = []
490
+ for (const [id, { className, instance }] of VrpcAdapter._instances) {
491
+ if (className !== json.c) continue
492
+ let v
493
+ let e = null
451
494
  try {
452
- VrpcAdapter._createNamed(context, ...wrappedArgs)
453
- data.r = wrappedArgs[0] // First argument is instanceId
454
- VrpcAdapter._emitter.emit('create', {
455
- className: context,
456
- instance: wrappedArgs[0],
457
- args: wrappedArgs.slice(1)
458
- })
495
+ const wrappedArgs = VrpcAdapter._wrapArguments(json, id)
496
+ const funcName = wrappedArgs[0]
497
+ v = instance[funcName].apply(instance, wrappedArgs.slice(1))
459
498
  } catch (err) {
460
- data.e = err.message
499
+ e = err.message
461
500
  }
462
- break
463
- case '__getNamed__': // Special case: retrieval of known instance
501
+ if (VrpcAdapter._isPromise(v)) {
502
+ calls.push(
503
+ v
504
+ .then(val => ({ id, val, err: null }))
505
+ .catch(err => ({ id, err, val: null }))
506
+ )
507
+ } else {
508
+ calls.push({ id, val: v, err: e })
509
+ }
510
+ }
511
+ this._handlePromise(json, Promise.all(calls))
512
+ } catch (err) {
513
+ json.e = err.message
514
+ }
515
+ }
516
+
517
+ static _handleDelete (json) {
518
+ try {
519
+ const wrappedArgs = VrpcAdapter._wrapArguments(json)
520
+ const instanceId = wrappedArgs[0]
521
+ json.r = VrpcAdapter._delete(instanceId)
522
+ VrpcAdapter._emitter.emit('delete', {
523
+ className: json.c,
524
+ instance: wrappedArgs[0]
525
+ })
526
+ } catch (err) {
527
+ json.e = err.message
528
+ }
529
+ }
530
+
531
+ static _handleCall (json) {
532
+ const wrappedArgs = VrpcAdapter._wrapArguments(json)
533
+ // Check whether context is a registered class
534
+ const entry = VrpcAdapter._functionRegistry.get(json.c)
535
+ if (entry !== undefined) {
536
+ // entry is class -> function is static
537
+ const { Klass } = entry
538
+ // TODO Think about whether to do live checking (like here) or
539
+ // rather sticking to those functions registered before...
540
+ // TODO This is even more important now as the agent does a wildcard
541
+ // subscription against all functions
542
+ if (VrpcAdapter._isFunction(Klass[json.f])) {
464
543
  try {
465
- const instanceId = wrappedArgs[0]
466
- const entry = VrpcAdapter._instances.get(instanceId)
467
- if (entry) data.r = instanceId
468
- else data.e = `Instance with id: ${instanceId} does not exist`
544
+ const ret = Klass[json.f].apply(null, wrappedArgs)
545
+ // check if function returns promise
546
+ if (VrpcAdapter._isPromise(ret)) {
547
+ this._handlePromise(json, ret)
548
+ } else json.r = ret
469
549
  } catch (err) {
470
- data.e = err.message
550
+ json.e = err.message
471
551
  }
472
- break
473
- case '__callAll__': // Special case: call on all known instances
552
+ } else throw new Error(`Could not find function: ${json.f}`)
553
+ } else {
554
+ // is not static
555
+ const entry = VrpcAdapter._instances.get(json.c)
556
+ if (entry === undefined) {
557
+ throw new Error(`Could not find context: ${json.c}`)
558
+ }
559
+ const { instance } = entry
560
+ if (VrpcAdapter._isFunction(instance[json.f])) {
474
561
  try {
475
- const funcName = wrappedArgs[0]
476
- const calls = []
477
- for (const [id, { className, instance }] of VrpcAdapter._instances) {
478
- if (className !== context) continue
479
- let v
480
- let e = null
481
- try {
482
- v = instance[funcName].apply(instance, wrappedArgs.slice(1))
483
- } catch (err) {
484
- e = err
485
- }
486
- // check wether function returned a promise
487
- if (VrpcAdapter._isPromise(v)) {
488
- calls.push(
489
- v
490
- .then((val) => ({ id, val, err: null }))
491
- .catch((err) => ({ id, err, val: null }))
492
- )
493
- } else {
494
- calls.push({ id, val: v, err: e })
495
- }
496
- }
497
- this._handlePromise(json, method, Promise.all(calls))
562
+ const ret = instance[json.f].apply(instance, wrappedArgs)
563
+ // check if function returns promise
564
+ if (VrpcAdapter._isPromise(ret)) {
565
+ this._handlePromise(json, ret)
566
+ } else json.r = ret
498
567
  } catch (err) {
499
- data.e = err.message
500
- }
501
- break
502
- // Regular function call
503
- default: {
504
- // Check whether context is a registered class
505
- const entry = VrpcAdapter._functionRegistry.get(context)
506
- if (entry !== undefined) {
507
- // entry is class -> function is static
508
- const { Klass } = entry
509
- // TODO Think about whether to do live checking (like here) or
510
- // rather sticking to those functions registered before...
511
- // TODO This is even more important now as the agent does a wildcard
512
- // subscription against all functions
513
- if (VrpcAdapter._isFunction(Klass[method])) {
514
- try {
515
- const ret = Klass[method].apply(null, wrappedArgs)
516
- // check if function returns promise
517
- if (ret && this._isFunction(ret.then)) {
518
- this._handlePromise(json, method, ret)
519
- } else data.r = ret
520
- } catch (err) {
521
- data.e = err.message
522
- }
523
- } else throw new Error(`Could not find function: ${method}`)
524
- } else {
525
- // is not static
526
- const entry = VrpcAdapter._instances.get(context)
527
- if (entry === undefined) {
528
- throw new Error(`Could not find context: ${context}`)
529
- }
530
- const { instance } = entry
531
- if (VrpcAdapter._isFunction(instance[method])) {
532
- try {
533
- const ret = instance[method].apply(instance, wrappedArgs)
534
- // check if function returns promise
535
- if (VrpcAdapter._isPromise(ret)) {
536
- this._handlePromise(json, method, ret)
537
- } else data.r = ret
538
- } catch (err) {
539
- data.e = err.message
540
- }
541
- } else throw new Error(`Could not find function: ${method}`)
568
+ json.e = err.message
542
569
  }
543
- }
570
+ } else throw new Error(`Could not find function: ${json.f}`)
544
571
  }
545
572
  }
546
573
 
547
- static _create (className, ...args) {
574
+ static _create (className, instanceId, ...args) {
575
+ const entry = VrpcAdapter._instances.get(instanceId)
576
+ if (entry) return entry.instance
548
577
  const { Klass, withNew, schema } = VrpcAdapter._getClassEntry(className)
549
578
  if (schema !== null) {
550
579
  VrpcAdapter._validate(schema, ...args)
@@ -553,16 +582,6 @@ class VrpcAdapter {
553
582
  return Klass(...args)
554
583
  }
555
584
 
556
- static _createNamed (className, instanceId, ...args) {
557
- const entry = VrpcAdapter._instances.get(instanceId)
558
- if (!entry) {
559
- const instance = VrpcAdapter._create(className, ...args)
560
- VrpcAdapter._instances.set(instanceId, { className, instance })
561
- return instance
562
- }
563
- return entry.instance
564
- }
565
-
566
585
  static _delete (instanceId) {
567
586
  const entry = VrpcAdapter._instances.get(instanceId)
568
587
  if (entry) {
@@ -582,6 +601,18 @@ class VrpcAdapter {
582
601
  delete VrpcAdapter._listeners[clientId]
583
602
  }
584
603
 
604
+ static _unregisterEventListenersOfInstance (instance) {
605
+ for (const [key, value] of Object.entries(VrpcAdapter._listeners)) {
606
+ VrpcAdapter._listeners[key] = value.filter(({ i, e, f }) => {
607
+ if (instance === i) {
608
+ VrpcAdapter.getInstance(i).removeListener(e, f)
609
+ return false
610
+ }
611
+ return true
612
+ })
613
+ }
614
+ }
615
+
585
616
  static _validate (schema, params) {
586
617
  if (!VrpcAdapter._ajv) {
587
618
  VrpcAdapter._ajv = new Ajv({ useDefaults: true })
@@ -590,95 +621,71 @@ class VrpcAdapter {
590
621
  if (!valid) throw new Error(VrpcAdapter._ajv.errorsText())
591
622
  }
592
623
 
593
- static _wrapCallbacks (json) {
594
- const { method, sender, data, context } = json
595
- const args = VrpcAdapter._extractDataToArray(data)
596
- const wrappedArgs = []
624
+ static _wrapArguments (json, instanceId) {
625
+ const { f: func, s: sender, a: args, c: context } = json
626
+ const wrapped = []
597
627
  args.forEach(arg => {
598
628
  // Find those args that actually need to be function callbacks
599
629
  if (typeof arg === 'string' && arg.substr(0, 5) === '__f__') {
600
- const f = (...innerArgs) => {
601
- // do not even trigger a callback for already offline clients
602
- if (sender && !VrpcAdapter._listeners[sender]) return
603
- const data = {}
604
- innerArgs.forEach((value, index) => {
605
- data[`_${index + 1}`] = value
606
- })
607
- const callbackJson = Object.assign({}, json, { data, id: arg })
608
- const callbackJsonString = VrpcAdapter._stringifySafely(callbackJson)
609
- VrpcAdapter._callback(callbackJsonString, callbackJson)
610
- }
611
- wrappedArgs.push(f)
630
+ const f = this._generateWrapper(arg, json, instanceId)
631
+ wrapped.push(f)
612
632
  if (!sender) return
613
633
  // Register this client to later know when he is dead and skip callbacks
614
634
  if (!VrpcAdapter._listeners[sender]) VrpcAdapter._listeners[sender] = []
615
635
  // Check whether injected callback is an EventEmitter registration
616
- if (method === 'on' && typeof args[0] === 'string') {
636
+ if (func === 'on' && typeof args[0] === 'string') {
617
637
  const e = args[0]
618
638
  const i = context
619
639
  const r = arg
620
640
  VrpcAdapter._listeners[sender].push({ i, e, f, r })
621
641
  }
622
- if ((method === 'off' || method === 'removeListener') &&
623
- typeof args[0] === 'string') {
624
- const r = arg
625
- const s = VrpcAdapter._listeners[sender]
626
- const entry = s && s.find(x => x.r === r)
642
+ if (
643
+ (func === 'off' || func === 'removeListener') &&
644
+ typeof args[0] === 'string'
645
+ ) {
646
+ const listener = VrpcAdapter._listeners[sender]
647
+ const entry = listener && listener.find(x => x.r === arg)
627
648
  if (entry) {
628
649
  const { i, e, f } = entry
629
650
  VrpcAdapter.getInstance(i).removeListener(e, f)
630
651
  }
631
652
  }
632
- } else { // Leave the others untouched
633
- wrappedArgs.push(arg)
653
+ } else {
654
+ // Leave the others untouched
655
+ wrapped.push(arg)
634
656
  }
635
657
  })
636
- return wrappedArgs
658
+ return wrapped
637
659
  }
638
660
 
639
- static _handlePromise (json, method, promise) {
640
- try {
641
- const cid = VrpcAdapter._correlationId++ % Number.MAX_SAFE_INTEGER
642
- const id = `__p__${method}-${cid}`
643
- json.data.r = id
644
- promise
645
- .then(value => {
646
- const data = { r: value }
647
- const promiseJson = Object.assign({}, json, { data, id })
648
- const promiseJsonString = VrpcAdapter._stringifySafely(promiseJson)
649
- VrpcAdapter._callback(promiseJsonString, promiseJson)
650
- })
651
- .catch(err => {
652
- const data = { e: err.message }
653
- const promiseJson = Object.assign({}, json, { data, id })
654
- const promiseJsonString = VrpcAdapter._stringifySafely(promiseJson)
655
- VrpcAdapter._callback(promiseJsonString, promiseJson)
656
- })
657
- } catch (err) {
658
- json.data.e = err.message
661
+ static _generateWrapper (id, json, instanceId) {
662
+ const wrapper = (...innerArgs) => {
663
+ // do not even trigger a callback for already offline clients
664
+ if (json.s && !VrpcAdapter._listeners[json.s]) return
665
+ const a = instanceId ? [instanceId, ...innerArgs] : [...innerArgs]
666
+ VrpcAdapter._callback({ a, s: json.s, f: json.f, i: id })
659
667
  }
668
+ return wrapper
660
669
  }
661
670
 
662
- static _stringifySafely (json) {
663
- let jsonString
671
+ static _handlePromise (json, promise) {
664
672
  try {
665
- jsonString = JSON.stringify(json)
673
+ const cid = VrpcAdapter._correlationId++ % Number.MAX_SAFE_INTEGER
674
+ const id = `__p__${json.f}-${cid}`
675
+ json.r = id
676
+ promise
677
+ .then(r => VrpcAdapter._callback({ ...json, r, i: id }))
678
+ .catch(err => VrpcAdapter._callback({ ...json, e: err.message, i: id }))
666
679
  } catch (err) {
667
- this._log.debug(`Failed serialization of return value for: ${json.context}::${json.method}, because: ${err.message}`)
668
- json.data.r = '__vrpc::not-serializable__'
669
- jsonString = JSON.stringify(json)
680
+ json.data.e = err.message
670
681
  }
671
- return jsonString
672
- }
673
-
674
- static _extractDataToArray (data) {
675
- return Object.keys(data).sort()
676
- .filter(value => value[0] === '_')
677
- .map(key => data[key])
678
682
  }
679
683
 
680
684
  static _generateId (object) {
681
- return crypto.createHash('md5').update(JSON.stringify(object)).digest('hex')
685
+ return crypto
686
+ .createHash('md5')
687
+ .update(JSON.stringify(object))
688
+ .digest('hex')
682
689
  }
683
690
 
684
691
  static _getClassEntry (className) {
@@ -698,11 +705,17 @@ class VrpcAdapter {
698
705
  }
699
706
 
700
707
  static _isClass (obj) {
701
- return !!obj && (typeof obj === 'function' && /^\s*class\s+/.test(obj.toString()))
708
+ return (
709
+ !!obj && typeof obj === 'function' && /^\s*class\s+/.test(obj.toString())
710
+ )
702
711
  }
703
712
 
704
713
  static _isPromise (obj) {
705
- return !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function'
714
+ return (
715
+ !!obj &&
716
+ (typeof obj === 'object' || typeof obj === 'function') &&
717
+ typeof obj.then === 'function'
718
+ )
706
719
  }
707
720
 
708
721
  static _extractMemberFunctions (klass) {
@@ -710,12 +723,20 @@ class VrpcAdapter {
710
723
  let fs = []
711
724
  do {
712
725
  if (klass_.prototype) {
713
- fs = [...fs, ...Object.getOwnPropertyNames(klass_.prototype)]
726
+ const funcs = Object.getOwnPropertyNames(klass_.prototype).filter(
727
+ x =>
728
+ !VrpcAdapter._blackList.has(x) &&
729
+ this._isFunction(klass_.prototype[x])
730
+ )
731
+ fs = [...fs, ...funcs]
714
732
  } else {
715
- fs = [...fs, ...Object.getOwnPropertyNames(klass_)]
733
+ const funcs = Object.getOwnPropertyNames(klass_).filter(
734
+ x => !VrpcAdapter._blackList.has(x) && this._isFunction(klass_[x])
735
+ )
736
+ fs = [...fs, ...funcs]
716
737
  }
717
738
  klass_ = Object.getPrototypeOf(klass_)
718
- } while (klass_ && klass_.name)
739
+ } while (klass_)
719
740
  // Filter out all duplicates
720
741
  return Array.from(new Set(fs))
721
742
  }
@@ -724,10 +745,13 @@ class VrpcAdapter {
724
745
  let klass_ = klass
725
746
  let fs = []
726
747
  do {
727
- fs = [...fs, ...Object.getOwnPropertyNames(klass_).filter(prop => {
728
- const desc = Object.getOwnPropertyDescriptor(klass_, prop)
729
- return !!desc && typeof desc.value === 'function'
730
- })]
748
+ fs = [
749
+ ...fs,
750
+ ...Object.getOwnPropertyNames(klass_).filter(prop => {
751
+ const desc = Object.getOwnPropertyDescriptor(klass_, prop)
752
+ return !!desc && typeof desc.value === 'function'
753
+ })
754
+ ]
731
755
  klass_ = Object.getPrototypeOf(klass_)
732
756
  } while (klass_ && klass_.name)
733
757
  // Filter out all duplicates
@@ -740,8 +764,8 @@ class VrpcAdapter {
740
764
 
741
765
  static _getInstancesArray (className) {
742
766
  const instances = []
743
- VrpcAdapter._instances.forEach((value, key) => {
744
- if (value.className === className) instances.push(key)
767
+ VrpcAdapter._instances.forEach((v, k) => {
768
+ if (v.className === className && !v.isIsolated) instances.push(k)
745
769
  })
746
770
  return instances
747
771
  }
@@ -775,7 +799,7 @@ class VrpcAdapter {
775
799
  * @property {String} className The class name of the create instance
776
800
  * @property {String} instance The instance name
777
801
  * @property {Array.<Any>} args The constructor arguments
778
- */
802
+ */
779
803
 
780
804
  /**
781
805
  * Event 'delete'
@@ -786,7 +810,7 @@ class VrpcAdapter {
786
810
  * @type {Object}
787
811
  * @property {String} className The class name of the deleted instance
788
812
  * @property {String} instance The instance name
789
- */
813
+ */
790
814
 
791
815
  // Initialize static members
792
816
  VrpcAdapter._functionRegistry = new Map()
@@ -794,5 +818,23 @@ VrpcAdapter._instances = new Map()
794
818
  VrpcAdapter._emitter = new EventEmitter()
795
819
  VrpcAdapter._correlationId = 0
796
820
  VrpcAdapter._listeners = {}
821
+ VrpcAdapter._blackList = new Set([
822
+ 'caller',
823
+ 'callee',
824
+ 'arguments',
825
+ 'apply',
826
+ 'bind',
827
+ 'call',
828
+ 'toString',
829
+ 'hasOwnProperty',
830
+ 'isPrototypeOf',
831
+ 'propertyIsEnumerable',
832
+ 'valueOf',
833
+ 'toLocaleString',
834
+ '__defineGetter__',
835
+ '__defineSetter__',
836
+ '__lookupGetter__',
837
+ '__lookupSetter__'
838
+ ])
797
839
 
798
840
  module.exports = VrpcAdapter