vrpc 2.6.0 → 3.0.0-alpha.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/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict'
2
2
  module.exports = {
3
- VrpcLocal: require('./vrpc/VrpcLocal'),
4
- VrpcRemote: require('./vrpc/VrpcRemote'),
3
+ VrpcNative: require('./vrpc/VrpcNative'),
4
+ VrpcClient: require('./vrpc/VrpcClient'),
5
5
  VrpcAdapter: require('./vrpc/VrpcAdapter'),
6
6
  VrpcAgent: require('./vrpc/VrpcAgent')
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vrpc",
3
- "version": "2.6.0",
3
+ "version": "3.0.0-alpha.1",
4
4
  "description": "Variadic Remote Procedure Calls",
5
5
  "main": "index.js",
6
6
  "directories": {
@@ -9,18 +9,15 @@
9
9
  "test": "test"
10
10
  },
11
11
  "scripts": {
12
- "build": "ln -sf binding.gyp.no-auto binding.gyp && third_party/install.sh && node-gyp rebuild && rm binding.gyp",
13
- "test": "npm run test:cpp && npm run test:jsLocal && npm run test:jsRemote && npm run test:jsRemoteClient && npm run test:jsAgent",
14
- "test:cpp": "build/Release/vrpc-test",
15
- "test:jsLocal": "./node_modules/.bin/mocha test/js/local/*.js --exit",
16
- "test:jsRemote": "./node_modules/.bin/mocha test/js/remote/lifeCycleTest.js --timeout 30000 --exit && test/js/remote/test.sh",
17
- "test:jsRemoteClient": "test/js/remoteClient/test.sh",
18
- "test:jsAgent": "test/js/agent/test.sh",
19
- "test:jsPerformance": "test/js/performance/test.sh",
20
- "build:pydoc": "pydoc-markdown -I vrpc -m VrpcLocal --render-toc > docs/reference/python.md",
21
- "build:jsdoc": "./node_modules/.bin/jsdoc2md -f vrpc/*.js --param-list-format=list --separators > docs/reference/nodeJs.md",
22
- "build:doc": "npm run build:pydoc; npm run build:jsdoc",
23
- "build:browser": "./node_modules/.bin/webpack"
12
+ "build:addon": "ln -sf binding.gyp.no-auto binding.gyp && node-gyp rebuild && rm binding.gyp",
13
+ "build:browser": "./node_modules/.bin/webpack",
14
+ "build:doc": "./node_modules/.bin/jsdoc2md -f vrpc/*.js --param-list-format=list --separators > docs/api.md",
15
+ "test": "npm run test:agent && npm run test:client && npm run test:native",
16
+ "test:agent": "tests/agent/test.sh",
17
+ "test:client": "tests/client/test.sh",
18
+ "test:native": "./node_modules/.bin/mocha tests/native/vrpc-native*.js --exit",
19
+ "test:performance": "tests/performance/test.sh",
20
+ "test:production": "./node_modules/.bin/mocha tests/production/lifeCycleTest.js --timeout 30000 --exit && tests/production/test.sh"
24
21
  },
25
22
  "bin": {
26
23
  "vrpc-agent-js": "./vrpc/vrpc-agent-js"
@@ -34,7 +31,7 @@
34
31
  "remote procedural calls",
35
32
  "language binding",
36
33
  "C++",
37
- "C++ binding",
34
+ "C++ embedding",
38
35
  "header-only"
39
36
  ],
40
37
  "repository": {
@@ -62,7 +59,6 @@
62
59
  },
63
60
  "files": [
64
61
  "vrpc/",
65
- "third_party/",
66
62
  "browser/",
67
63
  "binding.gyp.no-auto"
68
64
  ],
@@ -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 { nanoid } = require('nanoid')
46
45
  const commentParser = require('./comment-parser')
47
46
  const EventEmitter = require('events')
48
47
 
@@ -152,10 +151,14 @@ class VrpcAdapter {
152
151
  meta,
153
152
  Klass: {},
154
153
  withNew: false,
155
- staticFunctions: ['__getNamed__'],
154
+ staticFunctions: [],
156
155
  schema: null
157
156
  })
158
- VrpcAdapter._instances.set(instance, { className, instance: obj })
157
+ VrpcAdapter._instances.set(instance, {
158
+ className,
159
+ instance: obj,
160
+ isIsolated: false
161
+ })
159
162
  }
