vrpc 3.0.0-alpha.3 → 3.0.3
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 +53 -0
- package/LICENSE +1 -1
- package/README.md +8 -9
- package/browser/vrpc.js +1 -1
- package/package.json +8 -5
- package/vrpc/VrpcAdapter.js +209 -171
- package/vrpc/VrpcAgent.js +32 -27
- package/vrpc/VrpcClient.js +273 -119
- 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.3",
|
|
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,7 +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 {
|
|
47
|
+
const { nanoid } = require('nanoid')
|
|
48
48
|
|
|
49
49
|
/**
|
|
50
50
|
* Generates an adapter layer for existing code and enables further VRPC-based
|
|
@@ -105,13 +105,16 @@ class VrpcAdapter {
|
|
|
105
105
|
if (typeof code === 'string') {
|
|
106
106
|
const absPath = path.resolve(caller(), '../', code)
|
|
107
107
|
const relPath = path.relative(__dirname, absPath)
|
|
108
|
-
const absJsdocPath =
|
|
108
|
+
const absJsdocPath =
|
|
109
|
+
absPath && absPath.endsWith('.js') ? absPath : `${absPath}.js`
|
|
109
110
|
const Klass = require(relPath)
|
|
110
111
|
this._registerClass(Klass, absJsdocPath, options)
|
|
111
112
|
} else {
|
|
112
113
|
const { jsdocPath } = options
|
|
114
|
+
const sJsdocPath =
|
|
115
|
+
jsdocPath && jsdocPath.endsWith('.js') ? jsdocPath : `${jsdocPath}.js`
|
|
113
116
|
if (jsdocPath) {
|
|
114
|
-
const absJsdocPath = path.resolve(caller(), '../',
|
|
117
|
+
const absJsdocPath = path.resolve(caller(), '../', sJsdocPath)
|
|
115
118
|
this._registerClass(code, absJsdocPath, { ...options, jsdoc: true })
|
|
116
119
|
} else {
|
|
117
120
|
this._registerClass(code, null, options)
|
|
@@ -147,14 +150,16 @@ class VrpcAdapter {
|
|
|
147
150
|
const content = fs.readFileSync(absJsdocPath).toString('utf8')
|
|
148
151
|
meta = this._parseComments(content)
|
|
149
152
|
}
|
|
150
|
-
VrpcAdapter._functionRegistry.
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
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
|
+
}
|
|
158
163
|
VrpcAdapter._instances.set(instance, {
|
|
159
164
|
className,
|
|
160
165
|
instance: obj,
|
|
@@ -162,81 +167,56 @@ class VrpcAdapter {
|
|
|
162
167
|
})
|
|
163
168
|
}
|
|
164
169
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
static getMemberFunctions (className) {
|
|
170
|
-
return JSON.stringify(VrpcAdapter._getMemberFunctionsArray(className))
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
static getStaticFunctions (className) {
|
|
174
|
-
return JSON.stringify(VrpcAdapter._getStaticFunctionsArray(className))
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
static getMetaData (className) {
|
|
178
|
-
return JSON.stringify(VrpcAdapter._getMetaData(className))
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
static getInstances (className) {
|
|
182
|
-
return JSON.stringify(VrpcAdapter._getInstancesArray(className))
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
static call (jsonString) {
|
|
186
|
-
const json = JSON.parse(jsonString)
|
|
187
|
-
VrpcAdapter._call(json)
|
|
188
|
-
return JSON.stringify(json)
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
static onCallback (callback) {
|
|
192
|
-
VrpcAdapter._callback = callback
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// convenience interface if used in parallel - as local factory and from remote
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Creates an un-managed, anonymous instance
|
|
199
|
-
*
|
|
200
|
-
* @param {String} className Name of the class to create an instance of
|
|
201
|
-
* @param {...any} args Arguments to provide to the constructor
|
|
202
|
-
* @returns {Object} The real instance (not a proxy!)
|
|
203
|
-
*/
|
|
204
|
-
static create (className, ...args) {
|
|
205
|
-
if (typeof className === 'string') {
|
|
206
|
-
return VrpcAdapter._create(className, ...args)
|
|
207
|
-
}
|
|
208
|
-
if (typeof className === 'object') {
|
|
209
|
-
if (className.instance) {
|
|
210
|
-
return VrpcAdapter._createNamed(
|
|
211
|
-
className.className,
|
|
212
|
-
className.instance,
|
|
213
|
-
...className.args
|
|
214
|
-
)
|
|
215
|
-
}
|
|
216
|
-
return VrpcAdapter._create(className.className, ...className.args)
|
|
217
|
-
}
|
|
218
|
-
}
|
|
170
|
+
/*****************************************************
|
|
171
|
+
* convenience interface if used as plug-able factory *
|
|
172
|
+
******************************************************/
|
|
219
173
|
|
|
220
174
|
/**
|
|
221
|
-
* Creates a
|
|
175
|
+
* Creates a new instance
|
|
222
176
|
*
|
|
223
|
-
* @param {
|
|
224
|
-
* @param {String}
|
|
225
|
-
*
|
|
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
|
|
226
185
|
* @returns {Object} The real instance (not a proxy!)
|
|
227
186
|
*/
|
|
228
|
-
static
|
|
229
|
-
|
|
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
|
|
230
199
|
}
|
|
231
200
|
|
|
232
201
|
/**
|
|
233
|
-
* Deletes
|
|
202
|
+
* Deletes an instance
|
|
234
203
|
*
|
|
235
|
-
* @param {String} instance
|
|
204
|
+
* @param {String|Object} instance Instance (name or object itself) to be deleted
|
|
236
205
|
* @returns {Boolean} True in case of success, false otherwise
|
|
237
206
|
*/
|
|
238
207
|
static delete (instance) {
|
|
239
|
-
|
|
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
|
+
}
|
|
240
220
|
}
|
|
241
221
|
|
|
242
222
|
/**
|
|
@@ -270,34 +250,14 @@ class VrpcAdapter {
|
|
|
270
250
|
return VrpcAdapter._getInstancesArray(className)
|
|
271
251
|
}
|
|
272
252
|
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
* @return {Array.<String>} Array of member function names
|
|
278
|
-
*/
|
|
279
|
-
static getAvailableMemberFunctions (className) {
|
|
280
|
-
return VrpcAdapter._getMemberFunctionsArray(className)
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
/**
|
|
284
|
-
* Provides all available static functions of a registered class.
|
|
285
|
-
*
|
|
286
|
-
* @param {String} className Name of class to provide static functions for
|
|
287
|
-
* @returns {Array.<String>} Array of static function names
|
|
288
|
-
*/
|
|
289
|
-
static getAvailableStaticFunctions (className) {
|
|
290
|
-
return VrpcAdapter._getStaticFunctionsArray(className)
|
|
253
|
+
static call (jsonString) {
|
|
254
|
+
const json = JSON.parse(jsonString)
|
|
255
|
+
VrpcAdapter._call(json)
|
|
256
|
+
return JSON.stringify(json)
|
|
291
257
|
}
|
|
292
258
|
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
*
|
|
296
|
-
* @param {String} className Name of class to provide meta data for
|
|
297
|
-
* @returns {MetaData} Meta Data
|
|
298
|
-
*/
|
|
299
|
-
static getAvailableMetaData (className) {
|
|
300
|
-
return VrpcAdapter._getMetaData(className)
|
|
259
|
+
static onCallback (callback) {
|
|
260
|
+
VrpcAdapter._callback = callback
|
|
301
261
|
}
|
|
302
262
|
|
|
303
263
|
/**
|
|
@@ -445,6 +405,7 @@ class VrpcAdapter {
|
|
|
445
405
|
VrpcAdapter._handleDelete(json)
|
|
446
406
|
break
|
|
447
407
|
default:
|
|
408
|
+
// this call may have the side-effect of taking a listener on board
|
|
448
409
|
VrpcAdapter._handleCall(json)
|
|
449
410
|
}
|
|
450
411
|
const after = Object.keys(VrpcAdapter._listeners).length
|
|
@@ -454,26 +415,35 @@ class VrpcAdapter {
|
|
|
454
415
|
}
|
|
455
416
|
|
|
456
417
|
static _handleCreateIsolated (json) {
|
|
418
|
+
let instance
|
|
457
419
|
try {
|
|
458
420
|
const className = json.c
|
|
459
421
|
const [instanceId, ...args] = json.a
|
|
460
|
-
|
|
422
|
+
instance = VrpcAdapter._create(className, instanceId, ...args)
|
|
461
423
|
VrpcAdapter._instances.set(instanceId, {
|
|
462
424
|
instance,
|
|
463
425
|
className,
|
|
464
426
|
isIsolated: true
|
|
465
427
|
})
|
|
428
|
+
VrpcAdapter._emitter.emit('create', {
|
|
429
|
+
args,
|
|
430
|
+
className,
|
|
431
|
+
isIsolated: true,
|
|
432
|
+
instance: instanceId
|
|
433
|
+
})
|
|
466
434
|
json.r = instanceId
|
|
467
435
|
} catch (err) {
|
|
468
436
|
json.e = err.message
|
|
469
437
|
}
|
|
438
|
+
return instance
|
|
470
439
|
}
|
|
471
440
|
|
|
472
441
|
static _handleCreateShared (json) {
|
|
442
|
+
let instance
|
|
473
443
|
try {
|
|
474
444
|
const className = json.c
|
|
475
445
|
const [instanceId, ...args] = json.a
|
|
476
|
-
|
|
446
|
+
instance = VrpcAdapter._create(className, instanceId, ...args)
|
|
477
447
|
VrpcAdapter._instances.set(instanceId, {
|
|
478
448
|
instance,
|
|
479
449
|
className,
|
|
@@ -483,11 +453,13 @@ class VrpcAdapter {
|
|
|
483
453
|
VrpcAdapter._emitter.emit('create', {
|
|
484
454
|
args,
|
|
485
455
|
className,
|
|
456
|
+
isIsolated: false,
|
|
486
457
|
instance: instanceId
|
|
487
458
|
})
|
|
488
459
|
} catch (err) {
|
|
489
460
|
json.e = err.message
|
|
490
461
|
}
|
|
462
|
+
return instance
|
|
491
463
|
}
|
|
492
464
|
|
|
493
465
|
static _handleCallAll (json) {
|
|
@@ -499,13 +471,15 @@ class VrpcAdapter {
|
|
|
499
471
|
] of VrpcAdapter._instances) {
|
|
500
472
|
// TODO Think about a configurable behavior w.r.t. isolated instances...
|
|
501
473
|
if (className !== json.c || isIsolated) continue
|
|
502
|
-
let v
|
|
474
|
+
let v = true
|
|
503
475
|
let e = null
|
|
504
476
|
try {
|
|
505
|
-
const
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
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
|
+
}
|
|
509
483
|
} catch (err) {
|
|
510
484
|
e = err.message
|
|
511
485
|
}
|
|
@@ -535,12 +509,11 @@ class VrpcAdapter {
|
|
|
535
509
|
|
|
536
510
|
static _handleDelete (json) {
|
|
537
511
|
try {
|
|
538
|
-
const
|
|
539
|
-
|
|
540
|
-
json.r = VrpcAdapter._delete(instanceId)
|
|
512
|
+
const instance = json.a[0] // first arg is instance to be deleted
|
|
513
|
+
json.r = VrpcAdapter._delete(instance)
|
|
541
514
|
VrpcAdapter._emitter.emit('delete', {
|
|
542
|
-
|
|
543
|
-
|
|
515
|
+
instance,
|
|
516
|
+
className: json.c
|
|
544
517
|
})
|
|
545
518
|
} catch (err) {
|
|
546
519
|
json.e = err.message
|
|
@@ -548,7 +521,18 @@ class VrpcAdapter {
|
|
|
548
521
|
}
|
|
549
522
|
|
|
550
523
|
static _handleCall (json) {
|
|
551
|
-
|
|
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
|
+
}
|
|
552
536
|
// Check whether context is a registered class
|
|
553
537
|
const entry = VrpcAdapter._functionRegistry.get(json.c)
|
|
554
538
|
if (entry !== undefined) {
|
|
@@ -560,7 +544,7 @@ class VrpcAdapter {
|
|
|
560
544
|
// subscription against all functions
|
|
561
545
|
if (VrpcAdapter._isFunction(Klass[json.f])) {
|
|
562
546
|
try {
|
|
563
|
-
const ret = Klass[json.f].apply(null,
|
|
547
|
+
const ret = Klass[json.f].apply(null, unwrapped)
|
|
564
548
|
// check if function returns promise
|
|
565
549
|
if (VrpcAdapter._isPromise(ret)) {
|
|
566
550
|
this._handlePromise(json, ret)
|
|
@@ -578,7 +562,7 @@ class VrpcAdapter {
|
|
|
578
562
|
const { instance } = entry
|
|
579
563
|
if (VrpcAdapter._isFunction(instance[json.f])) {
|
|
580
564
|
try {
|
|
581
|
-
let ret = instance[json.f].apply(instance,
|
|
565
|
+
let ret = instance[json.f].apply(instance, unwrapped)
|
|
582
566
|
ret = VrpcAdapter.sanitizeEventListenerReturnValues(ret)
|
|
583
567
|
// check if function returns promise
|
|
584
568
|
if (VrpcAdapter._isPromise(ret)) {
|
|
@@ -605,31 +589,35 @@ class VrpcAdapter {
|
|
|
605
589
|
static _delete (instanceId) {
|
|
606
590
|
const entry = VrpcAdapter._instances.get(instanceId)
|
|
607
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
|
+
}
|
|
608
603
|
VrpcAdapter._instances.delete(instanceId)
|
|
609
604
|
return true
|
|
610
605
|
}
|
|
611
606
|
return false
|
|
612
607
|
}
|
|
613
608
|
|
|
614
|
-
static
|
|
615
|
-
const listeners = VrpcAdapter._listeners[clientId]
|
|
616
|
-
if (listeners) {
|
|
617
|
-
listeners.forEach(({ i, e, f }) => {
|
|
618
|
-
VrpcAdapter.getInstance(i).removeListener(e, f)
|
|
619
|
-
})
|
|
620
|
-
}
|
|
621
|
-
delete VrpcAdapter._listeners[clientId]
|
|
622
|
-
}
|
|
623
|
-
|
|
624
|
-
static _unregisterEventListenersOfInstance (instance) {
|
|
609
|
+
static _unregisterClient (clientId) {
|
|
625
610
|
for (const [key, value] of Object.entries(VrpcAdapter._listeners)) {
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
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
|
+
})
|
|
630
618
|
}
|
|
631
|
-
|
|
632
|
-
}
|
|
619
|
+
delete VrpcAdapter._listeners[key]
|
|
620
|
+
}
|
|
633
621
|
}
|
|
634
622
|
}
|
|
635
623
|
|
|
@@ -641,51 +629,101 @@ class VrpcAdapter {
|
|
|
641
629
|
if (!valid) throw new Error(VrpcAdapter._ajv.errorsText())
|
|
642
630
|
}
|
|
643
631
|
|
|
644
|
-
static
|
|
645
|
-
const
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
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)
|
|
661
662
|
}
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
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
|
|
671
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
|
|
672
690
|
}
|
|
673
691
|
} else {
|
|
674
|
-
//
|
|
675
|
-
|
|
692
|
+
// default behavior is to not touch
|
|
693
|
+
unwrapped.push(arg)
|
|
676
694
|
}
|
|
677
|
-
}
|
|
678
|
-
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
|
+
}
|
|
679
717
|
}
|
|
680
718
|
|
|
681
|
-
static
|
|
682
|
-
|
|
683
|
-
// do not even
|
|
684
|
-
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
|
|
685
724
|
const a = instanceId ? [instanceId, ...innerArgs] : [...innerArgs]
|
|
686
|
-
VrpcAdapter._callback({ a, s:
|
|
725
|
+
VrpcAdapter._callback({ a, s: sender, i: id })
|
|
687
726
|
}
|
|
688
|
-
return wrapper
|
|
689
727
|
}
|
|
690
728
|
|
|
691
729
|
static _handlePromise (json, promise) {
|
|
@@ -812,7 +850,7 @@ class VrpcAdapter {
|
|
|
812
850
|
/**
|
|
813
851
|
* Event 'create'
|
|
814
852
|
*
|
|
815
|
-
* Emitted on creation of
|
|
853
|
+
* Emitted on creation of shared instance
|
|
816
854
|
*
|
|
817
855
|
* @event VrpcAdapter#create
|
|
818
856
|
* @type {Object}
|
|
@@ -824,7 +862,7 @@ class VrpcAdapter {
|
|
|
824
862
|
/**
|
|
825
863
|
* Event 'delete'
|
|
826
864
|
*
|
|
827
|
-
* Emitted on deletion of
|
|
865
|
+
* Emitted on deletion of shared instance
|
|
828
866
|
*
|
|
829
867
|
* @event VrpcAdapter#delete
|
|
830
868
|
* @type {Object}
|