vrpc 2.4.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/CHANGELOG.md +69 -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 +337 -216
- package/vrpc/VrpcAgent.js +203 -183
- package/vrpc/{VrpcRemote.js → VrpcClient.js} +304 -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,8 +42,8 @@ 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')
|
|
46
|
+
const EventEmitter = require('events')
|
|
47
47
|
|
|
48
48
|
/**
|
|
49
49
|
* Generates an adapter layer for existing code and enables further VRPC-based
|
|
@@ -94,7 +94,7 @@ class VrpcAdapter {
|
|
|
94
94
|
* using the `new` operator
|
|
95
95
|
* @param {Object} [options.schema=null] If provided is used to validate ctor
|
|
96
96
|
* parameters (only works if registered code reflects a single class)
|
|
97
|
-
* @param {
|
|
97
|
+
* @param {String} options.jsdocPath if provided, parses documentation and
|
|
98
98
|
* provides it as meta information
|
|
99
99
|
*
|
|
100
100
|
* NOTE: This function currently only supports registration of classes (either
|
|
@@ -110,7 +110,7 @@ class VrpcAdapter {
|
|
|
110
110
|
} else {
|
|
111
111
|
const { jsdocPath } = options
|
|
112
112
|
if (jsdocPath) {
|
|
113
|
-
const absJsdocPath = path.resolve(caller(), '../', jsdocPath
|
|
113
|
+
const absJsdocPath = path.resolve(caller(), '../', `${jsdocPath}.js`)
|
|
114
114
|
this._registerClass(code, absJsdocPath, { ...options, jsdoc: true })
|
|
115
115
|
} else {
|
|
116
116
|
this._registerClass(code, null, options)
|
|
@@ -118,6 +118,49 @@ class VrpcAdapter {
|
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
120
|
|
|
121
|
+
/**
|
|
122
|
+
* Registers an existing instance and make it (remotely) callable
|
|
123
|
+
*
|
|
124
|
+
* @param {Object} obj The instance to be registered
|
|
125
|
+
* @param {Object} options
|
|
126
|
+
* @param {String} options.className Class name of the instance
|
|
127
|
+
* @param {String} options.instance Name of the instance
|
|
128
|
+
* @param {Boolean} [options.onlyPublic=true] If true, only registers
|
|
129
|
+
* functions that do not begin with an underscore
|
|
130
|
+
* @param {String} [options.jsdocPath] if provided, parses documentation and
|
|
131
|
+
* provides it as meta information
|
|
132
|
+
*/
|
|
133
|
+
static registerInstance (
|
|
134
|
+
obj,
|
|
135
|
+
{ className, instance, jsdocPath, onlyPublic = true } = {}
|
|
136
|
+
) {
|
|
137
|
+
let memberFunctions = VrpcAdapter._extractMemberFunctions(obj)
|
|
138
|
+
if (onlyPublic) {
|
|
139
|
+
memberFunctions = memberFunctions.filter(f => {
|
|
140
|
+
return !f.startsWith('_')
|
|
141
|
+
})
|
|
142
|
+
}
|
|
143
|
+
let meta = null
|
|
144
|
+
if (jsdocPath) {
|
|
145
|
+
const absJsdocPath = path.resolve(caller(), '../', `${jsdocPath}.js`)
|
|
146
|
+
const content = fs.readFileSync(absJsdocPath).toString('utf8')
|
|
147
|
+
meta = this._parseComments(content)
|
|
148
|
+
}
|
|
149
|
+
VrpcAdapter._functionRegistry.set(className, {
|
|
150
|
+
memberFunctions,
|
|
151
|
+
meta,
|
|
152
|
+
Klass: {},
|
|
153
|
+
withNew: false,
|
|
154
|
+
staticFunctions: [],
|
|
155
|
+
schema: null
|
|
156
|
+
})
|
|
157
|
+
VrpcAdapter._instances.set(instance, {
|
|
158
|
+
className,
|
|
159
|
+
instance: obj,
|
|
160
|
+
isIsolated: false
|
|
161
|
+
})
|
|
162
|
+
}
|
|
163
|
+
|
|
121
164
|
static getClasses () {
|
|
122
165
|
return JSON.stringify(VrpcAdapter._getClassesArray())
|
|
123
166
|
}
|
|
@@ -260,14 +303,14 @@ class VrpcAdapter {
|
|
|
260
303
|
* @typedef {Object.<String, Func>} MetaData Associates meta data to any function
|
|
261
304
|
*/
|
|
262
305
|
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
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
|
+
*/
|
|
269
312
|
|
|
270
|
-
|
|
313
|
+
/**
|
|
271
314
|
* @typedef {Object} Param
|
|
272
315
|
* @param {String} name Parameter name
|
|
273
316
|
* @param {Boolean} optional Whether parameter is optional
|
|
@@ -276,23 +319,34 @@ class VrpcAdapter {
|
|
|
276
319
|
* @param {Any} [default] The default to be injected when not provided
|
|
277
320
|
*/
|
|
278
321
|
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
322
|
+
/**
|
|
323
|
+
* @typedef {Object} Ret
|
|
324
|
+
* @param {String} description Return value description
|
|
325
|
+
* @param {String} [type] Return value type
|
|
326
|
+
*/
|
|
327
|
+
|
|
328
|
+
static on (eventName, listener) {
|
|
329
|
+
VrpcAdapter._emitter.on(eventName, listener)
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
static once (eventName, listener) {
|
|
333
|
+
VrpcAdapter._emitter.once(eventName, listener)
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
static off (eventName, listener) {
|
|
337
|
+
VrpcAdapter._emitter.off(eventName, listener)
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
static removeAllListeners (eventName) {
|
|
341
|
+
VrpcAdapter._emitter.removeAllListeners(eventName)
|
|
342
|
+
}
|
|
284
343
|
|
|
285
344
|
// private:
|
|
286
345
|
|
|
287
346
|
static _registerClass (
|
|
288
347
|
Klass,
|
|
289
348
|
absJsdocPath = null,
|
|
290
|
-
{
|
|
291
|
-
onlyPublic = true,
|
|
292
|
-
withNew = true,
|
|
293
|
-
schema = null,
|
|
294
|
-
jsdoc = true
|
|
295
|
-
} = {}
|
|
349
|
+
{ onlyPublic = true, withNew = true, schema = null, jsdoc = true } = {}
|
|
296
350
|
) {
|
|
297
351
|
// Get all static static functions
|
|
298
352
|
let staticFunctions = VrpcAdapter._extractStaticFunctions(Klass)
|
|
@@ -300,24 +354,29 @@ class VrpcAdapter {
|
|
|
300
354
|
staticFunctions = staticFunctions.filter(f => !f.startsWith('_'))
|
|
301
355
|
}
|
|
302
356
|
// Inject constructor and destructor
|
|
303
|
-
staticFunctions.push('
|
|
304
|
-
staticFunctions.push('
|
|
305
|
-
staticFunctions.push('__createNamed__')
|
|
306
|
-
staticFunctions.push('__getNamed__')
|
|
357
|
+
staticFunctions.push('__createIsolated__')
|
|
358
|
+
staticFunctions.push('__createShared__')
|
|
307
359
|
staticFunctions.push('__callAll__')
|
|
360
|
+
staticFunctions.push('__delete__')
|
|
308
361
|
let memberFunctions = VrpcAdapter._extractMemberFunctions(Klass)
|
|
309
362
|
if (onlyPublic) {
|
|
310
|
-
memberFunctions = memberFunctions.filter(f =>
|
|
363
|
+
memberFunctions = memberFunctions.filter(f => {
|
|
364
|
+
return !f.startsWith('_')
|
|
365
|
+
})
|
|
311
366
|
}
|
|
312
367
|
let meta = null
|
|
313
368
|
if (jsdoc && absJsdocPath) {
|
|
314
369
|
const content = fs.readFileSync(absJsdocPath).toString('utf8')
|
|
315
370
|
meta = this._parseComments(content)
|
|
316
371
|
}
|
|
317
|
-
VrpcAdapter._functionRegistry.set(
|
|
318
|
-
Klass
|
|
319
|
-
|
|
320
|
-
|
|
372
|
+
VrpcAdapter._functionRegistry.set(Klass.name, {
|
|
373
|
+
Klass,
|
|
374
|
+
withNew,
|
|
375
|
+
staticFunctions,
|
|
376
|
+
memberFunctions,
|
|
377
|
+
schema,
|
|
378
|
+
meta
|
|
379
|
+
})
|
|
321
380
|
}
|
|
322
381
|
|
|
323
382
|
static _parseComments (content) {
|
|
@@ -326,7 +385,9 @@ class VrpcAdapter {
|
|
|
326
385
|
comments.forEach(({ tags, description, functionName }) => {
|
|
327
386
|
if (functionName) {
|
|
328
387
|
if (tags) {
|
|
329
|
-
let params = tags.filter(
|
|
388
|
+
let params = tags.filter(
|
|
389
|
+
({ tag }) => tag === 'param' || tag === 'arg' || tag === 'argument'
|
|
390
|
+
)
|
|
330
391
|
if (params.length > 0) {
|
|
331
392
|
params = params.map(({ name, optional, description, type }) => {
|
|
332
393
|
return { name, optional, description, type }
|
|
@@ -334,10 +395,15 @@ class VrpcAdapter {
|
|
|
334
395
|
} else {
|
|
335
396
|
params = []
|
|
336
397
|
}
|
|
337
|
-
let ret = tags.filter(
|
|
398
|
+
let ret = tags.filter(
|
|
399
|
+
({ tag }) => tag === 'returns' || tag === 'return'
|
|
400
|
+
)
|
|
338
401
|
if (ret.length === 1) {
|
|
339
402
|
const { source, type } = ret[0]
|
|
340
|
-
const description = source
|
|
403
|
+
const description = source
|
|
404
|
+
.split(' ')
|
|
405
|
+
.splice(2)
|
|
406
|
+
.join(' ')
|
|
341
407
|
ret = { description, type }
|
|
342
408
|
} else {
|
|
343
409
|
ret = null
|
|
@@ -352,7 +418,7 @@ class VrpcAdapter {
|
|
|
352
418
|
},
|
|
353
419
|
...params
|
|
354
420
|
]
|
|
355
|
-
meta.
|
|
421
|
+
meta.__createShared__ = { description, params: modified, ret }
|
|
356
422
|
} else {
|
|
357
423
|
meta[functionName] = { description, params, ret }
|
|
358
424
|
}
|
|
@@ -363,120 +429,146 @@ class VrpcAdapter {
|
|
|
363
429
|
}
|
|
364
430
|
|
|
365
431
|
static _call (json) {
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
VrpcAdapter._instances.set(instanceId, { context, instance })
|
|
376
|
-
data.r = instanceId
|
|
377
|
-
} catch (err) {
|
|
378
|
-
data.e = err.message
|
|
379
|
-
}
|
|
432
|
+
switch (json.f) {
|
|
433
|
+
case '__createIsolated__':
|
|
434
|
+
VrpcAdapter._handleCreateIsolated(json)
|
|
435
|
+
break
|
|
436
|
+
case '__createShared__':
|
|
437
|
+
VrpcAdapter._handleCreateShared(json)
|
|
438
|
+
break
|
|
439
|
+
case '__callAll__':
|
|
440
|
+
VrpcAdapter._handleCallAll(json)
|
|
380
441
|
break
|
|
381
|
-
// Special case: dtor
|
|
382
442
|
case '__delete__':
|
|
383
|
-
|
|
384
|
-
const instanceId = wrappedArgs[0]
|
|
385
|
-
data.r = VrpcAdapter._delete(instanceId)
|
|
386
|
-
} catch (err) {
|
|
387
|
-
data.e = err.message
|
|
388
|
-
}
|
|
443
|
+
VrpcAdapter._handleDelete(json)
|
|
389
444
|
break
|
|
390
|
-
|
|
391
|
-
|
|
445
|
+
default:
|
|
446
|
+
VrpcAdapter._handleCall(json)
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
static _handleCreateIsolated (json) {
|
|
451
|
+
try {
|
|
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
|
|
459
|
+
})
|
|
460
|
+
json.r = instanceId
|
|
461
|
+
} catch (err) {
|
|
462
|
+
json.e = err.message
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
static _handleCreateShared (json) {
|
|
467
|
+
try {
|
|
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
|
|
475
|
+
})
|
|
476
|
+
json.r = instanceId
|
|
477
|
+
} catch (err) {
|
|
478
|
+
json.e = err.message
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
static _handleCallAll (json) {
|
|
483
|
+
try {
|
|
484
|
+
const calls = []
|
|
485
|
+
for (const [id, { className, instance }] of VrpcAdapter._instances) {
|
|
486
|
+
if (className !== json.c) continue
|
|
487
|
+
let v
|
|
488
|
+
let e = null
|
|
392
489
|
try {
|
|
393
|
-
VrpcAdapter.
|
|
394
|
-
|
|
490
|
+
const wrappedArgs = VrpcAdapter._wrapArguments(json, id)
|
|
491
|
+
const funcName = wrappedArgs[0]
|
|
492
|
+
v = instance[funcName].apply(instance, wrappedArgs.slice(1))
|
|
395
493
|
} catch (err) {
|
|
396
|
-
|
|
494
|
+
e = err.message
|
|
397
495
|
}
|
|
398
|
-
|
|
399
|
-
|
|
496
|
+
if (VrpcAdapter._isPromise(v)) {
|
|
497
|
+
calls.push(
|
|
498
|
+
v
|
|
499
|
+
.then(val => ({ id, val, err: null }))
|
|
500
|
+
.catch(err => ({ id, err, val: null }))
|
|
501
|
+
)
|
|
502
|
+
} else {
|
|
503
|
+
calls.push({ id, val: v, err: e })
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
this._handlePromise(json, Promise.all(calls))
|
|
507
|
+
} catch (err) {
|
|
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
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
static _handleCall (json) {
|
|
527
|
+
const wrappedArgs = VrpcAdapter._wrapArguments(json)
|
|
528
|
+
// Check whether context is a registered class
|
|
529
|
+
const entry = VrpcAdapter._functionRegistry.get(json.c)
|
|
530
|
+
if (entry !== undefined) {
|
|
531
|
+
// entry is class -> function is static
|
|
532
|
+
const { Klass } = entry
|
|
533
|
+
// TODO Think about whether to do live checking (like here) or
|
|
534
|
+
// rather sticking to those functions registered before...
|
|
535
|
+
// TODO This is even more important now as the agent does a wildcard
|
|
536
|
+
// subscription against all functions
|
|
537
|
+
if (VrpcAdapter._isFunction(Klass[json.f])) {
|
|
400
538
|
try {
|
|
401
|
-
const
|
|
402
|
-
|
|
403
|
-
if (
|
|
404
|
-
|
|
539
|
+
const ret = Klass[json.f].apply(null, wrappedArgs)
|
|
540
|
+
// check if function returns promise
|
|
541
|
+
if (VrpcAdapter._isPromise(ret)) {
|
|
542
|
+
this._handlePromise(json, ret)
|
|
543
|
+
} else json.r = ret
|
|
405
544
|
} catch (err) {
|
|
406
|
-
|
|
545
|
+
json.e = err.message
|
|
407
546
|
}
|
|
408
|
-
|
|
409
|
-
|
|
547
|
+
} else throw new Error(`Could not find function: ${json.f}`)
|
|
548
|
+
} else {
|
|
549
|
+
// is not static
|
|
550
|
+
const entry = VrpcAdapter._instances.get(json.c)
|
|
551
|
+
if (entry === undefined) {
|
|
552
|
+
throw new Error(`Could not find context: ${json.c}`)
|
|
553
|
+
}
|
|
554
|
+
const { instance } = entry
|
|
555
|
+
if (VrpcAdapter._isFunction(instance[json.f])) {
|
|
410
556
|
try {
|
|
411
|
-
const
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
let e = null
|
|
417
|
-
try {
|
|
418
|
-
v = instance[funcName].apply(instance, wrappedArgs.slice(1))
|
|
419
|
-
} catch (err) {
|
|
420
|
-
e = err
|
|
421
|
-
}
|
|
422
|
-
// check wether function returned a promise
|
|
423
|
-
if (VrpcAdapter._isPromise(v)) {
|
|
424
|
-
calls.push(v
|
|
425
|
-
.then(val => ({ id, val, err: null }))
|
|
426
|
-
.catch(err => ({ id, err, val: null })))
|
|
427
|
-
} else {
|
|
428
|
-
calls.push({ id, val: v, err: e })
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
this._handlePromise(json, method, Promise.all(calls))
|
|
557
|
+
const ret = instance[json.f].apply(instance, wrappedArgs)
|
|
558
|
+
// check if function returns promise
|
|
559
|
+
if (VrpcAdapter._isPromise(ret)) {
|
|
560
|
+
this._handlePromise(json, ret)
|
|
561
|
+
} else json.r = ret
|
|
432
562
|
} catch (err) {
|
|
433
|
-
|
|
434
|
-
}
|
|
435
|
-
break
|
|
436
|
-
// Regular function call
|
|
437
|
-
default: {
|
|
438
|
-
// Check whether context is a registered class
|
|
439
|
-
const entry = VrpcAdapter._functionRegistry.get(context)
|
|
440
|
-
if (entry !== undefined) { // entry is class -> function is static
|
|
441
|
-
const { Klass } = entry
|
|
442
|
-
// TODO Think about whether to do live checking (like here) or
|
|
443
|
-
// rather sticking to those functions registered before...
|
|
444
|
-
// TODO This is even more important now as the agent does a wildcard
|
|
445
|
-
// subscription against all functions
|
|
446
|
-
if (VrpcAdapter._isFunction(Klass[method])) {
|
|
447
|
-
try {
|
|
448
|
-
const ret = Klass[method].apply(null, wrappedArgs)
|
|
449
|
-
// check if function returns promise
|
|
450
|
-
if (ret && this._isFunction(ret.then)) {
|
|
451
|
-
this._handlePromise(json, method, ret)
|
|
452
|
-
} else data.r = ret
|
|
453
|
-
} catch (err) {
|
|
454
|
-
data.e = err.message
|
|
455
|
-
}
|
|
456
|
-
} else throw new Error(`Could not find function: ${method}`)
|
|
457
|
-
} else { // is not static
|
|
458
|
-
const entry = VrpcAdapter._instances.get(context)
|
|
459
|
-
if (entry === undefined) {
|
|
460
|
-
throw new Error(`Could not find context: ${context}`)
|
|
461
|
-
}
|
|
462
|
-
const { instance } = entry
|
|
463
|
-
if (VrpcAdapter._isFunction(instance[method])) {
|
|
464
|
-
try {
|
|
465
|
-
const ret = instance[method].apply(instance, wrappedArgs)
|
|
466
|
-
// check if function returns promise
|
|
467
|
-
if (VrpcAdapter._isPromise(ret)) {
|
|
468
|
-
this._handlePromise(json, method, ret)
|
|
469
|
-
} else data.r = ret
|
|
470
|
-
} catch (err) {
|
|
471
|
-
data.e = err.message
|
|
472
|
-
}
|
|
473
|
-
} else throw new Error(`Could not find function: ${method}`)
|
|
563
|
+
json.e = err.message
|
|
474
564
|
}
|
|
475
|
-
}
|
|
565
|
+
} else throw new Error(`Could not find function: ${json.f}`)
|
|
476
566
|
}
|
|
477
567
|
}
|
|
478
568
|
|
|
479
|
-
static _create (className, ...args) {
|
|
569
|
+
static _create (className, instanceId, ...args) {
|
|
570
|
+
const entry = VrpcAdapter._instances.get(instanceId)
|
|
571
|
+
if (entry) return entry.instance
|
|
480
572
|
const { Klass, withNew, schema } = VrpcAdapter._getClassEntry(className)
|
|
481
573
|
if (schema !== null) {
|
|
482
574
|
VrpcAdapter._validate(schema, ...args)
|
|
@@ -485,16 +577,6 @@ class VrpcAdapter {
|
|
|
485
577
|
return Klass(...args)
|
|
486
578
|
}
|
|
487
579
|
|
|
488
|
-
static _createNamed (className, instanceId, ...args) {
|
|
489
|
-
const entry = VrpcAdapter._instances.get(instanceId)
|
|
490
|
-
if (!entry) {
|
|
491
|
-
const instance = VrpcAdapter._create(className, ...args)
|
|
492
|
-
VrpcAdapter._instances.set(instanceId, { className, instance })
|
|
493
|
-
return instance
|
|
494
|
-
}
|
|
495
|
-
return entry.instance
|
|
496
|
-
}
|
|
497
|
-
|
|
498
580
|
static _delete (instanceId) {
|
|
499
581
|
const entry = VrpcAdapter._instances.get(instanceId)
|
|
500
582
|
if (entry) {
|
|
@@ -511,6 +593,7 @@ class VrpcAdapter {
|
|
|
511
593
|
VrpcAdapter.getInstance(i).removeListener(e, f)
|
|
512
594
|
})
|
|
513
595
|
}
|
|
596
|
+
delete VrpcAdapter._listeners[clientId]
|
|
514
597
|
}
|
|
515
598
|
|
|
516
599
|
static _validate (schema, params) {
|
|
@@ -521,92 +604,71 @@ class VrpcAdapter {
|
|
|
521
604
|
if (!valid) throw new Error(VrpcAdapter._ajv.errorsText())
|
|
522
605
|
}
|
|
523
606
|
|
|
524
|
-
static
|
|
525
|
-
const args =
|
|
526
|
-
const
|
|
607
|
+
static _wrapArguments (json, instanceId) {
|
|
608
|
+
const { f: func, s: sender, a: args, c: context } = json
|
|
609
|
+
const wrapped = []
|
|
527
610
|
args.forEach(arg => {
|
|
528
611
|
// Find those args that actually need to be function callbacks
|
|
529
612
|
if (typeof arg === 'string' && arg.substr(0, 5) === '__f__') {
|
|
530
|
-
const f = (
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
const callbackJson = Object.assign({}, json, { data, id: arg })
|
|
536
|
-
const callbackJsonString = VrpcAdapter._stringifySafely(callbackJson)
|
|
537
|
-
VrpcAdapter._callback(callbackJsonString, callbackJson)
|
|
538
|
-
}
|
|
613
|
+
const f = this._generateWrapper(arg, json, instanceId)
|
|
614
|
+
wrapped.push(f)
|
|
615
|
+
if (!sender) return
|
|
616
|
+
// Register this client to later know when he is dead and skip callbacks
|
|
617
|
+
if (!VrpcAdapter._listeners[sender]) VrpcAdapter._listeners[sender] = []
|
|
539
618
|
// Check whether injected callback is an EventEmitter registration
|
|
540
|
-
if (
|
|
619
|
+
if (func === 'on' && typeof args[0] === 'string') {
|
|
541
620
|
const e = args[0]
|
|
542
|
-
const i =
|
|
621
|
+
const i = context
|
|
543
622
|
const r = arg
|
|
544
|
-
VrpcAdapter._listeners[
|
|
545
|
-
? VrpcAdapter._listeners[json.sender].push({ i, e, f, r })
|
|
546
|
-
: VrpcAdapter._listeners[json.sender] = [{ i, e, f, r }]
|
|
623
|
+
VrpcAdapter._listeners[sender].push({ i, e, f, r })
|
|
547
624
|
}
|
|
548
|
-
if (
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
const
|
|
625
|
+
if (
|
|
626
|
+
(func === 'off' || func === 'removeListener') &&
|
|
627
|
+
typeof args[0] === 'string'
|
|
628
|
+
) {
|
|
629
|
+
const listener = VrpcAdapter._listeners[sender]
|
|
630
|
+
const entry = listener && listener.find(x => x.r === arg)
|
|
553
631
|
if (entry) {
|
|
554
632
|
const { i, e, f } = entry
|
|
555
633
|
VrpcAdapter.getInstance(i).removeListener(e, f)
|
|
556
634
|
}
|
|
557
635
|
}
|
|
558
|
-
wrappedArgs.push(f)
|
|
559
|
-
// Leave the others untouched
|
|
560
636
|
} else {
|
|
561
|
-
|
|
637
|
+
// Leave the others untouched
|
|
638
|
+
wrapped.push(arg)
|
|
562
639
|
}
|
|
563
640
|
})
|
|
564
|
-
return
|
|
641
|
+
return wrapped
|
|
565
642
|
}
|
|
566
643
|
|
|
567
|
-
static
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
.then(value => {
|
|
574
|
-
const data = { r: value }
|
|
575
|
-
const promiseJson = Object.assign({}, json, { data, id })
|
|
576
|
-
const promiseJsonString = VrpcAdapter._stringifySafely(promiseJson)
|
|
577
|
-
VrpcAdapter._callback(promiseJsonString, promiseJson)
|
|
578
|
-
})
|
|
579
|
-
.catch(err => {
|
|
580
|
-
const data = { e: err.message }
|
|
581
|
-
const promiseJson = Object.assign({}, json, { data, id })
|
|
582
|
-
const promiseJsonString = VrpcAdapter._stringifySafely(promiseJson)
|
|
583
|
-
VrpcAdapter._callback(promiseJsonString, promiseJson)
|
|
584
|
-
})
|
|
585
|
-
} catch (err) {
|
|
586
|
-
json.data.e = err.message
|
|
644
|
+
static _generateWrapper (id, json, instanceId) {
|
|
645
|
+
const wrapper = (...innerArgs) => {
|
|
646
|
+
// do not even trigger a callback for already offline clients
|
|
647
|
+
if (json.s && !VrpcAdapter._listeners[json.s]) return
|
|
648
|
+
const a = instanceId ? [instanceId, ...innerArgs] : [...innerArgs]
|
|
649
|
+
VrpcAdapter._callback({ ...json, a, i: id })
|
|
587
650
|
}
|
|
651
|
+
return wrapper
|
|
588
652
|
}
|
|
589
653
|
|
|
590
|
-
static
|
|
591
|
-
let jsonString
|
|
654
|
+
static _handlePromise (json, promise) {
|
|
592
655
|
try {
|
|
593
|
-
|
|
656
|
+
const cid = VrpcAdapter._correlationId++ % Number.MAX_SAFE_INTEGER
|
|
657
|
+
const id = `__p__${json.f}-${cid}`
|
|
658
|
+
json.r = id
|
|
659
|
+
promise
|
|
660
|
+
.then(r => VrpcAdapter._callback({ ...json, r, i: id }))
|
|
661
|
+
.catch(err => VrpcAdapter._callback({ ...json, e: err.message, i: id }))
|
|
594
662
|
} catch (err) {
|
|
595
|
-
|
|
596
|
-
json.data.r = '__vrpc::not-serializable__'
|
|
597
|
-
jsonString = JSON.stringify(json)
|
|
663
|
+
json.data.e = err.message
|
|
598
664
|
}
|
|
599
|
-
return jsonString
|
|
600
|
-
}
|
|
601
|
-
|
|
602
|
-
static _extractDataToArray (data) {
|
|
603
|
-
return Object.keys(data).sort()
|
|
604
|
-
.filter(value => value[0] === '_')
|
|
605
|
-
.map(key => data[key])
|
|
606
665
|
}
|
|
607
666
|
|
|
608
667
|
static _generateId (object) {
|
|
609
|
-
return crypto
|
|
668
|
+
return crypto
|
|
669
|
+
.createHash('md5')
|
|
670
|
+
.update(JSON.stringify(object))
|
|
671
|
+
.digest('hex')
|
|
610
672
|
}
|
|
611
673
|
|
|
612
674
|
static _getClassEntry (className) {
|
|
@@ -626,11 +688,17 @@ class VrpcAdapter {
|
|
|
626
688
|
}
|
|
627
689
|
|
|
628
690
|
static _isClass (obj) {
|
|
629
|
-
return
|
|
691
|
+
return (
|
|
692
|
+
!!obj && typeof obj === 'function' && /^\s*class\s+/.test(obj.toString())
|
|
693
|
+
)
|
|
630
694
|
}
|
|
631
695
|
|
|
632
696
|
static _isPromise (obj) {
|
|
633
|
-
return
|
|
697
|
+
return (
|
|
698
|
+
!!obj &&
|
|
699
|
+
(typeof obj === 'object' || typeof obj === 'function') &&
|
|
700
|
+
typeof obj.then === 'function'
|
|
701
|
+
)
|
|
634
702
|
}
|
|
635
703
|
|
|
636
704
|
static _extractMemberFunctions (klass) {
|
|
@@ -638,12 +706,20 @@ class VrpcAdapter {
|
|
|
638
706
|
let fs = []
|
|
639
707
|
do {
|
|
640
708
|
if (klass_.prototype) {
|
|
641
|
-
|
|
709
|
+
const funcs = Object.getOwnPropertyNames(klass_.prototype).filter(
|
|
710
|
+
x =>
|
|
711
|
+
!VrpcAdapter._blackList.has(x) &&
|
|
712
|
+
this._isFunction(klass_.prototype[x])
|
|
713
|
+
)
|
|
714
|
+
fs = [...fs, ...funcs]
|
|
642
715
|
} else {
|
|
643
|
-
|
|
716
|
+
const funcs = Object.getOwnPropertyNames(klass_).filter(
|
|
717
|
+
x => !VrpcAdapter._blackList.has(x) && this._isFunction(klass_[x])
|
|
718
|
+
)
|
|
719
|
+
fs = [...fs, ...funcs]
|
|
644
720
|
}
|
|
645
721
|
klass_ = Object.getPrototypeOf(klass_)
|
|
646
|
-
} while (klass_
|
|
722
|
+
} while (klass_)
|
|
647
723
|
// Filter out all duplicates
|
|
648
724
|
return Array.from(new Set(fs))
|
|
649
725
|
}
|
|
@@ -652,10 +728,13 @@ class VrpcAdapter {
|
|
|
652
728
|
let klass_ = klass
|
|
653
729
|
let fs = []
|
|
654
730
|
do {
|
|
655
|
-
fs = [
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
731
|
+
fs = [
|
|
732
|
+
...fs,
|
|
733
|
+
...Object.getOwnPropertyNames(klass_).filter(prop => {
|
|
734
|
+
const desc = Object.getOwnPropertyDescriptor(klass_, prop)
|
|
735
|
+
return !!desc && typeof desc.value === 'function'
|
|
736
|
+
})
|
|
737
|
+
]
|
|
659
738
|
klass_ = Object.getPrototypeOf(klass_)
|
|
660
739
|
} while (klass_ && klass_.name)
|
|
661
740
|
// Filter out all duplicates
|
|
@@ -668,8 +747,8 @@ class VrpcAdapter {
|
|
|
668
747
|
|
|
669
748
|
static _getInstancesArray (className) {
|
|
670
749
|
const instances = []
|
|
671
|
-
VrpcAdapter._instances.forEach((
|
|
672
|
-
if (
|
|
750
|
+
VrpcAdapter._instances.forEach((v, k) => {
|
|
751
|
+
if (v.className === className && !v.isIsolated) instances.push(k)
|
|
673
752
|
})
|
|
674
753
|
return instances
|
|
675
754
|
}
|
|
@@ -693,10 +772,52 @@ class VrpcAdapter {
|
|
|
693
772
|
}
|
|
694
773
|
}
|
|
695
774
|
|
|
775
|
+
/**
|
|
776
|
+
* Event 'create'
|
|
777
|
+
*
|
|
778
|
+
* Emitted on creation of named instance
|
|
779
|
+
*
|
|
780
|
+
* @event VrpcAdapter#create
|
|
781
|
+
* @type {Object}
|
|
782
|
+
* @property {String} className The class name of the create instance
|
|
783
|
+
* @property {String} instance The instance name
|
|
784
|
+
* @property {Array.<Any>} args The constructor arguments
|
|
785
|
+
*/
|
|
786
|
+
|
|
787
|
+
/**
|
|
788
|
+
* Event 'delete'
|
|
789
|
+
*
|
|
790
|
+
* Emitted on deletion of named instance
|
|
791
|
+
*
|
|
792
|
+
* @event VrpcAdapter#delete
|
|
793
|
+
* @type {Object}
|
|
794
|
+
* @property {String} className The class name of the deleted instance
|
|
795
|
+
* @property {String} instance The instance name
|
|
796
|
+
*/
|
|
797
|
+
|
|
696
798
|
// Initialize static members
|
|
697
799
|
VrpcAdapter._functionRegistry = new Map()
|
|
698
800
|
VrpcAdapter._instances = new Map()
|
|
801
|
+
VrpcAdapter._emitter = new EventEmitter()
|
|
699
802
|
VrpcAdapter._correlationId = 0
|
|
700
803
|
VrpcAdapter._listeners = {}
|
|
804
|
+
VrpcAdapter._blackList = new Set([
|
|
805
|
+
'caller',
|
|
806
|
+
'callee',
|
|
807
|
+
'arguments',
|
|
808
|
+
'apply',
|
|
809
|
+
'bind',
|
|
810
|
+
'call',
|
|
811
|
+
'toString',
|
|
812
|
+
'hasOwnProperty',
|
|
813
|
+
'isPrototypeOf',
|
|
814
|
+
'propertyIsEnumerable',
|
|
815
|
+
'valueOf',
|
|
816
|
+
'toLocaleString',
|
|
817
|
+
'__defineGetter__',
|
|
818
|
+
'__defineSetter__',
|
|
819
|
+
'__lookupGetter__',
|
|
820
|
+
'__lookupSetter__'
|
|
821
|
+
])
|
|
701
822
|
|
|
702
823
|
module.exports = VrpcAdapter
|