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.
- package/CHANGELOG.md +66 -0
- package/README.md +33 -56
- package/binding.gyp.no-auto +4 -26
- package/browser/vrpc.js +1 -1
- package/index.js +2 -2
- package/package.json +13 -17
- package/vrpc/VrpcAdapter.js +275 -233
- package/vrpc/VrpcAgent.js +204 -185
- package/vrpc/{VrpcRemote.js → VrpcClient.js} +295 -288
- package/vrpc/VrpcNative.js +307 -0
- package/vrpc/{vrpc.hpp → adapter.hpp} +1001 -1115
- package/vrpc/addon.cpp +5 -5
- package/vrpc/json.hpp +1769 -870
- package/vrpc/vrpc-agent-js +4 -4
- package/README.rst +0 -18
- package/third_party/include/catch.hpp +0 -12749
- package/third_party/install.sh +0 -22
- package/vrpc/VrpcLocal.js +0 -264
- package/vrpc/VrpcLocal.py +0 -171
- package/vrpc/__init__.py +0 -1
- package/vrpc/module.cpp +0 -183
package/vrpc/VrpcAdapter.js
CHANGED
|
@@ -10,9 +10,9 @@ __\/\\\_______\/\\\__/\\\///////\\\___\/\\\/////////\\\____/\\\////////__
|
|
|
10
10
|
________\///________\///________\///__\///___________________\/////////__
|
|
11
11
|
|
|
12
12
|
|
|
13
|
-
Non-intrusively
|
|
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/
|
|
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 {
|
|
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 =>
|
|
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: [
|
|
154
|
+
staticFunctions: [],
|
|
154
155
|
schema: null
|
|
155
156
|
})
|
|
156
|
-
VrpcAdapter._instances.set(instance, {
|
|
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
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
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
|
-
|
|
319
|
-
|
|
320
|
-
|
|
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('
|
|
359
|
-
staticFunctions.push('
|
|
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 =>
|
|
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
|
|
374
|
-
|
|
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(
|
|
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(
|
|
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
|
|
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.
|
|
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
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
case '
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
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
|
-
|
|
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
|
-
|
|
450
|
-
|
|
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.
|
|
453
|
-
|
|
454
|
-
|
|
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
|
-
|
|
499
|
+
e = err.message
|
|
461
500
|
}
|
|
462
|
-
|
|
463
|
-
|
|
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
|
|
466
|
-
|
|
467
|
-
if (
|
|
468
|
-
|
|
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
|
-
|
|
550
|
+
json.e = err.message
|
|
471
551
|
}
|
|
472
|
-
|
|
473
|
-
|
|
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
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
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
|
-
|
|
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
|
|
594
|
-
const {
|
|
595
|
-
const
|
|
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 = (
|
|
601
|
-
|
|
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 (
|
|
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 (
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
const
|
|
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 {
|
|
633
|
-
|
|
653
|
+
} else {
|
|
654
|
+
// Leave the others untouched
|
|
655
|
+
wrapped.push(arg)
|
|
634
656
|
}
|
|
635
657
|
})
|
|
636
|
-
return
|
|
658
|
+
return wrapped
|
|
637
659
|
}
|
|
638
660
|
|
|
639
|
-
static
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
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
|
|
663
|
-
let jsonString
|
|
671
|
+
static _handlePromise (json, promise) {
|
|
664
672
|
try {
|
|
665
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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_
|
|
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 = [
|
|
728
|
-
|
|
729
|
-
|
|
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((
|
|
744
|
-
if (
|
|
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
|