vrpc 3.13.0 → 3.15.0
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/LICENSE +1 -1
- package/README.md +100 -77
- package/browser/vrpc.js +5 -5
- package/index.js +7 -7
- package/package.json +25 -15
- package/vrpc/ReconnectBackoff.js +79 -0
- package/vrpc/Registrations.js +850 -0
- package/vrpc/SubscribeRetrier.js +33 -0
- package/vrpc/VrpcAdapter.js +552 -294
- package/vrpc/VrpcAgent.js +242 -154
- package/vrpc/VrpcBrowserAdapter.js +417 -285
- package/vrpc/VrpcBrowserAgent.js +239 -128
- package/vrpc/VrpcClient.js +1221 -233
- package/vrpc/VrpcNative.js +10 -5
- package/vrpc/VrpcPersistor.js +1 -1
- package/vrpc/adapter.hpp +1 -1
- package/vrpc/addon.cpp +1 -1
- package/vrpc/comment-parser/parser.js +23 -0
- package/vrpc/namePattern.js +86 -0
- package/vrpc/vrpc-agent-js +3 -11
|
@@ -14,7 +14,7 @@ procedure calls (RPC).
|
|
|
14
14
|
Author: Dr. Burkhard C. Heisen (https://github.com/heisenware/vrpc)
|
|
15
15
|
|
|
16
16
|
Licensed under the MIT License <http://opensource.org/licenses/MIT>.
|
|
17
|
-
Copyright (c) 2018
|
|
17
|
+
Copyright (c) 2018 Dr. Burkhard C. Heisen <burkhard.heisen@heisenware.com>.
|
|
18
18
|
|
|
19
19
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
20
20
|
of this software and associated documentation files (the "Software"), to deal
|
|
@@ -38,6 +38,8 @@ SOFTWARE.
|
|
|
38
38
|
const Ajv = require('ajv')
|
|
39
39
|
const EventEmitter = require('events')
|
|
40
40
|
const { nanoid } = require('nanoid')
|
|
41
|
+
const Registrations = require('./Registrations')
|
|
42
|
+
const NamePattern = require('./namePattern')
|
|
41
43
|
|
|
42
44
|
// A runtime without dispose symbols (older browsers, Node before 18.18 /
|
|
43
45
|
// 20.4) gets Node's own stand-ins from the symbol registry, so a class file
|
|
@@ -82,6 +84,7 @@ class VrpcAdapter {
|
|
|
82
84
|
staticFunctions.push('__createIsolated__')
|
|
83
85
|
staticFunctions.push('__createShared__')
|
|
84
86
|
staticFunctions.push('__callAll__')
|
|
87
|
+
staticFunctions.push('__callMatching__')
|
|
85
88
|
staticFunctions.push('__delete__')
|
|
86
89
|
let memberFunctions = VrpcAdapter._extractMemberFunctions(Klass)
|
|
87
90
|
if (onlyPublic) {
|
|
@@ -303,8 +306,35 @@ class VrpcAdapter {
|
|
|
303
306
|
|
|
304
307
|
// private:
|
|
305
308
|
|
|
309
|
+
/**
|
|
310
|
+
* Handles one request in place: the answer lands on `json` as `r` or `e`.
|
|
311
|
+
* Every request is answered - a malformed one, an unknown context or
|
|
312
|
+
* function with an error - so no caller waits for its timeout.
|
|
313
|
+
*
|
|
314
|
+
* @returns {Boolean} Whether the call took subscriptions of its sender,
|
|
315
|
+
* whose presence the agent then watches
|
|
316
|
+
*/
|
|
306
317
|
static _call (json) {
|
|
307
318
|
VrpcAdapter._mustTrackClient = false // reset client tracking flag
|
|
319
|
+
// the answer is what the call yields, never what the request brought
|
|
320
|
+
delete json.r
|
|
321
|
+
delete json.e
|
|
322
|
+
try {
|
|
323
|
+
// a request without arguments has none
|
|
324
|
+
if (json.a === undefined) json.a = []
|
|
325
|
+
if (!Array.isArray(json.a)) {
|
|
326
|
+
throw new Error('The arguments of a request must be an array')
|
|
327
|
+
}
|
|
328
|
+
VrpcAdapter._dispatch(json)
|
|
329
|
+
} catch (err) {
|
|
330
|
+
json.e = VrpcAdapter._error(err)
|
|
331
|
+
}
|
|
332
|
+
// if we took a listener on board we must tell our caller such that
|
|
333
|
+
// things can be cleaned up later.
|
|
334
|
+
return VrpcAdapter._mustTrackClient
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
static _dispatch (json) {
|
|
308
338
|
switch (json.f) {
|
|
309
339
|
case '__createIsolated__':
|
|
310
340
|
VrpcAdapter._handleCreateIsolated(json)
|
|
@@ -315,16 +345,49 @@ class VrpcAdapter {
|
|
|
315
345
|
case '__callAll__':
|
|
316
346
|
VrpcAdapter._handleCallAll(json)
|
|
317
347
|
break
|
|
348
|
+
case '__callMatching__':
|
|
349
|
+
VrpcAdapter._handleCallMatching(json)
|
|
350
|
+
break
|
|
318
351
|
case '__delete__':
|
|
319
352
|
VrpcAdapter._handleDelete(json)
|
|
320
353
|
break
|
|
354
|
+
case '__unsubscribe__':
|
|
355
|
+
VrpcAdapter._handleUnsubscribe(json)
|
|
356
|
+
break
|
|
357
|
+
case '__registrations__':
|
|
358
|
+
VrpcAdapter._handleRegistrations(json)
|
|
359
|
+
break
|
|
360
|
+
case '__end__':
|
|
361
|
+
VrpcAdapter._handleEnd(json)
|
|
362
|
+
break
|
|
321
363
|
default:
|
|
322
364
|
// this call may have the side-effect of taking a listener on board
|
|
323
365
|
VrpcAdapter._handleCall(json)
|
|
324
366
|
}
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// an error as it travels: `{ message, cause? }`, whatever was thrown
|
|
370
|
+
static _error (err) {
|
|
371
|
+
if (err && typeof err === 'object' && 'message' in err) {
|
|
372
|
+
const e = { message: String(err.message) }
|
|
373
|
+
if (err.cause !== undefined) e.cause = err.cause
|
|
374
|
+
return e
|
|
375
|
+
}
|
|
376
|
+
return { message: String(err) }
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Whether a request may call a function: only what the class info lists
|
|
381
|
+
* is reachable - a member function of the instance's class, a static
|
|
382
|
+
* function of the class, or a registered global function. Anything else
|
|
383
|
+
* an object happens to have (an EventEmitter's `emit`, a private helper)
|
|
384
|
+
* stays inside the agent.
|
|
385
|
+
*/
|
|
386
|
+
static _isPublished (className, func, isStatic) {
|
|
387
|
+
const entry = VrpcAdapter._functionRegistry.get(className)
|
|
388
|
+
if (!entry) return false
|
|
389
|
+
const published = isStatic ? entry.staticFunctions : entry.memberFunctions
|
|
390
|
+
return published.includes(func)
|
|
328
391
|
}
|
|
329
392
|
|
|
330
393
|
/**
|
|
@@ -343,11 +406,28 @@ class VrpcAdapter {
|
|
|
343
406
|
)
|
|
344
407
|
}
|
|
345
408
|
|
|
409
|
+
/**
|
|
410
|
+
* An instance name is one topic level of its own: a non-empty string
|
|
411
|
+
* without `/`, `+`, `#` or `*` (which would read as a pattern), and never
|
|
412
|
+
* `__static__`, which stands for the class in a request topic.
|
|
413
|
+
*/
|
|
414
|
+
static _assertInstanceName (name) {
|
|
415
|
+
if (
|
|
416
|
+
typeof name !== 'string' ||
|
|
417
|
+
name.length === 0 ||
|
|
418
|
+
/[/+#*]/.test(name) ||
|
|
419
|
+
name === '__static__'
|
|
420
|
+
) {
|
|
421
|
+
throw new Error(`Invalid instance name: ${JSON.stringify(name)}`)
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
|
|
346
425
|
static _handleCreateIsolated (json) {
|
|
347
426
|
let instance
|
|
348
427
|
try {
|
|
349
428
|
const className = json.c
|
|
350
429
|
const [instanceId, ...args] = json.a
|
|
430
|
+
VrpcAdapter._assertInstanceName(instanceId)
|
|
351
431
|
const existing = VrpcAdapter._instances.get(instanceId)
|
|
352
432
|
if (existing) {
|
|
353
433
|
// an id is never re-homed: a shared instance stays shared, an
|
|
@@ -375,7 +455,7 @@ class VrpcAdapter {
|
|
|
375
455
|
})
|
|
376
456
|
json.r = instanceId
|
|
377
457
|
} catch (err) {
|
|
378
|
-
json.e = err
|
|
458
|
+
json.e = VrpcAdapter._error(err)
|
|
379
459
|
}
|
|
380
460
|
return instance
|
|
381
461
|
}
|
|
@@ -385,6 +465,7 @@ class VrpcAdapter {
|
|
|
385
465
|
try {
|
|
386
466
|
const className = json.c
|
|
387
467
|
const [instanceId, ...args] = json.a
|
|
468
|
+
VrpcAdapter._assertInstanceName(instanceId)
|
|
388
469
|
const existing = VrpcAdapter._instances.get(instanceId)
|
|
389
470
|
if (existing && existing.isIsolated) {
|
|
390
471
|
throw new Error(`Instance '${instanceId}' exists as an isolated instance`)
|
|
@@ -403,66 +484,203 @@ class VrpcAdapter {
|
|
|
403
484
|
instance: instanceId
|
|
404
485
|
})
|
|
405
486
|
} catch (err) {
|
|
406
|
-
json.e = err
|
|
487
|
+
json.e = VrpcAdapter._error(err)
|
|
407
488
|
}
|
|
408
489
|
return instance
|
|
409
490
|
}
|
|
410
491
|
|
|
492
|
+
// `a` = [function, ...arguments]: every shared instance of the class (ALL-1)
|
|
411
493
|
static _handleCallAll (json) {
|
|
494
|
+
const [func, ...args] = json.a
|
|
495
|
+
VrpcAdapter._callAll(json, func, args, () => true)
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
// `a` = [selection, function, ...arguments]: the shared instances whose
|
|
499
|
+
// name the selection matches, a pattern or a list of them (ALL-4, ALL-5)
|
|
500
|
+
static _handleCallMatching (json) {
|
|
501
|
+
const [selection, func, ...args] = json.a
|
|
502
|
+
if (!NamePattern.isSelection(selection)) {
|
|
503
|
+
json.e = {
|
|
504
|
+
message: `Invalid selection: ${JSON.stringify(selection)} (a pattern or a list of them)`
|
|
505
|
+
}
|
|
506
|
+
return
|
|
507
|
+
}
|
|
508
|
+
VrpcAdapter._callAll(json, func, args, id =>
|
|
509
|
+
NamePattern.selects(selection, id)
|
|
510
|
+
)
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// calls a function on the shared instances of a class `chosen` takes, and
|
|
514
|
+
// answers one entry per instance (ALL-2)
|
|
515
|
+
static _callAll (json, func, args, chosen) {
|
|
412
516
|
try {
|
|
413
517
|
const calls = []
|
|
518
|
+
const subscribes = Registrations.carriesEventIds(args)
|
|
519
|
+
// a remover carrying ids never reaches the class (see Registrations)
|
|
520
|
+
const withdraws = subscribes && Registrations.isRemover(func, json.v)
|
|
521
|
+
if (!withdraws && !VrpcAdapter._isPublished(json.c, func, false)) {
|
|
522
|
+
throw new Error(`Could not find function: ${func}`)
|
|
523
|
+
}
|
|
524
|
+
// what the instance's callbacks unwrap from: the function and its
|
|
525
|
+
// arguments, as a __callAll__ request carries them
|
|
526
|
+
const asCallAll = { ...json, a: [func, ...args] }
|
|
414
527
|
for (const [
|
|
415
528
|
id,
|
|
416
529
|
{ className, instance, isIsolated }
|
|
417
530
|
] of VrpcAdapter._instances) {
|
|
418
|
-
//
|
|
419
|
-
if (className !== json.c || isIsolated) continue
|
|
420
|
-
|
|
421
|
-
|
|
531
|
+
// isolated instances never take part
|
|
532
|
+
if (className !== json.c || isIsolated || !chosen(id)) continue
|
|
533
|
+
// one answer per instance: `{ id, val }`, or `{ id, err }` with the
|
|
534
|
+
// error as it travels
|
|
422
535
|
try {
|
|
423
|
-
|
|
424
|
-
if (
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
536
|
+
let val
|
|
537
|
+
if (subscribes) {
|
|
538
|
+
val = VrpcAdapter._subscribe(json, {
|
|
539
|
+
contextKey: id,
|
|
540
|
+
contextName: id,
|
|
541
|
+
target: instance,
|
|
542
|
+
func,
|
|
543
|
+
args,
|
|
544
|
+
isCallAll: true
|
|
545
|
+
}).value
|
|
546
|
+
} else {
|
|
547
|
+
const unwrapped = VrpcAdapter._unwrapArguments(asCallAll, id)
|
|
548
|
+
val = instance[func].apply(instance, unwrapped.slice(1))
|
|
549
|
+
val = VrpcAdapter.sanitizeEventListenerReturnValues(val)
|
|
428
550
|
}
|
|
429
|
-
} catch (err) {
|
|
430
|
-
e = err.message
|
|
431
|
-
}
|
|
432
|
-
if (VrpcAdapter._isPromise(v)) {
|
|
433
551
|
calls.push(
|
|
434
|
-
|
|
435
|
-
.then(
|
|
436
|
-
|
|
552
|
+
VrpcAdapter._isPromise(val)
|
|
553
|
+
? val.then(
|
|
554
|
+
x => ({ id, val: x }),
|
|
555
|
+
err => ({ id, err: VrpcAdapter._error(err) })
|
|
556
|
+
)
|
|
557
|
+
: { id, val }
|
|
437
558
|
)
|
|
438
|
-
}
|
|
439
|
-
calls.push({ id,
|
|
559
|
+
} catch (err) {
|
|
560
|
+
calls.push({ id, err: VrpcAdapter._error(err) })
|
|
440
561
|
}
|
|
441
562
|
}
|
|
442
|
-
|
|
563
|
+
VrpcAdapter._handlePromise(
|
|
443
564
|
json,
|
|
444
565
|
Promise.allSettled(calls).then(result =>
|
|
445
566
|
result.filter(x => x.status === 'fulfilled').map(x => x.value)
|
|
446
567
|
)
|
|
447
568
|
)
|
|
448
569
|
} catch (err) {
|
|
449
|
-
json.e = err
|
|
570
|
+
json.e = VrpcAdapter._error(err)
|
|
450
571
|
}
|
|
451
572
|
}
|
|
452
573
|
|
|
453
574
|
static sanitizeEventListenerReturnValues (ret) {
|
|
454
|
-
return ret
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
575
|
+
return Registrations.sanitize(ret)
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* The book key of a request's context: an instance id, or the class for
|
|
580
|
+
* static functions (kept apart from an instance of the same name).
|
|
581
|
+
*/
|
|
582
|
+
static _contextKey (context, isStatic) {
|
|
583
|
+
return isStatic ? `\u0000${context}` : context
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
// a class name addresses the class, as in _handleCall
|
|
587
|
+
static _isStaticContext (context) {
|
|
588
|
+
return VrpcAdapter._functionRegistry.has(context)
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
/**
|
|
592
|
+
* A call carrying subscription ids: one registration per context,
|
|
593
|
+
* function and arguments, shared by every subscription (see
|
|
594
|
+
* Registrations).
|
|
595
|
+
*/
|
|
596
|
+
static _subscribe (
|
|
597
|
+
json,
|
|
598
|
+
{ contextKey, contextName, target, func, args, isCallAll = false }
|
|
599
|
+
) {
|
|
600
|
+
const result = VrpcAdapter._registrations.call({
|
|
601
|
+
json,
|
|
602
|
+
contextKey,
|
|
603
|
+
contextName,
|
|
604
|
+
target,
|
|
605
|
+
func,
|
|
606
|
+
args,
|
|
607
|
+
isCallAll,
|
|
608
|
+
speaks: VrpcAdapter._speaksFor(contextName),
|
|
609
|
+
makeCallback: eventId =>
|
|
610
|
+
VrpcAdapter._generateCallback({
|
|
611
|
+
clientId: json.s,
|
|
612
|
+
isCallAll,
|
|
613
|
+
instanceId: contextName,
|
|
614
|
+
eventId,
|
|
615
|
+
receiverVersion: json.v
|
|
616
|
+
})
|
|
617
|
+
})
|
|
618
|
+
// a subscriber is tracked: its going withdraws what it holds
|
|
619
|
+
if (result.ids.length > 0) VrpcAdapter._mustTrackClient = true
|
|
620
|
+
return result
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
/**
|
|
624
|
+
* `__unsubscribe__ [id, ...]`: withdraws the sender's subscriptions
|
|
625
|
+
* wherever they are held; an entry `{ id, context }` withdraws that id
|
|
626
|
+
* on that instance only (one instance of a callAll subscription).
|
|
627
|
+
* Answers true.
|
|
628
|
+
*/
|
|
629
|
+
static _handleUnsubscribe (json) {
|
|
630
|
+
VrpcAdapter._registrations.unsubscribe(json.a || [], json.s)
|
|
631
|
+
json.r = true
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* `__registrations__`: lists the registrations of an instance or (on the
|
|
636
|
+
* static topic) a class.
|
|
637
|
+
*/
|
|
638
|
+
static _handleRegistrations (json) {
|
|
639
|
+
try {
|
|
640
|
+
const isStatic = VrpcAdapter._isStaticContext(json.c)
|
|
641
|
+
if (!isStatic) {
|
|
642
|
+
VrpcAdapter._assertOwner(VrpcAdapter._instances.get(json.c), json, json.c)
|
|
643
|
+
}
|
|
644
|
+
json.r = VrpcAdapter._registrations.list(
|
|
645
|
+
VrpcAdapter._contextKey(json.c, isStatic)
|
|
646
|
+
)
|
|
647
|
+
} catch (err) {
|
|
648
|
+
json.e = VrpcAdapter._error(err)
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
/**
|
|
653
|
+
* `__end__ [function, args, by]`: ends one registration for all its
|
|
654
|
+
* subscriptions, which are told who ended it. Answers whether it existed.
|
|
655
|
+
*/
|
|
656
|
+
static _handleEnd (json) {
|
|
657
|
+
try {
|
|
658
|
+
const isStatic = VrpcAdapter._isStaticContext(json.c)
|
|
659
|
+
if (!isStatic) {
|
|
660
|
+
VrpcAdapter._assertOwner(VrpcAdapter._instances.get(json.c), json, json.c)
|
|
661
|
+
}
|
|
662
|
+
const [func, args = [], by = null] = json.a || []
|
|
663
|
+
json.r = VrpcAdapter._registrations.end(
|
|
664
|
+
VrpcAdapter._contextKey(json.c, isStatic),
|
|
665
|
+
func,
|
|
666
|
+
args,
|
|
667
|
+
by
|
|
668
|
+
)
|
|
669
|
+
} catch (err) {
|
|
670
|
+
json.e = VrpcAdapter._error(err)
|
|
671
|
+
}
|
|
460
672
|
}
|
|
461
673
|
|
|
462
674
|
static _handleDelete (json) {
|
|
463
675
|
try {
|
|
464
676
|
const instance = json.a[0] // first arg is instance to be deleted
|
|
465
|
-
VrpcAdapter.
|
|
677
|
+
const entry = VrpcAdapter._instances.get(instance)
|
|
678
|
+
// a delete names the instance's own class: the class info of that
|
|
679
|
+
// class is what announces it gone
|
|
680
|
+
if (entry && entry.className !== json.c && json.s !== VrpcAdapter.LOCAL_SENDER) {
|
|
681
|
+
throw new Error(`Instance '${instance}' is not of class '${json.c}'`)
|
|
682
|
+
}
|
|
683
|
+
VrpcAdapter._assertOwner(entry, json, instance)
|
|
466
684
|
VrpcAdapter._emitter.emit('beforeDelete', {
|
|
467
685
|
instance,
|
|
468
686
|
className: json.c
|
|
@@ -479,7 +697,7 @@ class VrpcAdapter {
|
|
|
479
697
|
VrpcAdapter._handlePromise(json, disposed.then(() => ended))
|
|
480
698
|
} else json.r = ended
|
|
481
699
|
} catch (err) {
|
|
482
|
-
json.e = err
|
|
700
|
+
json.e = VrpcAdapter._error(err)
|
|
483
701
|
}
|
|
484
702
|
}
|
|
485
703
|
|
|
@@ -488,13 +706,19 @@ class VrpcAdapter {
|
|
|
488
706
|
try {
|
|
489
707
|
VrpcAdapter._assertOwner(VrpcAdapter._instances.get(json.c), json, json.c)
|
|
490
708
|
} catch (err) {
|
|
491
|
-
|
|
492
|
-
json.e = { message, cause }
|
|
709
|
+
json.e = VrpcAdapter._error(err)
|
|
493
710
|
return
|
|
494
711
|
}
|
|
495
|
-
// special case: removeAllListeners
|
|
712
|
+
// special case: removeAllListeners withdraws the caller's subscriptions
|
|
713
|
+
// of that event - the emitter itself is never touched, it holds other
|
|
714
|
+
// clients' and its own listeners
|
|
496
715
|
if (json.f === 'removeAllListeners') {
|
|
497
|
-
VrpcAdapter.
|
|
716
|
+
const isStatic = VrpcAdapter._isStaticContext(json.c)
|
|
717
|
+
VrpcAdapter._registrations.withdrawEvent(
|
|
718
|
+
VrpcAdapter._contextKey(json.c, isStatic),
|
|
719
|
+
json.a[0],
|
|
720
|
+
json.s
|
|
721
|
+
)
|
|
498
722
|
json.r = true
|
|
499
723
|
return
|
|
500
724
|
}
|
|
@@ -507,66 +731,93 @@ class VrpcAdapter {
|
|
|
507
731
|
) {
|
|
508
732
|
throw new Error(`Could not find context: ${json.c}`)
|
|
509
733
|
}
|
|
510
|
-
const unwrapped = VrpcAdapter._unwrapArguments(json)
|
|
511
|
-
if (!unwrapped) {
|
|
512
|
-
// this call must be skipped (event emitter stuff)
|
|
513
|
-
json.r = true
|
|
514
|
-
return
|
|
515
|
-
}
|
|
516
|
-
|
|
517
734
|
// Check whether context is global
|
|
518
735
|
if (json.c === VRPC_GLOBAL) {
|
|
736
|
+
if (!VrpcAdapter._isPublished(VRPC_GLOBAL, json.f, true)) {
|
|
737
|
+
throw new Error(`Could not find function: ${json.f}`)
|
|
738
|
+
}
|
|
519
739
|
try {
|
|
740
|
+
const unwrapped = VrpcAdapter._unwrapArguments(json)
|
|
520
741
|
const ret = window[VRPC_WINDOW_NS][json.f].apply(null, unwrapped)
|
|
521
742
|
// check if function returns promise
|
|
522
743
|
if (VrpcAdapter._isPromise(ret)) {
|
|
523
744
|
VrpcAdapter._handlePromise(json, ret)
|
|
524
745
|
} else json.r = ret
|
|
525
746
|
} catch (err) {
|
|
526
|
-
json.e = err
|
|
747
|
+
json.e = VrpcAdapter._error(err)
|
|
527
748
|
}
|
|
528
749
|
return
|
|
529
750
|
}
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
const
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
// rather sticking to those functions registered before...
|
|
538
|
-
// TODO This is even more important now as the agent does a wildcard
|
|
539
|
-
// subscription against all functions
|
|
540
|
-
if (VrpcAdapter._isFunction(Klass[json.f])) {
|
|
541
|
-
try {
|
|
542
|
-
const ret = Klass[json.f].apply(null, unwrapped)
|
|
543
|
-
// check if function returns promise
|
|
544
|
-
if (VrpcAdapter._isPromise(ret)) {
|
|
545
|
-
VrpcAdapter._handlePromise(json, ret)
|
|
546
|
-
} else json.r = ret
|
|
547
|
-
} catch (err) {
|
|
548
|
-
json.e = err.message
|
|
549
|
-
}
|
|
550
|
-
} else throw new Error(`Could not find static function: ${json.f}`)
|
|
751
|
+
// Check whether context is a registered class (function is static)
|
|
752
|
+
const classEntry = VrpcAdapter._functionRegistry.get(json.c)
|
|
753
|
+
const isStatic = classEntry !== undefined
|
|
754
|
+
let target
|
|
755
|
+
let className = json.c
|
|
756
|
+
if (isStatic) {
|
|
757
|
+
target = classEntry.Klass
|
|
551
758
|
} else {
|
|
552
|
-
// is not static
|
|
553
759
|
const entry = VrpcAdapter._instances.get(json.c)
|
|
554
760
|
if (entry === undefined) {
|
|
555
761
|
throw new Error(`Could not find context: ${json.c}`)
|
|
556
762
|
}
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
763
|
+
target = entry.instance
|
|
764
|
+
className = entry.className
|
|
765
|
+
}
|
|
766
|
+
const carriesIds = Registrations.carriesEventIds(json.a)
|
|
767
|
+
// only what the class info lists is called; a remover carrying ids never
|
|
768
|
+
// reaches the class (see Registrations)
|
|
769
|
+
if (
|
|
770
|
+
!(carriesIds && Registrations.isRemover(json.f, json.v)) &&
|
|
771
|
+
!VrpcAdapter._isPublished(className, json.f, isStatic)
|
|
772
|
+
) {
|
|
773
|
+
throw new Error(`Could not find function: ${json.f}`)
|
|
774
|
+
}
|
|
775
|
+
// a call carrying subscription ids subscribes (or withdraws)
|
|
776
|
+
if (carriesIds) {
|
|
777
|
+
try {
|
|
778
|
+
const { value } = VrpcAdapter._subscribe(json, {
|
|
779
|
+
contextKey: VrpcAdapter._contextKey(json.c, isStatic),
|
|
780
|
+
contextName: json.c,
|
|
781
|
+
target,
|
|
782
|
+
func: json.f,
|
|
783
|
+
args: json.a
|
|
784
|
+
})
|
|
785
|
+
if (VrpcAdapter._isPromise(value)) {
|
|
786
|
+
VrpcAdapter._handlePromise(json, value)
|
|
787
|
+
} else json.r = value
|
|
788
|
+
} catch (err) {
|
|
789
|
+
json.e = VrpcAdapter._error(err)
|
|
790
|
+
}
|
|
791
|
+
return
|
|
792
|
+
}
|
|
793
|
+
const unwrapped = VrpcAdapter._unwrapArguments(json)
|
|
794
|
+
// special case: removing a listener the adapter does not hold (the
|
|
795
|
+
// client's subscription outlived a restart of this agent, or it sent
|
|
796
|
+
// no listener at all) - nothing to remove, and the instance's
|
|
797
|
+
// EventEmitter would throw on a listener that is not a function
|
|
798
|
+
if (
|
|
799
|
+
(json.f === 'off' || json.f === 'removeListener') &&
|
|
800
|
+
typeof unwrapped[1] !== 'function'
|
|
801
|
+
) {
|
|
802
|
+
json.r = true
|
|
803
|
+
return
|
|
804
|
+
}
|
|
805
|
+
// TODO Think about whether to do live checking (like here) or
|
|
806
|
+
// rather sticking to those functions registered before...
|
|
807
|
+
if (!VrpcAdapter._isFunction(target[json.f])) {
|
|
808
|
+
throw new Error(`Could not find function: ${json.f}`)
|
|
809
|
+
}
|
|
810
|
+
try {
|
|
811
|
+
let ret = isStatic
|
|
812
|
+
? target[json.f].apply(null, unwrapped)
|
|
813
|
+
: target[json.f].apply(target, unwrapped)
|
|
814
|
+
if (!isStatic) ret = VrpcAdapter.sanitizeEventListenerReturnValues(ret)
|
|
815
|
+
// check if function returns promise
|
|
816
|
+
if (VrpcAdapter._isPromise(ret)) {
|
|
817
|
+
VrpcAdapter._handlePromise(json, ret)
|
|
818
|
+
} else json.r = ret
|
|
819
|
+
} catch (err) {
|
|
820
|
+
json.e = VrpcAdapter._error(err)
|
|
570
821
|
}
|
|
571
822
|
}
|
|
572
823
|
|
|
@@ -588,9 +839,10 @@ class VrpcAdapter {
|
|
|
588
839
|
/**
|
|
589
840
|
* Ends an instance - the one teardown behind every door (a remote delete,
|
|
590
841
|
* the auto-delete of an isolated instance whose client went, an
|
|
591
|
-
* in-process delete): its name is free at once, the adapter
|
|
592
|
-
*
|
|
593
|
-
*
|
|
842
|
+
* in-process delete): its name is free at once, the adapter forgets its
|
|
843
|
+
* registrations (silent from now on, see Registrations; released by the
|
|
844
|
+
* adapter only for an object without a dispose method, and Node's own
|
|
845
|
+
* `on` always), and the object releases what it runs through the
|
|
594
846
|
* ECMAScript dispose protocol, `[Symbol.asyncDispose]` or else
|
|
595
847
|
* `[Symbol.dispose]`.
|
|
596
848
|
*
|
|
@@ -601,33 +853,16 @@ class VrpcAdapter {
|
|
|
601
853
|
const entry = VrpcAdapter._instances.get(instanceId)
|
|
602
854
|
if (!entry) return { ended: false, disposed: null }
|
|
603
855
|
VrpcAdapter._instances.delete(instanceId)
|
|
604
|
-
|
|
856
|
+
const { instance } = entry
|
|
857
|
+
VrpcAdapter._registrations.forgetContext(instanceId, {
|
|
858
|
+
release: !(
|
|
859
|
+
VrpcAdapter._isFunction(instance[Symbol.asyncDispose]) ||
|
|
860
|
+
VrpcAdapter._isFunction(instance[Symbol.dispose])
|
|
861
|
+
)
|
|
862
|
+
})
|
|
605
863
|
return { ended: true, disposed: VrpcAdapter._dispose(instanceId, entry) }
|
|
606
864
|
}
|
|
607
865
|
|
|
608
|
-
static _detachListeners (instanceId, instance) {
|
|
609
|
-
const registrations = VrpcAdapter._listeners[instanceId]
|
|
610
|
-
delete VrpcAdapter._listeners[instanceId]
|
|
611
|
-
if (!registrations || !VrpcAdapter._isFunction(instance.removeListener)) {
|
|
612
|
-
return
|
|
613
|
-
}
|
|
614
|
-
for (const { event, listener, clients } of Object.values(registrations)) {
|
|
615
|
-
try {
|
|
616
|
-
VrpcAdapter._removeTimes(instance, event, listener, clients.length)
|
|
617
|
-
} catch (err) {
|
|
618
|
-
// a class whose removeListener fails keeps a silent listener
|
|
619
|
-
}
|
|
620
|
-
}
|
|
621
|
-
}
|
|
622
|
-
|
|
623
|
-
// a subscription repeated n times may hold n attachments of one listener
|
|
624
|
-
// (EventEmitter semantics): each removeListener takes one of them
|
|
625
|
-
static _removeTimes (instance, event, listener, times) {
|
|
626
|
-
for (let n = 0; n < Math.max(1, times); n++) {
|
|
627
|
-
instance.removeListener(event, listener)
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
|
|
631
866
|
/**
|
|
632
867
|
* Runs the object's dispose method. A dispose that fails or outlasts
|
|
633
868
|
* VrpcAdapter.DISPOSE_TIMEOUT is reported (event 'disposeFailed') and
|
|
@@ -673,24 +908,7 @@ class VrpcAdapter {
|
|
|
673
908
|
}
|
|
674
909
|
|
|
675
910
|
static _unregisterClient (clientId) {
|
|
676
|
-
|
|
677
|
-
Object.entries(iv).forEach(([ek, ev]) => {
|
|
678
|
-
const { listener, event } = ev
|
|
679
|
-
// a client is listed once per subscription: its going ends them all
|
|
680
|
-
const remaining = ev.clients.filter(x => x !== clientId)
|
|
681
|
-
const gone = ev.clients.length - remaining.length
|
|
682
|
-
if (gone === 0) return
|
|
683
|
-
ev.clients = remaining
|
|
684
|
-
if (remaining.length === 0) {
|
|
685
|
-
const entry = VrpcAdapter._instances.get(ik)
|
|
686
|
-
const instance = entry && entry.instance
|
|
687
|
-
if (instance && instance.removeListener) {
|
|
688
|
-
VrpcAdapter._removeTimes(instance, event, listener, gone)
|
|
689
|
-
}
|
|
690
|
-
delete VrpcAdapter._listeners[ik][ek]
|
|
691
|
-
}
|
|
692
|
-
})
|
|
693
|
-
})
|
|
911
|
+
VrpcAdapter._registrations.withdrawClient(clientId)
|
|
694
912
|
}
|
|
695
913
|
|
|
696
914
|
static _validate (schema, params) {
|
|
@@ -701,6 +919,7 @@ class VrpcAdapter {
|
|
|
701
919
|
if (!valid) throw new Error(VrpcAdapter._ajv.errorsText())
|
|
702
920
|
}
|
|
703
921
|
|
|
922
|
+
// the arguments of a plain call: `__f__` ids become one-shot callbacks
|
|
704
923
|
static _unwrapArguments (json, instanceId) {
|
|
705
924
|
const clientId = json.s
|
|
706
925
|
// if we came from a "callAll" we will have an instanceId defined
|
|
@@ -711,59 +930,17 @@ class VrpcAdapter {
|
|
|
711
930
|
const func = isCallAll ? json.a[0] : json.f
|
|
712
931
|
const unwrapped = isCallAll ? [func] : []
|
|
713
932
|
for (const arg of args) {
|
|
714
|
-
if (typeof arg === 'string') {
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
)
|
|
725
|
-
} else if (arg.startsWith('__e__')) {
|
|
726
|
-
// event registration
|
|
727
|
-
if (func === 'on' || func === 'addListener') {
|
|
728
|
-
VrpcAdapter._mustTrackClient = true
|
|
729
|
-
const held = VrpcAdapter._holdsListener(context, arg)
|
|
730
|
-
const listener = VrpcAdapter._registerListener({
|
|
731
|
-
clientId,
|
|
732
|
-
isCallAll,
|
|
733
|
-
instanceId: context,
|
|
734
|
-
eventId: arg,
|
|
735
|
-
event: args[0]
|
|
736
|
-
})
|
|
737
|
-
// attached already: skip the call, one listener hears once
|
|
738
|
-
if (held) return null
|
|
739
|
-
unwrapped.push(listener)
|
|
740
|
-
// event un-registration
|
|
741
|
-
} else if (func === 'off' || func === 'removeListener') {
|
|
742
|
-
const listener = VrpcAdapter._unregisterListener({
|
|
743
|
-
clientId,
|
|
744
|
-
instanceId: context,
|
|
745
|
-
eventId: arg
|
|
746
|
-
})
|
|
747
|
-
if (!listener) {
|
|
748
|
-
return null // skip call as others are still interested
|
|
749
|
-
}
|
|
750
|
-
unwrapped.push(listener)
|
|
751
|
-
} else {
|
|
752
|
-
VrpcAdapter._mustTrackClient = true
|
|
753
|
-
const listener = VrpcAdapter._registerListener({
|
|
754
|
-
clientId,
|
|
755
|
-
isCallAll,
|
|
756
|
-
instanceId: context,
|
|
757
|
-
eventId: arg,
|
|
758
|
-
event: null
|
|
759
|
-
})
|
|
760
|
-
unwrapped.push(listener)
|
|
761
|
-
}
|
|
762
|
-
} else {
|
|
763
|
-
unwrapped.push(arg)
|
|
764
|
-
}
|
|
933
|
+
if (typeof arg === 'string' && arg.startsWith('__f__')) {
|
|
934
|
+
unwrapped.push(
|
|
935
|
+
VrpcAdapter._generateCallback({
|
|
936
|
+
clientId,
|
|
937
|
+
isCallAll,
|
|
938
|
+
instanceId: context,
|
|
939
|
+
eventId: arg,
|
|
940
|
+
receiverVersion: json.v
|
|
941
|
+
})
|
|
942
|
+
)
|
|
765
943
|
} else {
|
|
766
|
-
// regular argument
|
|
767
944
|
unwrapped.push(arg)
|
|
768
945
|
}
|
|
769
946
|
}
|
|
@@ -787,113 +964,38 @@ class VrpcAdapter {
|
|
|
787
964
|
}
|
|
788
965
|
}
|
|
789
966
|
|
|
790
|
-
static
|
|
791
|
-
const registrations = VrpcAdapter._listeners[instanceId]
|
|
792
|
-
return Boolean(registrations && registrations[eventId])
|
|
793
|
-
}
|
|
794
|
-
|
|
795
|
-
static _generateCallback ({ eventId, clientId, instanceId, isCallAll }) {
|
|
796
|
-
const speaks = VrpcAdapter._speaksFor(instanceId)
|
|
797
|
-
return (...innerArgs) => {
|
|
798
|
-
if (!speaks()) return
|
|
799
|
-
// "callAll" event notifications expect the instanceId as first argument
|
|
800
|
-
const a = isCallAll ? [instanceId, ...innerArgs] : [...innerArgs]
|
|
801
|
-
VrpcAdapter._callback({ a, s: clientId, i: eventId })
|
|
802
|
-
}
|
|
803
|
-
}
|
|
804
|
-
|
|
805
|
-
static _registerListener ({
|
|
967
|
+
static _generateCallback ({
|
|
806
968
|
eventId,
|
|
807
969
|
clientId,
|
|
808
970
|
instanceId,
|
|
809
|
-
|
|
810
|
-
|
|
971
|
+
isCallAll,
|
|
972
|
+
receiverVersion
|
|
811
973
|
}) {
|
|
812
|
-
if (!VrpcAdapter._listeners[instanceId]) {
|
|
813
|
-
VrpcAdapter._listeners[instanceId] = {
|
|
814
|
-
[eventId]: {
|
|
815
|
-
event,
|
|
816
|
-
clients: [clientId],
|
|
817
|
-
listener: VrpcAdapter._generateListener({
|
|
818
|
-
eventId,
|
|
819
|
-
instanceId,
|
|
820
|
-
isCallAll
|
|
821
|
-
})
|
|
822
|
-
}
|
|
823
|
-
}
|
|
824
|
-
return VrpcAdapter._listeners[instanceId][eventId].listener
|
|
825
|
-
}
|
|
826
|
-
if (!VrpcAdapter._listeners[instanceId][eventId]) {
|
|
827
|
-
VrpcAdapter._listeners[instanceId][eventId] = {
|
|
828
|
-
event,
|
|
829
|
-
clients: [clientId],
|
|
830
|
-
listener: VrpcAdapter._generateListener({
|
|
831
|
-
eventId,
|
|
832
|
-
instanceId,
|
|
833
|
-
isCallAll
|
|
834
|
-
})
|
|
835
|
-
}
|
|
836
|
-
return VrpcAdapter._listeners[instanceId][eventId].listener
|
|
837
|
-
}
|
|
838
|
-
VrpcAdapter._listeners[instanceId][eventId].clients.push(clientId)
|
|
839
|
-
return VrpcAdapter._listeners[instanceId][eventId].listener
|
|
840
|
-
}
|
|
841
|
-
|
|
842
|
-
static _generateListener ({ eventId, instanceId, isCallAll }) {
|
|
843
974
|
const speaks = VrpcAdapter._speaksFor(instanceId)
|
|
844
975
|
return (...innerArgs) => {
|
|
845
976
|
if (!speaks()) return
|
|
977
|
+
// "callAll" event notifications expect the instanceId as first argument
|
|
846
978
|
const a = isCallAll ? [instanceId, ...innerArgs] : [...innerArgs]
|
|
847
|
-
|
|
979
|
+
// the receiver's protocol version: whether it can be told of a
|
|
980
|
+
// callback that cannot travel (CALL-10)
|
|
981
|
+
VrpcAdapter._callback({ a, s: clientId, i: eventId, receiverVersion })
|
|
848
982
|
}
|
|
849
983
|
}
|
|
850
984
|
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
const { listener, clients } = VrpcAdapter._listeners[instanceId][eventId]
|
|
857
|
-
const index = clients.indexOf(clientId)
|
|
858
|
-
if (index !== -1) clients.splice(index, 1)
|
|
859
|
-
if (clients.length === 0) {
|
|
860
|
-
delete VrpcAdapter._listeners[instanceId][eventId]
|
|
861
|
-
if (Object.keys(VrpcAdapter._listeners[instanceId]).length === 0) {
|
|
862
|
-
delete VrpcAdapter._listeners[instanceId]
|
|
863
|
-
}
|
|
864
|
-
return listener
|
|
865
|
-
}
|
|
866
|
-
}
|
|
867
|
-
}
|
|
868
|
-
|
|
869
|
-
static _removeAllListeners (event, clientId, instanceId) {
|
|
870
|
-
const eventIds = VrpcAdapter._listeners[instanceId]
|
|
871
|
-
if (!eventIds) return
|
|
872
|
-
Object.entries(eventIds).forEach(([ek, ev]) => {
|
|
873
|
-
if (ev.event === event && ev.clients.includes(clientId)) {
|
|
874
|
-
ev.clients = ev.clients.filter(x => x !== clientId)
|
|
875
|
-
if (ev.clients.length === 0) {
|
|
876
|
-
VrpcAdapter.getInstance(instanceId).removeListener(
|
|
877
|
-
ev.event,
|
|
878
|
-
ev.listener
|
|
879
|
-
)
|
|
880
|
-
delete VrpcAdapter._listeners[instanceId][ek]
|
|
881
|
-
}
|
|
882
|
-
}
|
|
883
|
-
})
|
|
884
|
-
}
|
|
885
|
-
|
|
985
|
+
/**
|
|
986
|
+
* Answers a promise twice: at once with `r: '__p__<f>-<n>'`, and once it
|
|
987
|
+
* settled with a second answer under that id, `{ s, i, r }` or
|
|
988
|
+
* `{ s, i, e }`.
|
|
989
|
+
*/
|
|
886
990
|
static _handlePromise (json, promise) {
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
json.data.e = err.message
|
|
896
|
-
}
|
|
991
|
+
const cid = VrpcAdapter._correlationId++ % Number.MAX_SAFE_INTEGER
|
|
992
|
+
const id = `__p__${json.f}-${cid}`
|
|
993
|
+
const { s } = json
|
|
994
|
+
json.r = id
|
|
995
|
+
promise.then(
|
|
996
|
+
r => VrpcAdapter._callback({ s, i: id, r }),
|
|
997
|
+
err => VrpcAdapter._callback({ s, i: id, e: VrpcAdapter._error(err) })
|
|
998
|
+
)
|
|
897
999
|
}
|
|
898
1000
|
|
|
899
1001
|
static _getClassEntry (className) {
|
|
@@ -929,6 +1031,18 @@ class VrpcAdapter {
|
|
|
929
1031
|
static _extractMemberFunctions (klass) {
|
|
930
1032
|
let klass_ = klass
|
|
931
1033
|
let fs = []
|
|
1034
|
+
// Node's EventEmitter offers subscribing, withdrawing and once to
|
|
1035
|
+
// clients; emit (anyone could fake an event to every subscriber, or emit
|
|
1036
|
+
// 'error' and end the agent) and its internals stay inside the class
|
|
1037
|
+
const isEmitter =
|
|
1038
|
+
klass instanceof EventEmitter ||
|
|
1039
|
+
(!!klass.prototype && klass.prototype instanceof EventEmitter)
|
|
1040
|
+
const published = (names, level) => {
|
|
1041
|
+
if (level === EventEmitter.prototype) {
|
|
1042
|
+
return names.filter(x => VrpcAdapter._emitterPublic.has(x))
|
|
1043
|
+
}
|
|
1044
|
+
return isEmitter ? names.filter(x => x !== 'emit') : names
|
|
1045
|
+
}
|
|
932
1046
|
do {
|
|
933
1047
|
if (klass_.prototype) {
|
|
934
1048
|
const funcs = Object.getOwnPropertyNames(klass_.prototype).filter(
|
|
@@ -936,13 +1050,12 @@ class VrpcAdapter {
|
|
|
936
1050
|
!VrpcAdapter._blackList.has(x) &&
|
|
937
1051
|
VrpcAdapter._isFunction(klass_.prototype[x])
|
|
938
1052
|
)
|
|
939
|
-
fs = [...fs, ...funcs]
|
|
1053
|
+
fs = [...fs, ...published(funcs, klass_.prototype)]
|
|
940
1054
|
} else {
|
|
941
1055
|
const funcs = Object.getOwnPropertyNames(klass_).filter(
|
|
942
|
-
x =>
|
|
943
|
-
!VrpcAdapter._blackList.has(x) && VrpcAdapter._isFunction(klass_[x])
|
|
1056
|
+
x => !VrpcAdapter._blackList.has(x) && VrpcAdapter._isFunction(klass_[x])
|
|
944
1057
|
)
|
|
945
|
-
fs = [...fs, ...funcs]
|
|
1058
|
+
fs = [...fs, ...published(funcs, klass_)]
|
|
946
1059
|
}
|
|
947
1060
|
klass_ = Object.getPrototypeOf(klass_)
|
|
948
1061
|
} while (klass_)
|
|
@@ -954,13 +1067,16 @@ class VrpcAdapter {
|
|
|
954
1067
|
let klass_ = klass
|
|
955
1068
|
let fs = []
|
|
956
1069
|
do {
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
1070
|
+
// EventEmitter's own statics are Node helpers, not the class's API
|
|
1071
|
+
if (klass_ !== EventEmitter) {
|
|
1072
|
+
fs = [
|
|
1073
|
+
...fs,
|
|
1074
|
+
...Object.getOwnPropertyNames(klass_).filter(prop => {
|
|
1075
|
+
const desc = Object.getOwnPropertyDescriptor(klass_, prop)
|
|
1076
|
+
return !!desc && typeof desc.value === 'function'
|
|
1077
|
+
})
|
|
1078
|
+
]
|
|
1079
|
+
}
|
|
964
1080
|
klass_ = Object.getPrototypeOf(klass_)
|
|
965
1081
|
} while (klass_ && klass_.name)
|
|
966
1082
|
// Filter out all duplicates
|
|
@@ -1041,10 +1157,26 @@ VrpcAdapter._functionRegistry = new Map()
|
|
|
1041
1157
|
VrpcAdapter._instances = new Map()
|
|
1042
1158
|
VrpcAdapter._emitter = new EventEmitter()
|
|
1043
1159
|
VrpcAdapter._correlationId = 0
|
|
1044
|
-
|
|
1160
|
+
// the event registrations of every context and their subscriptions
|
|
1161
|
+
VrpcAdapter._registrations = new Registrations({
|
|
1162
|
+
publish: message => VrpcAdapter._callback(message),
|
|
1163
|
+
emit: (event, payload) => VrpcAdapter._emitter.emit(event, payload)
|
|
1164
|
+
})
|
|
1045
1165
|
// the longest a delete waits for the dispose method of its instance
|
|
1046
1166
|
VrpcAdapter.DISPOSE_TIMEOUT = 10000
|
|
1167
|
+
// the EventEmitter functions published to clients
|
|
1168
|
+
VrpcAdapter._emitterPublic = new Set([
|
|
1169
|
+
'on',
|
|
1170
|
+
'addListener',
|
|
1171
|
+
'off',
|
|
1172
|
+
'removeListener',
|
|
1173
|
+
'once',
|
|
1174
|
+
'removeAllListeners'
|
|
1175
|
+
])
|
|
1047
1176
|
VrpcAdapter._blackList = new Set([
|
|
1177
|
+
// a class's constructor is reached through __createShared__ and
|
|
1178
|
+
// __createIsolated__, never as a member function
|
|
1179
|
+
'constructor',
|
|
1048
1180
|
'caller',
|
|
1049
1181
|
'callee',
|
|
1050
1182
|
'arguments',
|