vrpc 3.0.0-alpha.1 → 3.0.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 +63 -2
- package/LICENSE +1 -1
- package/README.md +12 -15
- package/browser/vrpc.js +1 -1
- package/package.json +8 -5
- package/vrpc/VrpcAdapter.js +234 -161
- package/vrpc/VrpcAgent.js +25 -18
- 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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vrpc",
|
|
3
|
-
"version": "3.0.
|
|
3
|
+
"version": "3.0.1",
|
|
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
|
/**
|
|
@@ -429,6 +390,7 @@ class VrpcAdapter {
|
|
|
429
390
|
}
|
|
430
391
|
|
|
431
392
|
static _call (json) {
|
|
393
|
+
const before = Object.keys(VrpcAdapter._listeners).length
|
|
432
394
|
switch (json.f) {
|
|
433
395
|
case '__createIsolated__':
|
|
434
396
|
VrpcAdapter._handleCreateIsolated(json)
|
|
@@ -443,53 +405,81 @@ class VrpcAdapter {
|
|
|
443
405
|
VrpcAdapter._handleDelete(json)
|
|
444
406
|
break
|
|
445
407
|
default:
|
|
408
|
+
// this call may have the side-effect of taking a listener on board
|
|
446
409
|
VrpcAdapter._handleCall(json)
|
|
447
410
|
}
|
|
411
|
+
const after = Object.keys(VrpcAdapter._listeners).length
|
|
412
|
+
// if we took a listener on board we must tell our caller such that
|
|
413
|
+
// things can be cleaned up later.
|
|
414
|
+
return after > before
|
|
448
415
|
}
|
|
449
416
|
|
|
450
417
|
static _handleCreateIsolated (json) {
|
|
418
|
+
let instance
|
|
451
419
|
try {
|
|
452
420
|
const className = json.c
|
|
453
421
|
const [instanceId, ...args] = json.a
|
|
454
|
-
|
|
422
|
+
instance = VrpcAdapter._create(className, instanceId, ...args)
|
|
455
423
|
VrpcAdapter._instances.set(instanceId, {
|
|
456
424
|
instance,
|
|
457
425
|
className,
|
|
458
426
|
isIsolated: true
|
|
459
427
|
})
|
|
428
|
+
VrpcAdapter._emitter.emit('create', {
|
|
429
|
+
args,
|
|
430
|
+
className,
|
|
431
|
+
isIsolated: true,
|
|
432
|
+
instance: instanceId
|
|
433
|
+
})
|
|
460
434
|
json.r = instanceId
|
|
461
435
|
} catch (err) {
|
|
462
436
|
json.e = err.message
|
|
463
437
|
}
|
|
438
|
+
return instance
|
|
464
439
|
}
|
|
465
440
|
|
|
466
441
|
static _handleCreateShared (json) {
|
|
442
|
+
let instance
|
|
467
443
|
try {
|
|
468
444
|
const className = json.c
|
|
469
445
|
const [instanceId, ...args] = json.a
|
|
470
|
-
|
|
446
|
+
instance = VrpcAdapter._create(className, instanceId, ...args)
|
|
471
447
|
VrpcAdapter._instances.set(instanceId, {
|
|
472
448
|
instance,
|
|
473
449
|
className,
|
|
474
450
|
isIsolated: false
|
|
475
451
|
})
|
|
476
452
|
json.r = instanceId
|
|
453
|
+
VrpcAdapter._emitter.emit('create', {
|
|
454
|
+
args,
|
|
455
|
+
className,
|
|
456
|
+
isIsolated: false,
|
|
457
|
+
instance: instanceId
|
|
458
|
+
})
|
|
477
459
|
} catch (err) {
|
|
478
460
|
json.e = err.message
|
|
479
461
|
}
|
|
462
|
+
return instance
|
|
480
463
|
}
|
|
481
464
|
|
|
482
465
|
static _handleCallAll (json) {
|
|
483
466
|
try {
|
|
484
467
|
const calls = []
|
|
485
|
-
for (const [
|
|
486
|
-
|
|
487
|
-
|
|
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
|
|
488
475
|
let e = null
|
|
489
476
|
try {
|
|
490
|
-
const
|
|
491
|
-
|
|
492
|
-
|
|
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
|
+
}
|
|
493
483
|
} catch (err) {
|
|
494
484
|
e = err.message
|
|
495
485
|
}
|
|
@@ -509,14 +499,21 @@ class VrpcAdapter {
|
|
|
509
499
|
}
|
|
510
500
|
}
|
|
511
501
|
|
|
502
|
+
static sanitizeEventListenerReturnValues (ret) {
|
|
503
|
+
return typeof ret === 'object' &&
|
|
504
|
+
ret._events !== undefined &&
|
|
505
|
+
ret._eventsCount !== undefined
|
|
506
|
+
? true
|
|
507
|
+
: ret
|
|
508
|
+
}
|
|
509
|
+
|
|
512
510
|
static _handleDelete (json) {
|
|
513
511
|
try {
|
|
514
|
-
const
|
|
515
|
-
|
|
516
|
-
json.r = VrpcAdapter._delete(instanceId)
|
|
512
|
+
const instance = json.a[0] // first arg is instance to be deleted
|
|
513
|
+
json.r = VrpcAdapter._delete(instance)
|
|
517
514
|
VrpcAdapter._emitter.emit('delete', {
|
|
518
|
-
|
|
519
|
-
|
|
515
|
+
instance,
|
|
516
|
+
className: json.c
|
|
520
517
|
})
|
|
521
518
|
} catch (err) {
|
|
522
519
|
json.e = err.message
|
|
@@ -524,7 +521,18 @@ class VrpcAdapter {
|
|
|
524
521
|
}
|
|
525
522
|
|
|
526
523
|
static _handleCall (json) {
|
|
527
|
-
|
|
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
|
+
}
|
|
528
536
|
// Check whether context is a registered class
|
|
529
537
|
const entry = VrpcAdapter._functionRegistry.get(json.c)
|
|
530
538
|
if (entry !== undefined) {
|
|
@@ -536,7 +544,7 @@ class VrpcAdapter {
|
|
|
536
544
|
// subscription against all functions
|
|
537
545
|
if (VrpcAdapter._isFunction(Klass[json.f])) {
|
|
538
546
|
try {
|
|
539
|
-
const ret = Klass[json.f].apply(null,
|
|
547
|
+
const ret = Klass[json.f].apply(null, unwrapped)
|
|
540
548
|
// check if function returns promise
|
|
541
549
|
if (VrpcAdapter._isPromise(ret)) {
|
|
542
550
|
this._handlePromise(json, ret)
|
|
@@ -554,7 +562,8 @@ class VrpcAdapter {
|
|
|
554
562
|
const { instance } = entry
|
|
555
563
|
if (VrpcAdapter._isFunction(instance[json.f])) {
|
|
556
564
|
try {
|
|
557
|
-
|
|
565
|
+
let ret = instance[json.f].apply(instance, unwrapped)
|
|
566
|
+
ret = VrpcAdapter.sanitizeEventListenerReturnValues(ret)
|
|
558
567
|
// check if function returns promise
|
|
559
568
|
if (VrpcAdapter._isPromise(ret)) {
|
|
560
569
|
this._handlePromise(json, ret)
|
|
@@ -580,20 +589,34 @@ class VrpcAdapter {
|
|
|
580
589
|
static _delete (instanceId) {
|
|
581
590
|
const entry = VrpcAdapter._instances.get(instanceId)
|
|
582
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
|
+
}
|
|
583
603
|
VrpcAdapter._instances.delete(instanceId)
|
|
584
604
|
return true
|
|
585
605
|
}
|
|
586
606
|
return false
|
|
587
607
|
}
|
|
588
608
|
|
|
589
|
-
static
|
|
590
|
-
const
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
609
|
+
static _unregisterClient (clientId) {
|
|
610
|
+
for (const [key, value] of Object.entries(VrpcAdapter._listeners)) {
|
|
611
|
+
const { instance, event, listener, clients } = value
|
|
612
|
+
clients.delete(clientId)
|
|
613
|
+
if (clients.size === 0) {
|
|
614
|
+
if (event) {
|
|
615
|
+
VrpcAdapter.getInstance(instance).removeListener(event, listener)
|
|
616
|
+
}
|
|
617
|
+
delete VrpcAdapter._listeners[key]
|
|
618
|
+
}
|
|
595
619
|
}
|
|
596
|
-
delete VrpcAdapter._listeners[clientId]
|
|
597
620
|
}
|
|
598
621
|
|
|
599
622
|
static _validate (schema, params) {
|
|
@@ -604,51 +627,101 @@ class VrpcAdapter {
|
|
|
604
627
|
if (!valid) throw new Error(VrpcAdapter._ajv.errorsText())
|
|
605
628
|
}
|
|
606
629
|
|
|
607
|
-
static
|
|
608
|
-
const
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
630
|
+
static _unwrapArguments (json, instanceId) {
|
|
631
|
+
const sender = json.s
|
|
632
|
+
let context = json.c
|
|
633
|
+
let func = json.f
|
|
634
|
+
let args = json.a
|
|
635
|
+
// things are different if we came from callAll (instanceId !== undefined)
|
|
636
|
+
if (instanceId) {
|
|
637
|
+
context = instanceId
|
|
638
|
+
func = args[0]
|
|
639
|
+
args = args.slice(1)
|
|
640
|
+
}
|
|
641
|
+
const unwrapped = instanceId ? [func] : []
|
|
642
|
+
for (const arg of args) {
|
|
643
|
+
// find those args that actually need to be functions
|
|
644
|
+
if (typeof arg === 'string' && arg.slice(0, 5) === '__f__') {
|
|
645
|
+
const callback = this._generateCallback(arg, sender, instanceId)
|
|
646
|
+
unwrapped.push(callback)
|
|
647
|
+
} else if (typeof arg === 'string' && arg.slice(0, 5) === '__e__') {
|
|
648
|
+
const listener = this._generateListener(arg, sender, instanceId)
|
|
649
|
+
unwrapped.push(listener)
|
|
650
|
+
// start tracking clients that are registering event listeners
|
|
651
|
+
if (!VrpcAdapter._listeners[arg]) {
|
|
652
|
+
VrpcAdapter._listeners[arg] = {
|
|
653
|
+
listener,
|
|
654
|
+
clients: new Set([sender]),
|
|
655
|
+
instances: new Set(),
|
|
656
|
+
event: null
|
|
657
|
+
}
|
|
658
|
+
} else {
|
|
659
|
+
VrpcAdapter._listeners[arg].clients.add(sender)
|
|
660
|
+
}
|
|
661
|
+
// see whether the requested listener is an EventEmitter registration
|
|
662
|
+
if (func === 'on' || func === 'addListener') {
|
|
663
|
+
// if this event is already registered on the given instance
|
|
664
|
+
// avoid a second registration
|
|
665
|
+
if (
|
|
666
|
+
VrpcAdapter._listeners[arg].event &&
|
|
667
|
+
VrpcAdapter._listeners[arg].instances.has(context)
|
|
668
|
+
) {
|
|
669
|
+
return null // means that this call won't be forwarded
|
|
670
|
+
}
|
|
671
|
+
VrpcAdapter._listeners[arg].event = args[0]
|
|
672
|
+
VrpcAdapter._listeners[arg].instances.add(context)
|
|
624
673
|
}
|
|
625
|
-
if (
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
674
|
+
if (func === 'off' || func === 'removeListener') {
|
|
675
|
+
const {
|
|
676
|
+
clients,
|
|
677
|
+
instances,
|
|
678
|
+
listener,
|
|
679
|
+
event
|
|
680
|
+
} = VrpcAdapter._listeners[arg]
|
|
681
|
+
clients.delete(sender)
|
|
682
|
+
instances.delete(context)
|
|
683
|
+
if (clients.size === 0) {
|
|
684
|
+
delete VrpcAdapter._listeners[arg]
|
|
685
|
+
VrpcAdapter.getInstance(context).off(event, listener)
|
|
634
686
|
}
|
|
687
|
+
return null // means that this call won't be forwarded
|
|
635
688
|
}
|
|
636
689
|
} else {
|
|
637
|
-
//
|
|
638
|
-
|
|
690
|
+
// default behavior is to not touch
|
|
691
|
+
unwrapped.push(arg)
|
|
639
692
|
}
|
|
640
|
-
}
|
|
641
|
-
return
|
|
693
|
+
}
|
|
694
|
+
return unwrapped
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
static _removeAllListeners (event, sender, context) {
|
|
698
|
+
for (const [key, value] of Object.entries(VrpcAdapter._listeners)) {
|
|
699
|
+
if (value.event === event) {
|
|
700
|
+
value.clients.delete(sender)
|
|
701
|
+
if (value.clients.size === 0) {
|
|
702
|
+
delete VrpcAdapter._listeners[key]
|
|
703
|
+
VrpcAdapter.getInstance(context).off(event, value.listener)
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
static _generateCallback (id, sender, instanceId) {
|
|
710
|
+
return (...innerArgs) => {
|
|
711
|
+
// callAll expects the instanceId as first argument
|
|
712
|
+
const a = instanceId ? [instanceId, ...innerArgs] : [...innerArgs]
|
|
713
|
+
VrpcAdapter._callback({ a, s: sender, i: id })
|
|
714
|
+
}
|
|
642
715
|
}
|
|
643
716
|
|
|
644
|
-
static
|
|
645
|
-
|
|
646
|
-
// do not even
|
|
647
|
-
if (
|
|
717
|
+
static _generateListener (id, sender, instanceId) {
|
|
718
|
+
return (...innerArgs) => {
|
|
719
|
+
// do not even emit for already offline clients
|
|
720
|
+
if (!VrpcAdapter._listeners[id]) return
|
|
721
|
+
// callAll expects the instanceId as first argument
|
|
648
722
|
const a = instanceId ? [instanceId, ...innerArgs] : [...innerArgs]
|
|
649
|
-
VrpcAdapter._callback({
|
|
723
|
+
VrpcAdapter._callback({ a, s: sender, i: id })
|
|
650
724
|
}
|
|
651
|
-
return wrapper
|
|
652
725
|
}
|
|
653
726
|
|
|
654
727
|
static _handlePromise (json, promise) {
|
|
@@ -775,7 +848,7 @@ class VrpcAdapter {
|
|
|
775
848
|
/**
|
|
776
849
|
* Event 'create'
|
|
777
850
|
*
|
|
778
|
-
* Emitted on creation of
|
|
851
|
+
* Emitted on creation of shared instance
|
|
779
852
|
*
|
|
780
853
|
* @event VrpcAdapter#create
|
|
781
854
|
* @type {Object}
|
|
@@ -787,7 +860,7 @@ class VrpcAdapter {
|
|
|
787
860
|
/**
|
|
788
861
|
* Event 'delete'
|
|
789
862
|
*
|
|
790
|
-
* Emitted on deletion of
|
|
863
|
+
* Emitted on deletion of shared instance
|
|
791
864
|
*
|
|
792
865
|
* @event VrpcAdapter#delete
|
|
793
866
|
* @type {Object}
|