160
163
 
161
164
  static getClasses () {
@@ -351,11 +354,10 @@ class VrpcAdapter {
351
354
  staticFunctions = staticFunctions.filter(f => !f.startsWith('_'))
352
355
  }
353
356
  // Inject constructor and destructor
354
- staticFunctions.push('__create__')
355
- staticFunctions.push('__delete__')
356
- staticFunctions.push('__createNamed__')
357
- staticFunctions.push('__getNamed__')
357
+ staticFunctions.push('__createIsolated__')
358
+ staticFunctions.push('__createShared__')
358
359
  staticFunctions.push('__callAll__')
360
+ staticFunctions.push('__delete__')
359
361
  let memberFunctions = VrpcAdapter._extractMemberFunctions(Klass)
360
362
  if (onlyPublic) {
361
363
  memberFunctions = memberFunctions.filter(f => {
@@ -416,7 +418,7 @@ class VrpcAdapter {
416
418
  },
417
419
  ...params
418
420
  ]
419
- meta.__createNamed__ = { description, params: modified, ret }
421
+ meta.__createShared__ = { description, params: modified, ret }
420
422
  } else {
421
423
  meta[functionName] = { description, params, ret }
422
424
  }
@@ -427,91 +429,61 @@ class VrpcAdapter {
427
429
  }
428
430
 
429
431
  static _call (json) {
430
- const { method } = json
431
- switch (method) {
432
- case '__create__':
433
- VrpcAdapter._handleCreate(json)
434
- break
435
- case '__delete__':
436
- VrpcAdapter._handleDelete(json)
432
+ switch (json.f) {
433
+ case '__createIsolated__':
434
+ VrpcAdapter._handleCreateIsolated(json)
437
435
  break
438
- case '__createNamed__':
439
- VrpcAdapter._handleCreateNamed(json)
440
- break
441
- case '__getNamed__':
442
- VrpcAdapter._handleGetNamed(json)
436
+ case '__createShared__':
437
+ VrpcAdapter._handleCreateShared(json)
443
438
  break
444
439
  case '__callAll__':
445
440
  VrpcAdapter._handleCallAll(json)
446
441
  break
442
+ case '__delete__':
443
+ VrpcAdapter._handleDelete(json)
444
+ break
447
445
  default:
448
446
  VrpcAdapter._handleCall(json)
449
447
  }
450
448
  }
451
449
 
452
- static _handleCreate (json) {
453
- const { context, data } = json
450
+ static _handleCreateIsolated (json) {
454
451
  try {
455
- const wrappedArgs = VrpcAdapter._wrapArguments(json)
456
- const instance = VrpcAdapter._create(context, ...wrappedArgs)
457
- const instanceId = nanoid(9)
458
- VrpcAdapter._instances.set(instanceId, { context, instance })
459
- data.r = instanceId
460
- } catch (err) {
461
- data.e = err.message
462
- }
463
- }
464
-
465
- static _handleDelete (json) {
466
- const { context, data } = json
467
- try {
468
- const wrappedArgs = VrpcAdapter._wrapArguments(json)
469
- const instanceId = wrappedArgs[0]
470
- data.r = VrpcAdapter._delete(instanceId)
471
- VrpcAdapter._emitter.emit('delete', {
472
- className: context,
473
- instance: wrappedArgs[0]
452
+ const className = json.c
453
+ const [instanceId, ...args] = json.a
454
+ const instance = VrpcAdapter._create(className, instanceId, ...args)
455
+ VrpcAdapter._instances.set(instanceId, {
456
+ instance,
457
+ className,
458
+ isIsolated: true
474
459
  })
460
+ json.r = instanceId
475
461
  } catch (err) {
476
- data.e = err.message
462
+ json.e = err.message
477
463
  }
478
464
  }
479
465
 
480
- static _handleCreateNamed (json) {
481
- const { context, data } = json
466
+ static _handleCreateShared (json) {
482
467
  try {
483
- const wrappedArgs = VrpcAdapter._wrapArguments(json)
484
- VrpcAdapter._createNamed(context, ...wrappedArgs)
485
- data.r = wrappedArgs[0] // First argument is instanceId
486
- VrpcAdapter._emitter.emit('create', {
487
- className: context,
488
- instance: wrappedArgs[0],
489
- args: wrappedArgs.slice(1)
468
+ const className = json.c
469
+ const [instanceId, ...args] = json.a
470
+ const instance = VrpcAdapter._create(className, instanceId, ...args)
471
+ VrpcAdapter._instances.set(instanceId, {
472
+ instance,
473
+ className,
474
+ isIsolated: false
490
475
  })
476
+ json.r = instanceId
491
477
  } catch (err) {
492
- data.e = err.message
493
- }
494
- }
495
-
496
- static _handleGetNamed (json) {
497
- const { data } = json
498
- try {
499
- const wrappedArgs = VrpcAdapter._wrapArguments(json)
500
- const instanceId = wrappedArgs[0]
501
- const entry = VrpcAdapter._instances.get(instanceId)
502
- if (entry) data.r = instanceId
503
- else data.e = `Instance with id: ${instanceId} does not exist`
504
- } catch (err) {
505
- data.e = err.message
478
+ json.e = err.message
506
479
  }
507
480
  }
508
481
 
509
482
  static _handleCallAll (json) {
510
- const { context, method, data } = json
511
483
  try {
512
484
  const calls = []
513
485
  for (const [id, { className, instance }] of VrpcAdapter._instances) {
514
- if (className !== context) continue
486
+ if (className !== json.c) continue
515
487
  let v
516
488
  let e = null
517
489
  try {
@@ -519,7 +491,7 @@ class VrpcAdapter {
519
491
  const funcName = wrappedArgs[0]
520
492
  v = instance[funcName].apply(instance, wrappedArgs.slice(1))
521
493
  } catch (err) {
522
- e = err
494
+ e = err.message
523
495
  }
524
496
  if (VrpcAdapter._isPromise(v)) {
525
497
  calls.push(
@@ -531,17 +503,30 @@ class VrpcAdapter {
531
503
  calls.push({ id, val: v, err: e })
532
504
  }
533
505
  }
534
- this._handlePromise(json, method, Promise.all(calls))
506
+ this._handlePromise(json, Promise.all(calls))
535
507
  } catch (err) {
536
- data.e = err.message
508
+ json.e = err.message
509
+ }
510
+ }
511
+
512
+ static _handleDelete (json) {
513
+ try {
514
+ const wrappedArgs = VrpcAdapter._wrapArguments(json)
515
+ const instanceId = wrappedArgs[0]
516
+ json.r = VrpcAdapter._delete(instanceId)
517
+ VrpcAdapter._emitter.emit('delete', {
518
+ className: json.c,
519
+ instance: wrappedArgs[0]
520
+ })
521
+ } catch (err) {
522
+ json.e = err.message
537
523
  }
538
524
  }
539
525
 
540
526
  static _handleCall (json) {
541
- const { context, method, data } = json
542
527
  const wrappedArgs = VrpcAdapter._wrapArguments(json)
543
528
  // Check whether context is a registered class
544
- const entry = VrpcAdapter._functionRegistry.get(context)
529
+ const entry = VrpcAdapter._functionRegistry.get(json.c)
545
530
  if (entry !== undefined) {
546
531
  // entry is class -> function is static
547
532
  const { Klass } = entry
@@ -549,39 +534,41 @@ class VrpcAdapter {
549
534
  // rather sticking to those functions registered before...
550
535
  // TODO This is even more important now as the agent does a wildcard
551
536
  // subscription against all functions
552
- if (VrpcAdapter._isFunction(Klass[method])) {
537
+ if (VrpcAdapter._isFunction(Klass[json.f])) {
553
538
  try {
554
- const ret = Klass[method].apply(null, wrappedArgs)
539
+ const ret = Klass[json.f].apply(null, wrappedArgs)
555
540
  // check if function returns promise
556
541
  if (VrpcAdapter._isPromise(ret)) {
557
- this._handlePromise(json, method, ret)
558
- } else data.r = ret
542
+ this._handlePromise(json, ret)
543
+ } else json.r = ret
559
544
  } catch (err) {
560
- data.e = err.message
545
+ json.e = err.message
561
546
  }
562
- } else throw new Error(`Could not find function: ${method}`)
547
+ } else throw new Error(`Could not find function: ${json.f}`)
563
548
  } else {
564
549
  // is not static
565
- const entry = VrpcAdapter._instances.get(context)
550
+ const entry = VrpcAdapter._instances.get(json.c)
566
551
  if (entry === undefined) {
567
- throw new Error(`Could not find context: ${context}`)
552
+ throw new Error(`Could not find context: ${json.c}`)
568
553
  }
569
554
  const { instance } = entry
570
- if (VrpcAdapter._isFunction(instance[method])) {
555
+ if (VrpcAdapter._isFunction(instance[json.f])) {
571
556
  try {
572
- const ret = instance[method].apply(instance, wrappedArgs)
557
+ const ret = instance[json.f].apply(instance, wrappedArgs)
573
558
  // check if function returns promise
574
559
  if (VrpcAdapter._isPromise(ret)) {
575
- this._handlePromise(json, method, ret)
576
- } else data.r = ret
560
+ this._handlePromise(json, ret)
561
+ } else json.r = ret
577
562
  } catch (err) {
578
- data.e = err.message
563
+ json.e = err.message
579
564
  }
580
- } else throw new Error(`Could not find function: ${method}`)
565
+ } else throw new Error(`Could not find function: ${json.f}`)
581
566
  }
582
567
  }
583
568
 
584
- static _create (className, ...args) {
569
+ static _create (className, instanceId, ...args) {
570
+ const entry = VrpcAdapter._instances.get(instanceId)
571
+ if (entry) return entry.instance
585
572
  const { Klass, withNew, schema } = VrpcAdapter._getClassEntry(className)
586
573
  if (schema !== null) {
587
574
  VrpcAdapter._validate(schema, ...args)
@@ -590,16 +577,6 @@ class VrpcAdapter {
590
577
  return Klass(...args)
591
578
  }
592
579
 
593
- static _createNamed (className, instanceId, ...args) {
594
- const entry = VrpcAdapter._instances.get(instanceId)
595
- if (!entry) {
596
- const instance = VrpcAdapter._create(className, ...args)
597
- VrpcAdapter._instances.set(instanceId, { className, instance })
598
- return instance
599
- }
600
- return entry.instance
601
- }
602
-
603
580
  static _delete (instanceId) {
604
581
  const entry = VrpcAdapter._instances.get(instanceId)
605
582
  if (entry) {
@@ -628,31 +605,29 @@ class VrpcAdapter {
628
605
  }
629
606
 
630
607
  static _wrapArguments (json, instanceId) {
631
- const { method, sender, data, context } = json
632
- const args = VrpcAdapter._extractDataToArray(data)
633
- const wrappedArgs = []
608
+ const { f: func, s: sender, a: args, c: context } = json
609
+ const wrapped = []
634
610
  args.forEach(arg => {
635
611
  // Find those args that actually need to be function callbacks
636
612
  if (typeof arg === 'string' && arg.substr(0, 5) === '__f__') {
637
613
  const f = this._generateWrapper(arg, json, instanceId)
638
- wrappedArgs.push(f)
614
+ wrapped.push(f)
639
615
  if (!sender) return
640
616
  // Register this client to later know when he is dead and skip callbacks
641
617
  if (!VrpcAdapter._listeners[sender]) VrpcAdapter._listeners[sender] = []
642
618
  // Check whether injected callback is an EventEmitter registration
643
- if (method === 'on' && typeof args[0] === 'string') {
619
+ if (func === 'on' && typeof args[0] === 'string') {
644
620
  const e = args[0]
645
621
  const i = context
646
622
  const r = arg
647
623
  VrpcAdapter._listeners[sender].push({ i, e, f, r })
648
624
  }
649
625
  if (
650
- (method === 'off' || method === 'removeListener') &&
626
+ (func === 'off' || func === 'removeListener') &&
651
627
  typeof args[0] === 'string'
652
628
  ) {
653
- const r = arg
654
- const s = VrpcAdapter._listeners[sender]
655
- const entry = s && s.find(x => x.r === r)
629
+ const listener = VrpcAdapter._listeners[sender]
630
+ const entry = listener && listener.find(x => x.r === arg)
656
631
  if (entry) {
657
632
  const { i, e, f } = entry
658
633
  VrpcAdapter.getInstance(i).removeListener(e, f)
@@ -660,88 +635,35 @@ class VrpcAdapter {
660
635
  }
661
636
  } else {
662
637
  // Leave the others untouched
663
- wrappedArgs.push(arg)
638
+ wrapped.push(arg)
664
639
  }
665
640
  })
666
- return wrappedArgs
641
+ return wrapped
667
642
  }
668
643
 
669
644
  static _generateWrapper (id, json, instanceId) {
670
- const { sender } = json
671
- if (instanceId) {
672
- const wrapper = (...innerArgs) => {
673
- // do not even trigger a callback for already offline clients
674
- if (sender && !VrpcAdapter._listeners[sender]) return
675
- const data = { _1: instanceId }
676
- innerArgs.forEach((x, i) => {
677
- data[`_${i + 2}`] = x
678
- })
679
- // TODO Heal that crazy API !!
680
- const callbackJson = { ...json, data, id }
681
- const callbackJsonString = VrpcAdapter._stringifySafely(callbackJson)
682
- VrpcAdapter._callback(callbackJsonString, callbackJson)
683
- }
684
- return wrapper
685
- }
686
645
  const wrapper = (...innerArgs) => {
687
646
  // do not even trigger a callback for already offline clients
688
- if (sender && !VrpcAdapter._listeners[sender]) return
689
- const data = {}
690
- innerArgs.forEach((x, i) => {
691
- data[`_${i + 1}`] = x
692
- })
693
- // TODO Heal that crazy API !!
694
- const callbackJson = { ...json, data, id }
695
- const callbackJsonString = VrpcAdapter._stringifySafely(callbackJson)
696
- VrpcAdapter._callback(callbackJsonString, callbackJson)
647
+ if (json.s && !VrpcAdapter._listeners[json.s]) return
648
+ const a = instanceId ? [instanceId, ...innerArgs] : [...innerArgs]
649
+ VrpcAdapter._callback({ ...json, a, i: id })
697
650
  }
698
651
  return wrapper
699
652
  }
700
653
 
701
- static _handlePromise (json, method, promise) {
654
+ static _handlePromise (json, promise) {
702
655
  try {
703
656
  const cid = VrpcAdapter._correlationId++ % Number.MAX_SAFE_INTEGER
704
- const id = `__p__${method}-${cid}`
705
- json.data.r = id
657
+ const id = `__p__${json.f}-${cid}`
658
+ json.r = id
706
659
  promise
707
- .then(value => {
708
- const data = { r: value }
709
- const promiseJson = Object.assign({}, json, { data, id })
710
- const promiseJsonString = VrpcAdapter._stringifySafely(promiseJson)
711
- VrpcAdapter._callback(promiseJsonString, promiseJson)
712
- })
713
- .catch(err => {
714
- const data = { e: err.message }
715
- const promiseJson = Object.assign({}, json, { data, id })
716
- const promiseJsonString = VrpcAdapter._stringifySafely(promiseJson)
717
- VrpcAdapter._callback(promiseJsonString, promiseJson)
718
- })
660
+ .then(r => VrpcAdapter._callback({ ...json, r, i: id }))
661
+ .catch(err => VrpcAdapter._callback({ ...json, e: err.message, i: id }))
719
662
  } catch (err) {
720
663
  json.data.e = err.message
721
664
  }
722
665
  }
723
666
 
724
- static _stringifySafely (json) {
725
- let jsonString
726
- try {
727
- jsonString = JSON.stringify(json)
728
- } catch (err) {
729
- this._log.debug(
730
- `Failed serialization of return value for: ${json.context}::${json.method}, because: ${err.message}`
731
- )
732
- json.data.r = '__vrpc::not-serializable__'
733
- jsonString = JSON.stringify(json)
734
- }
735
- return jsonString
736
- }
737
-
738
- static _extractDataToArray (data) {
739
- return Object.keys(data)
740
- .sort()
741
- .filter(value => value[0] === '_')
742
- .map(key => data[key])
743
- }
744
-
745
667
  static _generateId (object) {
746
668
  return crypto
747
669
  .createHash('md5')
@@ -825,8 +747,8 @@ class VrpcAdapter {
825
747
 
826
748
  static _getInstancesArray (className) {
827
749
  const instances = []
828
- VrpcAdapter._instances.forEach((value, key) => {
829
- if (value.className === className) instances.push(key)
750
+ VrpcAdapter._instances.forEach((v, k) => {
751
+ if (v.className === className && !v.isIsolated) instances.push(k)
830
752
  })
831
753
  return instances
832
754
  }