vrpc 3.12.0 → 3.12.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/browser/vrpc.js +1 -1
- package/package.json +1 -1
- package/vrpc/VrpcAgent.js +79 -21
- package/vrpc/VrpcBrowserAgent.js +65 -20
package/package.json
CHANGED
package/vrpc/VrpcAgent.js
CHANGED
|
@@ -153,6 +153,11 @@ class VrpcAgent extends EventEmitter {
|
|
|
153
153
|
subscribe: (topics, options) => this._mqttSubscribe(topics, options),
|
|
154
154
|
log: this._log
|
|
155
155
|
})
|
|
156
|
+
// counts the connections: an announcement belongs to the connection
|
|
157
|
+
// that prepared it (see _handleConnect)
|
|
158
|
+
this._connectGeneration = 0
|
|
159
|
+
// connected, request topics subscribed and info announced
|
|
160
|
+
this._serving = false
|
|
156
161
|
|
|
157
162
|
// Handle the internal error event in case the user forgot to implement it
|
|
158
163
|
this.on('error', err => {
|
|
@@ -172,8 +177,9 @@ class VrpcAgent extends EventEmitter {
|
|
|
172
177
|
* If the connection could not be established because of authorization
|
|
173
178
|
* failure, the 'error' event will be emitted.
|
|
174
179
|
*
|
|
175
|
-
* @return {Promise} Resolves once
|
|
176
|
-
*
|
|
180
|
+
* @return {Promise} Resolves once the agent serves - connected, its
|
|
181
|
+
* request topics subscribed and its info announced - or once it was
|
|
182
|
+
* explicitly ended before that, never rejects
|
|
177
183
|
*/
|
|
178
184
|
async serve () {
|
|
179
185
|
let username = this._username
|
|
@@ -377,7 +383,13 @@ class VrpcAgent extends EventEmitter {
|
|
|
377
383
|
)
|
|
378
384
|
}
|
|
379
385
|
|
|
380
|
-
|
|
386
|
+
/**
|
|
387
|
+
* Subscribes topic(s); `onSettled` is called once the broker has
|
|
388
|
+
* answered (granted, refused or failed alike).
|
|
389
|
+
*
|
|
390
|
+
* @private
|
|
391
|
+
*/
|
|
392
|
+
_mqttSubscribe (topic, options, onSettled) {
|
|
381
393
|
this._client.subscribe(
|
|
382
394
|
topic,
|
|
383
395
|
{ qos: this._qos, ...options },
|
|
@@ -424,6 +436,7 @@ class VrpcAgent extends EventEmitter {
|
|
|
424
436
|
this._log.debug(`Already subscribed to topic '${topic}'`)
|
|
425
437
|
}
|
|
426
438
|
}
|
|
439
|
+
if (onSettled) onSettled()
|
|
427
440
|
}
|
|
428
441
|
)
|
|
429
442
|
}
|
|
@@ -458,12 +471,18 @@ class VrpcAgent extends EventEmitter {
|
|
|
458
471
|
return VrpcAdapter._getMetaData(className)
|
|
459
472
|
}
|
|
460
473
|
|
|
474
|
+
/**
|
|
475
|
+
* Resolves once the agent serves (its own 'connect' event: connected,
|
|
476
|
+
* request topics subscribed, info announced), or once it was ended.
|
|
477
|
+
*
|
|
478
|
+
* @private
|
|
479
|
+
*/
|
|
461
480
|
async _ensureConnected () {
|
|
462
481
|
return new Promise(resolve => {
|
|
463
|
-
if (this.
|
|
482
|
+
if (this._serving) {
|
|
464
483
|
resolve()
|
|
465
484
|
} else {
|
|
466
|
-
this.
|
|
485
|
+
this.once('connect', resolve)
|
|
467
486
|
// Will be triggered if the user called 'agent.end()'
|
|
468
487
|
this.once('end', resolve)
|
|
469
488
|
}
|
|
@@ -502,36 +521,64 @@ class VrpcAgent extends EventEmitter {
|
|
|
502
521
|
return str
|
|
503
522
|
}
|
|
504
523
|
|
|
524
|
+
/**
|
|
525
|
+
* Serve first, announce second. The request topics - the statics and
|
|
526
|
+
* the methods of every instance that exists already - are subscribed
|
|
527
|
+
* before the agent publishes its agent and class info, and the
|
|
528
|
+
* announcement waits until the broker has answered every subscription.
|
|
529
|
+
* A client acts on the announcement at once; a request it publishes
|
|
530
|
+
* before the broker routes the topic is lost (QoS 0) and only times out
|
|
531
|
+
* on the caller's side. That was the fate of the first call into an
|
|
532
|
+
* agent that came online after the client waiting for it. A refused
|
|
533
|
+
* subscription is the retrier's business and delays nothing.
|
|
534
|
+
*
|
|
535
|
+
* @private
|
|
536
|
+
*/
|
|
505
537
|
_handleConnect () {
|
|
506
538
|
this._log.info('[OK]')
|
|
507
539
|
// everything is subscribed afresh: pending retries are moot
|
|
508
540
|
this._subscribeRetrier.cancel()
|
|
541
|
+
const generation = ++this._connectGeneration
|
|
542
|
+
const batches = []
|
|
509
543
|
try {
|
|
510
|
-
const
|
|
511
|
-
if (
|
|
544
|
+
const statics = this._generateTopics()
|
|
545
|
+
if (statics.length > 0) batches.push(statics)
|
|
512
546
|
} catch (err) {
|
|
513
547
|
this._log.error(
|
|
514
548
|
err,
|
|
515
549
|
`Problem during initial topic subscription: ${err.message}`
|
|
516
550
|
)
|
|
517
551
|
}
|
|
518
|
-
//
|
|
519
|
-
this._publishAgentInfoMessage()
|
|
520
|
-
|
|
521
|
-
// Publish class information
|
|
522
|
-
const classes = this._getClasses()
|
|
523
|
-
classes.forEach(className => {
|
|
524
|
-
this._publishClassInfoMessage(className)
|
|
525
|
-
this._publishClassInfoConciseMessage(className)
|
|
526
|
-
})
|
|
527
|
-
// Register all pre-existing instances
|
|
552
|
+
// all pre-existing instances
|
|
528
553
|
for (const [
|
|
529
554
|
instanceId,
|
|
530
555
|
{ className }
|
|
531
556
|
] of VrpcAdapter._instances.entries()) {
|
|
532
|
-
this.
|
|
557
|
+
batches.push(this._methodsTopic(className, instanceId))
|
|
558
|
+
}
|
|
559
|
+
let pending = batches.length
|
|
560
|
+
const announce = () => {
|
|
561
|
+
// a connection that ended meanwhile announces nothing: the next
|
|
562
|
+
// one prepares and announces itself
|
|
563
|
+
if (generation !== this._connectGeneration) return
|
|
564
|
+
this._publishAgentInfoMessage()
|
|
565
|
+
for (const className of this._getClasses()) {
|
|
566
|
+
this._publishClassInfoMessage(className)
|
|
567
|
+
this._publishClassInfoConciseMessage(className)
|
|
568
|
+
}
|
|
569
|
+
this._serving = true
|
|
570
|
+
this.emit('connect')
|
|
571
|
+
}
|
|
572
|
+
if (pending === 0) {
|
|
573
|
+
announce()
|
|
574
|
+
return
|
|
575
|
+
}
|
|
576
|
+
for (const topic of batches) {
|
|
577
|
+
this._mqttSubscribe(topic, undefined, () => {
|
|
578
|
+
pending -= 1
|
|
579
|
+
if (pending === 0) announce()
|
|
580
|
+
})
|
|
533
581
|
}
|
|
534
|
-
this.emit('connect')
|
|
535
582
|
}
|
|
536
583
|
|
|
537
584
|
_publishAgentInfoMessage () {
|
|
@@ -785,14 +832,23 @@ class VrpcAgent extends EventEmitter {
|
|
|
785
832
|
return true
|
|
786
833
|
}
|
|
787
834
|
|
|
835
|
+
/**
|
|
836
|
+
* The request topics of one instance: every method of it.
|
|
837
|
+
*
|
|
838
|
+
* @private
|
|
839
|
+
*/
|
|
840
|
+
_methodsTopic (className, instance) {
|
|
841
|
+
return `${this._baseTopic}/${className}/${instance}/+`
|
|
842
|
+
}
|
|
843
|
+
|
|
788
844
|
_subscribeToMethodsOfNewInstance (className, instance) {
|
|
789
|
-
const topic =
|
|
845
|
+
const topic = this._methodsTopic(className, instance)
|
|
790
846
|
this._mqttSubscribe(topic)
|
|
791
847
|
this._log.debug(`Subscribed to new topic after instantiation: ${topic}`)
|
|
792
848
|
}
|
|
793
849
|
|
|
794
850
|
_unsubscribeMethodsOfDeletedInstance (className, instance) {
|
|
795
|
-
const topic =
|
|
851
|
+
const topic = this._methodsTopic(className, instance)
|
|
796
852
|
this._mqttUnsubscribe(topic)
|
|
797
853
|
this._log.debug(`Unsubscribed from topic after deletion: ${topic}`)
|
|
798
854
|
}
|
|
@@ -807,6 +863,8 @@ class VrpcAgent extends EventEmitter {
|
|
|
807
863
|
}
|
|
808
864
|
|
|
809
865
|
_handleClose () {
|
|
866
|
+
// the next connection prepares and announces itself afresh
|
|
867
|
+
this._serving = false
|
|
810
868
|
this.emit('close')
|
|
811
869
|
}
|
|
812
870
|
|
package/vrpc/VrpcBrowserAgent.js
CHANGED
|
@@ -71,6 +71,11 @@ class VrpcAgent extends EventEmitter {
|
|
|
71
71
|
// maps clientId to instanceId
|
|
72
72
|
this._isolatedInstances = new Map()
|
|
73
73
|
this._sharedInstances = new Map()
|
|
74
|
+
// counts the connections: an announcement belongs to the connection
|
|
75
|
+
// that prepared it (see _handleConnect)
|
|
76
|
+
this._connectGeneration = 0
|
|
77
|
+
// connected, request topics subscribed and info announced
|
|
78
|
+
this._serving = false
|
|
74
79
|
|
|
75
80
|
// Handle the internal error event in case the user forgot to implement it
|
|
76
81
|
this.on('error', err => {
|
|
@@ -90,8 +95,9 @@ class VrpcAgent extends EventEmitter {
|
|
|
90
95
|
* If the connection could not be established because of authorization
|
|
91
96
|
* failure, the 'error' event will be emitted.
|
|
92
97
|
*
|
|
93
|
-
* @return {Promise} Resolves once
|
|
94
|
-
*
|
|
98
|
+
* @return {Promise} Resolves once the agent serves - connected, its
|
|
99
|
+
* request topics subscribed and its info announced - or once it was
|
|
100
|
+
* explicitly ended before that, never rejects
|
|
95
101
|
*/
|
|
96
102
|
async serve () {
|
|
97
103
|
let username = this._username
|
|
@@ -226,7 +232,11 @@ class VrpcAgent extends EventEmitter {
|
|
|
226
232
|
)
|
|
227
233
|
}
|
|
228
234
|
|
|
229
|
-
|
|
235
|
+
/**
|
|
236
|
+
* Subscribes topic(s); `onSettled` is called once the broker has
|
|
237
|
+
* answered (granted, refused or failed alike).
|
|
238
|
+
*/
|
|
239
|
+
_mqttSubscribe (topic, options, onSettled) {
|
|
230
240
|
this._client.subscribe(
|
|
231
241
|
topic,
|
|
232
242
|
{ qos: this._qos, ...options },
|
|
@@ -269,6 +279,7 @@ class VrpcAgent extends EventEmitter {
|
|
|
269
279
|
this._log.debug(`Already subscribed to topic '${topic}'`)
|
|
270
280
|
}
|
|
271
281
|
}
|
|
282
|
+
if (onSettled) onSettled()
|
|
272
283
|
}
|
|
273
284
|
)
|
|
274
285
|
}
|
|
@@ -303,12 +314,16 @@ class VrpcAgent extends EventEmitter {
|
|
|
303
314
|
return VrpcAdapter._getMetaData(className)
|
|
304
315
|
}
|
|
305
316
|
|
|
317
|
+
/**
|
|
318
|
+
* Resolves once the agent serves (its own 'connect' event: connected,
|
|
319
|
+
* request topics subscribed, info announced), or once it was ended.
|
|
320
|
+
*/
|
|
306
321
|
async _ensureConnected () {
|
|
307
322
|
return new Promise(resolve => {
|
|
308
|
-
if (this.
|
|
323
|
+
if (this._serving) {
|
|
309
324
|
resolve()
|
|
310
325
|
} else {
|
|
311
|
-
this.
|
|
326
|
+
this.once('connect', resolve)
|
|
312
327
|
// Will be triggered if the user called 'agent.end()'
|
|
313
328
|
this.once('end', resolve)
|
|
314
329
|
}
|
|
@@ -347,33 +362,56 @@ class VrpcAgent extends EventEmitter {
|
|
|
347
362
|
return str
|
|
348
363
|
}
|
|
349
364
|
|
|
365
|
+
/**
|
|
366
|
+
* Serve first, announce second - the twin of VrpcAgent._handleConnect:
|
|
367
|
+
* every request topic (statics, the methods of every existing instance)
|
|
368
|
+
* is subscribed before the agent and class info go out, and they go out
|
|
369
|
+
* once the broker has answered every subscription. A client acts on the
|
|
370
|
+
* announcement at once; a request published before the broker routes
|
|
371
|
+
* the topic is lost (QoS 0) and only times out on the caller's side.
|
|
372
|
+
*/
|
|
350
373
|
_handleConnect () {
|
|
351
374
|
this._log.info('[OK]')
|
|
375
|
+
const generation = ++this._connectGeneration
|
|
376
|
+
const batches = []
|
|
352
377
|
try {
|
|
353
|
-
const
|
|
354
|
-
if (
|
|
378
|
+
const statics = this._generateTopics()
|
|
379
|
+
if (statics.length > 0) batches.push(statics)
|
|
355
380
|
} catch (err) {
|
|
356
381
|
this._log.error(
|
|
357
382
|
err,
|
|
358
383
|
`Problem during initial topic subscription: ${err.message}`
|
|
359
384
|
)
|
|
360
385
|
}
|
|
361
|
-
//
|
|
362
|
-
this._publishAgentInfoMessage()
|
|
363
|
-
|
|
364
|
-
// Publish class information
|
|
365
|
-
const classes = this._getClasses()
|
|
366
|
-
classes.forEach(className => {
|
|
367
|
-
this._publishClassInfoMessage(className)
|
|
368
|
-
})
|
|
369
|
-
// Register all pre-existing instances
|
|
386
|
+
// all pre-existing instances
|
|
370
387
|
for (const [
|
|
371
388
|
instanceId,
|
|
372
389
|
{ className }
|
|
373
390
|
] of VrpcAdapter._instances.entries()) {
|
|
374
|
-
this.
|
|
391
|
+
batches.push(this._methodsTopic(className, instanceId))
|
|
392
|
+
}
|
|
393
|
+
let pending = batches.length
|
|
394
|
+
const announce = () => {
|
|
395
|
+
// a connection that ended meanwhile announces nothing: the next
|
|
396
|
+
// one prepares and announces itself
|
|
397
|
+
if (generation !== this._connectGeneration) return
|
|
398
|
+
this._publishAgentInfoMessage()
|
|
399
|
+
for (const className of this._getClasses()) {
|
|
400
|
+
this._publishClassInfoMessage(className)
|
|
401
|
+
}
|
|
402
|
+
this._serving = true
|
|
403
|
+
this.emit('connect')
|
|
404
|
+
}
|
|
405
|
+
if (pending === 0) {
|
|
406
|
+
announce()
|
|
407
|
+
return
|
|
408
|
+
}
|
|
409
|
+
for (const topic of batches) {
|
|
410
|
+
this._mqttSubscribe(topic, undefined, () => {
|
|
411
|
+
pending -= 1
|
|
412
|
+
if (pending === 0) announce()
|
|
413
|
+
})
|
|
375
414
|
}
|
|
376
|
-
this.emit('connect')
|
|
377
415
|
}
|
|
378
416
|
|
|
379
417
|
_publishAgentInfoMessage () {
|
|
@@ -592,14 +630,19 @@ class VrpcAgent extends EventEmitter {
|
|
|
592
630
|
return true
|
|
593
631
|
}
|
|
594
632
|
|
|
633
|
+
/** The request topics of one instance: every method of it. */
|
|
634
|
+
_methodsTopic (className, instance) {
|
|
635
|
+
return `${this._baseTopic}/${className}/${instance}/+`
|
|
636
|
+
}
|
|
637
|
+
|
|
595
638
|
_subscribeToMethodsOfNewInstance (className, instance) {
|
|
596
|
-
const topic =
|
|
639
|
+
const topic = this._methodsTopic(className, instance)
|
|
597
640
|
this._mqttSubscribe(topic)
|
|
598
641
|
this._log.debug(`Subscribed to new topic after instantiation: ${topic}`)
|
|
599
642
|
}
|
|
600
643
|
|
|
601
644
|
_unsubscribeMethodsOfDeletedInstance (className, instance) {
|
|
602
|
-
const topic =
|
|
645
|
+
const topic = this._methodsTopic(className, instance)
|
|
603
646
|
this._mqttUnsubscribe(topic)
|
|
604
647
|
this._log.debug(`Unsubscribed from topic after deletion: ${topic}`)
|
|
605
648
|
}
|
|
@@ -614,6 +657,8 @@ class VrpcAgent extends EventEmitter {
|
|
|
614
657
|
}
|
|
615
658
|
|
|
616
659
|
_handleClose () {
|
|
660
|
+
// the next connection prepares and announces itself afresh
|
|
661
|
+
this._serving = false
|
|
617
662
|
this.emit('close')
|
|
618
663
|
}
|
|
619
664
|
|