vrpc 3.0.0-alpha.2 → 3.0.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 +60 -0
- package/LICENSE +1 -1
- package/README.md +12 -15
- package/browser/vrpc.js +1 -1
- package/package.json +8 -5
- package/vrpc/VrpcAdapter.js +229 -171
- package/vrpc/VrpcAgent.js +22 -22
- package/vrpc/VrpcClient.js +305 -289
- package/vrpc/VrpcNative.js +25 -2
- package/vrpc/adapter.hpp +4 -2
- package/vrpc/addon.cpp +1 -1
- package/vrpc/vrpc-agent-js +1 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vrpc",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.2",
|
|
4
4
|
"description": "Variadic Remote Procedure Calls",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"directories": {
|
|
@@ -12,10 +12,11 @@
|
|
|
12
12
|
"build:addon": "ln -sf binding.gyp.no-auto binding.gyp && node-gyp rebuild && rm binding.gyp",
|
|
13
13
|
"build:browser": "./node_modules/.bin/webpack",
|
|
14
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:
|
|
15
|
+
"test": "npm run test:adapter && npm run test:native && npm run test:agent && npm run test:client && npm run test:production",
|
|
16
|
+
"test:adapter": "./node_modules/.bin/mocha tests/adapter/*.js --exit",
|
|
17
|
+
"test:native": "./node_modules/.bin/mocha tests/native/*.js --exit",
|
|
16
18
|
"test:agent": "tests/agent/test.sh",
|
|
17
19
|
"test:client": "tests/client/test.sh",
|
|
18
|
-
"test:native": "./node_modules/.bin/mocha tests/native/vrpc-native*.js --exit",
|
|
19
20
|
"test:performance": "tests/performance/test.sh",
|
|
20
21
|
"test:production": "./node_modules/.bin/mocha tests/production/lifeCycleTest.js --timeout 30000 --exit && tests/production/test.sh"
|
|
21
22
|
},
|
|
@@ -49,7 +50,7 @@
|
|
|
49
50
|
"crypto-browserify": "^3.12.0",
|
|
50
51
|
"dockerode": "^3.2.0",
|
|
51
52
|
"jsdoc-to-markdown": "^7.0.1",
|
|
52
|
-
"mocha": "^
|
|
53
|
+
"mocha": "^9.1.3",
|
|
53
54
|
"os-browserify": "^0.3.0",
|
|
54
55
|
"sinon": "^7.3.2",
|
|
55
56
|
"stream-browserify": "^3.0.0",
|
|
@@ -66,8 +67,10 @@
|
|
|
66
67
|
"dependencies": {
|
|
67
68
|
"ajv": "^6.10.0",
|
|
68
69
|
"argparse": "^2.0.1",
|
|
70
|
+
"buffer": "^6.0.3",
|
|
69
71
|
"caller": "^1.0.1",
|
|
70
72
|
"mqtt": "^4.2.6",
|
|
71
|
-
"nanoid": "^3.1.23"
|
|
73
|
+
"nanoid": "^3.1.23",
|
|
74
|
+
"process": "^0.11.10"
|
|
72
75
|
}
|
|
73
76
|
}
|
package/vrpc/VrpcAdapter.js
CHANGED
|
@@ -16,7 +16,7 @@ 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>.
|
|
19
|
-
Copyright (c) 2018 -
|
|
19
|
+
Copyright (c) 2018 - 2022 Dr. Burkhard C. Heisen <burkhard.heisen@heisenware.com>.
|
|
20
20
|
|
|
21
21
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
22
22
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -44,6 +44,7 @@ const Ajv = require('ajv')
|
|
|
44
44
|
const caller = require('caller')
|
|
45
45
|
const commentParser = require('./comment-parser')
|
|
46
46
|
const EventEmitter = require('events')
|
|
47
|
+
const { nanoid } = require('nanoid')
|
|
47
48
|
|
|
48
49
|
/**
|
|
49
50
|
* Generates an adapter layer for existing code and enables further VRPC-based
|
|
@@ -104,13 +105,16 @@ class VrpcAdapter {
|
|
|
104
105
|
if (typeof code === 'string') {
|
|
105
106
|
const absPath = path.resolve(caller(), '../', code)
|
|
106
107
|
const relPath = path.relative(__dirname, absPath)
|
|
107
|
-
const absJsdocPath =
|
|
108
|
+
const absJsdocPath =
|
|
109
|
+
absPath && absPath.endsWith('.js') ? absPath : `${absPath}.js`
|
|
108
110
|
const Klass = require(relPath)
|
|
109
111
|
this._registerClass(Klass, absJsdocPath, options)
|
|
110
112
|
} else {
|
|
111
113
|
const { jsdocPath } = options
|
|
114
|
+
const sJsdocPath =
|
|
115
|
+
jsdocPath && jsdocPath.endsWith('.js') ? jsdocPath : `${jsdocPath}.js`
|
|
112
116
|
if (jsdocPath) {
|
|
113
|
-
const absJsdocPath = path.resolve(caller(), '../',
|
|
117
|
+
const absJsdocPath = path.resolve(caller(), '../', sJsdocPath)
|
|
114
118
|
this._registerClass(code, absJsdocPath, { ...options, jsdoc: true })
|
|
115
119
|
} else {
|
|
116
120
|
this._registerClass(code, null, options)
|
|
@@ -146,14 +150,16 @@ class VrpcAdapter {
|
|
|
146
150
|
const content = fs.readFileSync(absJsdocPath).toString('utf8')
|
|
147
151
|
meta = this._parseComments(content)
|
|
148
152
|
}
|
|
149
|
-
VrpcAdapter._functionRegistry.
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
153
|
+
if (!VrpcAdapter._functionRegistry.has(className)) {
|
|
154
|
+
VrpcAdapter._functionRegistry.set(className, {
|
|
155
|
+
memberFunctions,
|
|
156
|
+
meta,
|
|
157
|
+
Klass: {},
|
|
158
|
+
withNew: false,
|
|
159
|
+
staticFunctions: [],
|
|
160
|
+
schema: null
|
|
161
|
+
})
|
|
162
|
+
}
|
|
157
163
|
VrpcAdapter._instances.set(instance, {
|
|
158
164
|
className,
|
|
159
165
|
instance: obj,
|
|
@@ -161,81 +167,56 @@ class VrpcAdapter {
|
|
|
161
167
|
})
|
|
162
168
|
}
|
|
163
169
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
static getMemberFunctions (className) {
|
|
169
|
-
return JSON.stringify(VrpcAdapter._getMemberFunctionsArray(className))
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
static getStaticFunctions (className) {
|
|
173
|
-
return JSON.stringify(VrpcAdapter._getStaticFunctionsArray(className))
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
static getMetaData (className) {
|
|
177
|
-
return JSON.stringify(VrpcAdapter._getMetaData(className))
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
static getInstances (className) {
|
|
181
|
-
return JSON.stringify(VrpcAdapter._getInstancesArray(className))
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
static call (jsonString) {
|
|
185
|
-
const json = JSON.parse(jsonString)
|
|
186
|
-
VrpcAdapter._call(json)
|
|
187
|
-
return JSON.stringify(json)
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
static onCallback (callback) {
|
|
191
|
-
VrpcAdapter._callback = callback
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
// convenience interface if used in parallel - as local factory and from remote
|
|
195
|
-
|
|
196
|
-
/**
|
|
197
|
-
* Creates an un-managed, anonymous instance
|
|
198
|
-
*
|
|
199
|
-
* @param {String} className Name of the class to create an instance of
|
|
200
|
-
* @param {...any} args Arguments to provide to the constructor
|
|
201
|
-
* @returns {Object} The real instance (not a proxy!)
|
|
202
|
-
*/
|
|
203
|
-
static create (className, ...args) {
|
|
204
|
-
if (typeof className === 'string') {
|
|
205
|
-
return VrpcAdapter._create(className, ...args)
|
|
206
|
-
}
|
|
207
|
-
if (typeof className === 'object') {
|
|
208
|
-
if (className.instance) {
|
|
209
|
-
return VrpcAdapter._createNamed(
|
|
210
|
-
className.className,
|
|
211
|
-
className.instance,
|
|
212
|
-
...className.args
|
|
213
|
-
)
|
|
214
|
-
}
|
|
215
|
-
return VrpcAdapter._create(className.className, ...className.args)
|
|
216
|
-
}
|
|
217
|
-
}
|
|
170
|
+
/*****************************************************
|
|
171
|
+
* convenience interface if used as plug-able factory *
|
|
172
|
+
******************************************************/
|
|
218
173
|
|
|
219
174
|
/**
|
|
220
|
-
* Creates a
|
|
175
|
+
* Creates a new instance
|
|
221
176
|
*
|
|
222
|
-
* @param {
|
|
223
|
-
* @param {String}
|
|
224
|
-
*
|
|
177
|
+
* @param {Object} options
|
|
178
|
+
* @param {String} options.className Name of the class which should be
|
|
179
|
+
* instantiated
|
|
180
|
+
* @param {String} [options.instance] Name of the created instance. If not
|
|
181
|
+
* provided an id will be generated
|
|
182
|
+
* @param {Array} [options.args] Positional arguments for the constructor call
|
|
183
|
+
* @param {bool} [options.isIsolated=false] If true the created instance will
|
|
184
|
+
* be visible only to the client who created it
|
|
225
185
|
* @returns {Object} The real instance (not a proxy!)
|
|
226
186
|
*/
|
|
227
|
-
static
|
|
228
|
-
|
|
187
|
+
static create ({
|
|
188
|
+
className,
|
|
189
|
+
instance = nanoid(8),
|
|
190
|
+
args = [],
|
|
191
|
+
isIsolated = false
|
|
192
|
+
} = {}) {
|
|
193
|
+
const json = { c: className, a: [instance, ...args] }
|
|
194
|
+
const obj = isIsolated
|
|
195
|
+
? VrpcAdapter._handleCreateIsolated(json)
|
|
196
|
+
: VrpcAdapter._handleCreateShared(json)
|
|
197
|
+
if (json.e) throw new Error(json.e)
|
|
198
|
+
return obj
|
|
229
199
|
}
|
|
230
200
|
|
|
231
201
|
/**
|
|
232
|
-
* Deletes
|
|
202
|
+
* Deletes an instance
|
|
233
203
|
*
|
|
234
|
-
* @param {String} instance
|
|
204
|
+
* @param {String|Object} instance Instance (name or object itself) to be deleted
|
|
235
205
|
* @returns {Boolean} True in case of success, false otherwise
|
|
236
206
|
*/
|
|
237
207
|
static delete (instance) {
|
|
238
|
-
|
|
208
|
+
if (typeof instance === 'string') {
|
|
209
|
+
return VrpcAdapter._delete(instance)
|
|
210
|
+
}
|
|
211
|
+
if (typeof instance === 'object') {
|
|
212
|
+
for (const [k, v] of VrpcAdapter._instances) {
|
|
213
|
+
if (v.instance === instance) {
|
|
214
|
+
VrpcAdapter._instances.delete(k)
|
|
215
|
+
return true
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
return false
|
|
219
|
+
}
|
|
239
220
|
}
|
|
240
221
|
|
|
241
222
|
/**
|
|
@@ -269,34 +250,14 @@ class VrpcAdapter {
|
|
|
269
250
|
return VrpcAdapter._getInstancesArray(className)
|
|
270
251
|
}
|
|
271
252
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
* @return {Array.<String>} Array of member function names
|
|
277
|
-
*/
|
|
278
|
-
static getAvailableMemberFunctions (className) {
|
|
279
|
-
return VrpcAdapter._getMemberFunctionsArray(className)
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
/**
|
|
283
|
-
* Provides all available static functions of a registered class.
|
|
284
|
-
*
|
|
285
|
-
* @param {String} className Name of class to provide static functions for
|
|
286
|
-
* @returns {Array.<String>} Array of static function names
|
|
287
|
-
*/
|
|
288
|
-
static getAvailableStaticFunctions (className) {
|
|
289
|
-
return VrpcAdapter._getStaticFunctionsArray(className)
|
|
253
|
+
static call (jsonString) {
|
|
254
|
+
const json = JSON.parse(jsonString)
|
|
255
|
+
VrpcAdapter._call(json)
|
|
256
|
+
return JSON.stringify(json)
|
|
290
257
|
}
|
|
291
258
|
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
*
|
|
295
|
-
* @param {String} className Name of class to provide meta data for
|
|
296
|
-
* @returns {MetaData} Meta Data
|
|
297
|
-
*/
|
|
298
|
-
static getAvailableMetaData (className) {
|
|
299
|
-
return VrpcAdapter._getMetaData(className)
|
|
259
|
+
static onCallback (callback) {
|
|
260
|
+
VrpcAdapter._callback = callback
|
|
300
261
|
}
|
|
301
262
|
|
|
302
263
|
/**
|
|
@@ -444,6 +405,7 @@ class VrpcAdapter {
|
|
|
444
405
|
VrpcAdapter._handleDelete(json)
|
|
445
406
|
break
|
|
446
407
|
default:
|
|
408
|
+
// this call may have the side-effect of taking a listener on board
|
|
447
409
|
VrpcAdapter._handleCall(json)
|
|
448
410
|
}
|
|
449
411
|
const after = Object.keys(VrpcAdapter._listeners).length
|
|
@@ -453,48 +415,71 @@ class VrpcAdapter {
|
|
|
453
415
|
}
|
|
454
416
|
|
|
455
417
|
static _handleCreateIsolated (json) {
|
|
418
|
+
let instance
|
|
456
419
|
try {
|
|
457
420
|
const className = json.c
|
|
458
421
|
const [instanceId, ...args] = json.a
|
|
459
|
-
|
|
422
|
+
instance = VrpcAdapter._create(className, instanceId, ...args)
|
|
460
423
|
VrpcAdapter._instances.set(instanceId, {
|
|
461
424
|
instance,
|
|
462
425
|
className,
|
|
463
426
|
isIsolated: true
|
|
464
427
|
})
|
|
428
|
+
VrpcAdapter._emitter.emit('create', {
|
|
429
|
+
args,
|
|
430
|
+
className,
|
|
431
|
+
isIsolated: true,
|
|
432
|
+
instance: instanceId
|
|
433
|
+
})
|
|
465
434
|
json.r = instanceId
|
|
466
435
|
} catch (err) {
|
|
467
436
|
json.e = err.message
|
|
468
437
|
}
|
|
438
|
+
return instance
|
|
469
439
|
}
|
|
470
440
|
|
|
471
441
|
static _handleCreateShared (json) {
|
|
442
|
+
let instance
|
|
472
443
|
try {
|
|
473
444
|
const className = json.c
|
|
474
445
|
const [instanceId, ...args] = json.a
|
|
475
|
-
|
|
446
|
+
instance = VrpcAdapter._create(className, instanceId, ...args)
|
|
476
447
|
VrpcAdapter._instances.set(instanceId, {
|
|
477
448
|
instance,
|
|
478
449
|
className,
|
|
479
450
|
isIsolated: false
|
|
480
451
|
})
|
|
481
452
|
json.r = instanceId
|
|
453
|
+
VrpcAdapter._emitter.emit('create', {
|
|
454
|
+
args,
|
|
455
|
+
className,
|
|
456
|
+
isIsolated: false,
|
|
457
|
+
instance: instanceId
|
|
458
|
+
})
|
|
482
459
|
} catch (err) {
|
|
483
460
|
json.e = err.message
|
|
484
461
|
}
|
|
462
|
+
return instance
|
|
485
463
|
}
|
|
486
464
|
|
|
487
465
|
static _handleCallAll (json) {
|
|
488
466
|
try {
|
|
489
467
|
const calls = []
|
|
490
|
-
for (const [
|
|
491
|
-
|
|
492
|
-
|
|
468
|
+
for (const [
|
|
469
|
+
id,
|
|
470
|
+
{ className, instance, isIsolated }
|
|
471
|
+
] of VrpcAdapter._instances) {
|
|
472
|
+
// TODO Think about a configurable behavior w.r.t. isolated instances...
|
|
473
|
+
if (className !== json.c || isIsolated) continue
|
|
474
|
+
let v = true
|
|
493
475
|
let e = null
|
|
494
476
|
try {
|
|
495
|
-
const
|
|
496
|
-
|
|
497
|
-
|
|
477
|
+
const unwrapped = VrpcAdapter._unwrapArguments(json, id)
|
|
478
|
+
if (unwrapped) {
|
|
479
|
+
const funcName = unwrapped[0]
|
|
480
|
+
v = instance[funcName].apply(instance, unwrapped.slice(1))
|
|
481
|
+
v = VrpcAdapter.sanitizeEventListenerReturnValues(v)
|
|
482
|
+
}
|
|
498
483
|
} catch (err) {
|
|
499
484
|
e = err.message
|
|
500
485
|
}
|
|
@@ -514,14 +499,21 @@ class VrpcAdapter {
|
|
|
514
499
|
}
|
|
515
500
|
}
|
|
516
501
|
|
|
502
|
+
static sanitizeEventListenerReturnValues (ret) {
|
|
503
|
+
return typeof ret === 'object' &&
|
|
504
|
+
ret._events !== undefined &&
|
|
505
|
+
ret._eventsCount !== undefined
|
|
506
|
+
? true
|
|
507
|
+
: ret
|
|
508
|
+
}
|
|
509
|
+
|
|
517
510
|
static _handleDelete (json) {
|
|
518
511
|
try {
|
|
519
|
-
const
|
|
520
|
-
|
|
521
|
-
json.r = VrpcAdapter._delete(instanceId)
|
|
512
|
+
const instance = json.a[0] // first arg is instance to be deleted
|
|
513
|
+
json.r = VrpcAdapter._delete(instance)
|
|
522
514
|
VrpcAdapter._emitter.emit('delete', {
|
|
523
|
-
|
|
524
|
-
|
|
515
|
+
instance,
|
|
516
|
+
className: json.c
|
|
525
517
|
})
|
|
526
518
|
} catch (err) {
|
|
527
519
|
json.e = err.message
|
|
@@ -529,7 +521,18 @@ class VrpcAdapter {
|
|
|
529
521
|
}
|
|
530
522
|
|
|
531
523
|
static _handleCall (json) {
|
|
532
|
-
|
|
524
|
+
// special case: removeAllListeners
|
|
525
|
+
if (json.f === 'removeAllListeners') {
|
|
526
|
+
VrpcAdapter._removeAllListeners(json.a[0], json.s, json.c)
|
|
527
|
+
json.r = true
|
|
528
|
+
return
|
|
529
|
+
}
|
|
530
|
+
const unwrapped = VrpcAdapter._unwrapArguments(json)
|
|
531
|
+
if (!unwrapped) {
|
|
532
|
+
// this call must be skipped (event emitter stuff)
|
|
533
|
+
json.r = true
|
|
534
|
+
return
|
|
535
|
+
}
|
|
533
536
|
// Check whether context is a registered class
|
|
534
537
|
const entry = VrpcAdapter._functionRegistry.get(json.c)
|
|
535
538
|
if (entry !== undefined) {
|
|
@@ -541,7 +544,7 @@ class VrpcAdapter {
|
|
|
541
544
|
// subscription against all functions
|
|
542
545
|
if (VrpcAdapter._isFunction(Klass[json.f])) {
|
|
543
546
|
try {
|
|
544
|
-
const ret = Klass[json.f].apply(null,
|
|
547
|
+
const ret = Klass[json.f].apply(null, unwrapped)
|
|
545
548
|
// check if function returns promise
|
|
546
549
|
if (VrpcAdapter._isPromise(ret)) {
|
|
547
550
|
this._handlePromise(json, ret)
|
|
@@ -559,7 +562,8 @@ class VrpcAdapter {
|
|
|
559
562
|
const { instance } = entry
|
|
560
563
|
if (VrpcAdapter._isFunction(instance[json.f])) {
|
|
561
564
|
try {
|
|
562
|
-
|
|
565
|
+
let ret = instance[json.f].apply(instance, unwrapped)
|
|
566
|
+
ret = VrpcAdapter.sanitizeEventListenerReturnValues(ret)
|
|
563
567
|
// check if function returns promise
|
|
564
568
|
if (VrpcAdapter._isPromise(ret)) {
|
|
565
569
|
this._handlePromise(json, ret)
|
|
@@ -585,31 +589,35 @@ class VrpcAdapter {
|
|
|
585
589
|
static _delete (instanceId) {
|
|
586
590
|
const entry = VrpcAdapter._instances.get(instanceId)
|
|
587
591
|
if (entry) {
|
|
592
|
+
// in case the instance was an EventEmitter, free all registered listeners
|
|
593
|
+
if (VrpcAdapter._isFunction(entry.removeAllListeners)) {
|
|
594
|
+
entry.removeAllListeners()
|
|
595
|
+
}
|
|
596
|
+
for (const [key, { clients, instance }] of Object.entries(
|
|
597
|
+
VrpcAdapter._listeners
|
|
598
|
+
)) {
|
|
599
|
+
if (instance === instanceId) {
|
|
600
|
+
VrpcAdapter._listeners[key] = { clients }
|
|
601
|
+
}
|
|
602
|
+
}
|
|
588
603
|
VrpcAdapter._instances.delete(instanceId)
|
|
589
604
|
return true
|
|
590
605
|
}
|
|
591
606
|
return false
|
|
592
607
|
}
|
|
593
608
|
|
|
594
|
-
static
|
|
595
|
-
const listeners = VrpcAdapter._listeners[clientId]
|
|
596
|
-
if (listeners) {
|
|
597
|
-
listeners.forEach(({ i, e, f }) => {
|
|
598
|
-
VrpcAdapter.getInstance(i).removeListener(e, f)
|
|
599
|
-
})
|
|
600
|
-
}
|
|
601
|
-
delete VrpcAdapter._listeners[clientId]
|
|
602
|
-
}
|
|
603
|
-
|
|
604
|
-
static _unregisterEventListenersOfInstance (instance) {
|
|
609
|
+
static _unregisterClient (clientId) {
|
|
605
610
|
for (const [key, value] of Object.entries(VrpcAdapter._listeners)) {
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
611
|
+
const { instances, event, listener, clients } = value
|
|
612
|
+
clients.delete(clientId)
|
|
613
|
+
if (clients.size === 0) {
|
|
614
|
+
if (event) {
|
|
615
|
+
instances.forEach(instance => {
|
|
616
|
+
VrpcAdapter.getInstance(instance).removeListener(event, listener)
|
|
617
|
+
})
|
|
610
618
|
}
|
|
611
|
-
|
|
612
|
-
}
|
|
619
|
+
delete VrpcAdapter._listeners[key]
|
|
620
|
+
}
|
|
613
621
|
}
|
|
614
622
|
}
|
|
615
623
|
|
|
@@ -621,51 +629,101 @@ class VrpcAdapter {
|
|
|
621
629
|
if (!valid) throw new Error(VrpcAdapter._ajv.errorsText())
|
|
622
630
|
}
|
|
623
631
|
|
|
624
|
-
static
|
|
625
|
-
const
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
632
|
+
static _unwrapArguments (json, instanceId) {
|
|
633
|
+
const sender = json.s
|
|
634
|
+
let context = json.c
|
|
635
|
+
let func = json.f
|
|
636
|
+
let args = json.a
|
|
637
|
+
// things are different if we came from callAll (instanceId !== undefined)
|
|
638
|
+
if (instanceId) {
|
|
639
|
+
context = instanceId
|
|
640
|
+
func = args[0]
|
|
641
|
+
args = args.slice(1)
|
|
642
|
+
}
|
|
643
|
+
const unwrapped = instanceId ? [func] : []
|
|
644
|
+
for (const arg of args) {
|
|
645
|
+
// find those args that actually need to be functions
|
|
646
|
+
if (typeof arg === 'string' && arg.slice(0, 5) === '__f__') {
|
|
647
|
+
const callback = this._generateCallback(arg, sender, instanceId)
|
|
648
|
+
unwrapped.push(callback)
|
|
649
|
+
} else if (typeof arg === 'string' && arg.slice(0, 5) === '__e__') {
|
|
650
|
+
const listener = this._generateListener(arg, sender, instanceId)
|
|
651
|
+
unwrapped.push(listener)
|
|
652
|
+
// start tracking clients that are registering event listeners
|
|
653
|
+
if (!VrpcAdapter._listeners[arg]) {
|
|
654
|
+
VrpcAdapter._listeners[arg] = {
|
|
655
|
+
listener,
|
|
656
|
+
clients: new Set([sender]),
|
|
657
|
+
instances: new Set(),
|
|
658
|
+
event: null
|
|
659
|
+
}
|
|
660
|
+
} else {
|
|
661
|
+
VrpcAdapter._listeners[arg].clients.add(sender)
|
|
641
662
|
}
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
663
|
+
// see whether the requested listener is an EventEmitter registration
|
|
664
|
+
if (func === 'on' || func === 'addListener') {
|
|
665
|
+
// if this event is already registered on the given instance
|
|
666
|
+
// avoid a second registration
|
|
667
|
+
if (
|
|
668
|
+
VrpcAdapter._listeners[arg].event &&
|
|
669
|
+
VrpcAdapter._listeners[arg].instances.has(context)
|
|
670
|
+
) {
|
|
671
|
+
return null // means that this call won't be forwarded
|
|
651
672
|
}
|
|
673
|
+
VrpcAdapter._listeners[arg].event = args[0]
|
|
674
|
+
VrpcAdapter._listeners[arg].instances.add(context)
|
|
675
|
+
}
|
|
676
|
+
if (func === 'off' || func === 'removeListener') {
|
|
677
|
+
const {
|
|
678
|
+
clients,
|
|
679
|
+
instances,
|
|
680
|
+
listener,
|
|
681
|
+
event
|
|
682
|
+
} = VrpcAdapter._listeners[arg]
|
|
683
|
+
clients.delete(sender)
|
|
684
|
+
instances.delete(context)
|
|
685
|
+
if (clients.size === 0) {
|
|
686
|
+
delete VrpcAdapter._listeners[arg]
|
|
687
|
+
VrpcAdapter.getInstance(context).off(event, listener)
|
|
688
|
+
}
|
|
689
|
+
return null // means that this call won't be forwarded
|
|
652
690
|
}
|
|
653
691
|
} else {
|
|
654
|
-
//
|
|
655
|
-
|
|
692
|
+
// default behavior is to not touch
|
|
693
|
+
unwrapped.push(arg)
|
|
656
694
|
}
|
|
657
|
-
}
|
|
658
|
-
return
|
|
695
|
+
}
|
|
696
|
+
return unwrapped
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
static _removeAllListeners (event, sender, context) {
|
|
700
|
+
for (const [key, value] of Object.entries(VrpcAdapter._listeners)) {
|
|
701
|
+
if (value.event === event) {
|
|
702
|
+
value.clients.delete(sender)
|
|
703
|
+
if (value.clients.size === 0) {
|
|
704
|
+
delete VrpcAdapter._listeners[key]
|
|
705
|
+
VrpcAdapter.getInstance(context).off(event, value.listener)
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
static _generateCallback (id, sender, instanceId) {
|
|
712
|
+
return (...innerArgs) => {
|
|
713
|
+
// callAll expects the instanceId as first argument
|
|
714
|
+
const a = instanceId ? [instanceId, ...innerArgs] : [...innerArgs]
|
|
715
|
+
VrpcAdapter._callback({ a, s: sender, i: id })
|
|
716
|
+
}
|
|
659
717
|
}
|
|
660
718
|
|
|
661
|
-
static
|
|
662
|
-
|
|
663
|
-
// do not even
|
|
664
|
-
if (
|
|
719
|
+
static _generateListener (id, sender, instanceId) {
|
|
720
|
+
return (...innerArgs) => {
|
|
721
|
+
// do not even emit for already offline clients
|
|
722
|
+
if (!VrpcAdapter._listeners[id]) return
|
|
723
|
+
// callAll expects the instanceId as first argument
|
|
665
724
|
const a = instanceId ? [instanceId, ...innerArgs] : [...innerArgs]
|
|
666
|
-
VrpcAdapter._callback({ a, s:
|
|
725
|
+
VrpcAdapter._callback({ a, s: sender, i: id })
|
|
667
726
|
}
|
|
668
|
-
return wrapper
|
|
669
727
|
}
|
|
670
728
|
|
|
671
729
|
static _handlePromise (json, promise) {
|
|
@@ -792,7 +850,7 @@ class VrpcAdapter {
|
|
|
792
850
|
/**
|
|
793
851
|
* Event 'create'
|
|
794
852
|
*
|
|
795
|
-
* Emitted on creation of
|
|
853
|
+
* Emitted on creation of shared instance
|
|
796
854
|
*
|
|
797
855
|
* @event VrpcAdapter#create
|
|
798
856
|
* @type {Object}
|
|
@@ -804,7 +862,7 @@ class VrpcAdapter {
|
|
|
804
862
|
/**
|
|
805
863
|
* Event 'delete'
|
|
806
864
|
*
|
|
807
|
-
* Emitted on deletion of
|
|
865
|
+
* Emitted on deletion of shared instance
|
|
808
866
|
*
|
|
809
867
|
* @event VrpcAdapter#delete
|
|
810
868
|
* @type {Object}
|