@rails/actioncable 6.1.4-6 → 6.1.5-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.
@@ -291,6 +291,7 @@
291
291
  return this.monitor.recordPing();
292
292
 
293
293
  case message_types.confirmation:
294
+ this.subscriptions.confirmSubscription(identifier);
294
295
  return this.subscriptions.notify(identifier, "connected");
295
296
 
296
297
  case message_types.rejection:
@@ -360,10 +361,52 @@
360
361
  };
361
362
  return Subscription;
362
363
  }();
364
+ var SubscriptionGuarantor = function() {
365
+ function SubscriptionGuarantor(subscriptions) {
366
+ classCallCheck(this, SubscriptionGuarantor);
367
+ this.subscriptions = subscriptions;
368
+ this.pendingSubscriptions = [];
369
+ }
370
+ SubscriptionGuarantor.prototype.guarantee = function guarantee(subscription) {
371
+ if (this.pendingSubscriptions.indexOf(subscription) == -1) {
372
+ logger.log("SubscriptionGuarantor guaranteeing " + subscription.identifier);
373
+ this.pendingSubscriptions.push(subscription);
374
+ } else {
375
+ logger.log("SubscriptionGuarantor already guaranteeing " + subscription.identifier);
376
+ }
377
+ this.startGuaranteeing();
378
+ };
379
+ SubscriptionGuarantor.prototype.forget = function forget(subscription) {
380
+ logger.log("SubscriptionGuarantor forgetting " + subscription.identifier);
381
+ this.pendingSubscriptions = this.pendingSubscriptions.filter(function(s) {
382
+ return s !== subscription;
383
+ });
384
+ };
385
+ SubscriptionGuarantor.prototype.startGuaranteeing = function startGuaranteeing() {
386
+ this.stopGuaranteeing();
387
+ this.retrySubscribing();
388
+ };
389
+ SubscriptionGuarantor.prototype.stopGuaranteeing = function stopGuaranteeing() {
390
+ clearTimeout(this.retryTimeout);
391
+ };
392
+ SubscriptionGuarantor.prototype.retrySubscribing = function retrySubscribing() {
393
+ var _this = this;
394
+ this.retryTimeout = setTimeout(function() {
395
+ if (_this.subscriptions && typeof _this.subscriptions.subscribe === "function") {
396
+ _this.pendingSubscriptions.map(function(subscription) {
397
+ logger.log("SubscriptionGuarantor resubscribing " + subscription.identifier);
398
+ _this.subscriptions.subscribe(subscription);
399
+ });
400
+ }
401
+ }, 500);
402
+ };
403
+ return SubscriptionGuarantor;
404
+ }();
363
405
  var Subscriptions = function() {
364
406
  function Subscriptions(consumer) {
365
407
  classCallCheck(this, Subscriptions);
366
408
  this.consumer = consumer;
409
+ this.guarantor = new SubscriptionGuarantor(this);
367
410
  this.subscriptions = [];
368
411
  }
369
412
  Subscriptions.prototype.create = function create(channelName, mixin) {
@@ -378,7 +421,7 @@
378
421
  this.subscriptions.push(subscription);
379
422
  this.consumer.ensureActiveConnection();
380
423
  this.notify(subscription, "initialized");
381
- this.sendCommand(subscription, "subscribe");
424
+ this.subscribe(subscription);
382
425
  return subscription;
383
426
  };
384
427
  Subscriptions.prototype.remove = function remove(subscription) {
@@ -397,6 +440,7 @@
397
440
  });
398
441
  };
399
442
  Subscriptions.prototype.forget = function forget(subscription) {
443
+ this.guarantor.forget(subscription);
400
444
  this.subscriptions = this.subscriptions.filter(function(s) {
401
445
  return s !== subscription;
402
446
  });
@@ -410,7 +454,7 @@
410
454
  Subscriptions.prototype.reload = function reload() {
411
455
  var _this2 = this;
412
456
  return this.subscriptions.map(function(subscription) {
413
- return _this2.sendCommand(subscription, "subscribe");
457
+ return _this2.subscribe(subscription);
414
458
  });
415
459
  };
416
460
  Subscriptions.prototype.notifyAll = function notifyAll(callbackName) {
@@ -436,6 +480,18 @@
436
480
  return typeof subscription[callbackName] === "function" ? subscription[callbackName].apply(subscription, args) : undefined;
437
481
  });
438
482
  };
483
+ Subscriptions.prototype.subscribe = function subscribe(subscription) {
484
+ if (this.sendCommand(subscription, "subscribe")) {
485
+ this.guarantor.guarantee(subscription);
486
+ }
487
+ };
488
+ Subscriptions.prototype.confirmSubscription = function confirmSubscription(identifier) {
489
+ var _this4 = this;
490
+ logger.log("Subscription confirmed " + identifier);
491
+ this.findAll(identifier).map(function(subscription) {
492
+ return _this4.guarantor.forget(subscription);
493
+ });
494
+ };
439
495
  Subscriptions.prototype.sendCommand = function sendCommand(subscription, command) {
440
496
  var identifier = subscription.identifier;
441
497
  return this.consumer.send({
@@ -506,6 +562,7 @@
506
562
  exports.INTERNAL = INTERNAL;
507
563
  exports.Subscription = Subscription;
508
564
  exports.Subscriptions = Subscriptions;
565
+ exports.SubscriptionGuarantor = SubscriptionGuarantor;
509
566
  exports.adapters = adapters;
510
567
  exports.createWebSocketURL = createWebSocketURL;
511
568
  exports.logger = logger;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rails/actioncable",
3
- "version": "6.1.4-6",
3
+ "version": "6.1.5-1",
4
4
  "description": "WebSocket framework for Ruby on Rails.",
5
5
  "main": "app/assets/javascripts/action_cable.js",
6
6
  "files": [
package/src/connection.js CHANGED
@@ -132,6 +132,7 @@ Connection.prototype.events = {
132
132
  case message_types.ping:
133
133
  return this.monitor.recordPing()
134
134
  case message_types.confirmation:
135
+ this.subscriptions.confirmSubscription(identifier)
135
136
  return this.subscriptions.notify(identifier, "connected")
136
137
  case message_types.rejection:
137
138
  return this.subscriptions.reject(identifier)
package/src/index.js CHANGED
@@ -4,6 +4,7 @@ import Consumer, { createWebSocketURL } from "./consumer"
4
4
  import INTERNAL from "./internal"
5
5
  import Subscription from "./subscription"
6
6
  import Subscriptions from "./subscriptions"
7
+ import SubscriptionGuarantor from "./subscription_guarantor"
7
8
  import adapters from "./adapters"
8
9
  import logger from "./logger"
9
10
 
@@ -14,6 +15,7 @@ export {
14
15
  INTERNAL,
15
16
  Subscription,
16
17
  Subscriptions,
18
+ SubscriptionGuarantor,
17
19
  adapters,
18
20
  createWebSocketURL,
19
21
  logger,
@@ -0,0 +1,50 @@
1
+ import logger from "./logger"
2
+
3
+ // Responsible for ensuring channel subscribe command is confirmed, retrying until confirmation is received.
4
+ // Internal class, not intended for direct user manipulation.
5
+
6
+ class SubscriptionGuarantor {
7
+ constructor(subscriptions) {
8
+ this.subscriptions = subscriptions
9
+ this.pendingSubscriptions = []
10
+ }
11
+
12
+ guarantee(subscription) {
13
+ if(this.pendingSubscriptions.indexOf(subscription) == -1){
14
+ logger.log(`SubscriptionGuarantor guaranteeing ${subscription.identifier}`)
15
+ this.pendingSubscriptions.push(subscription)
16
+ }
17
+ else {
18
+ logger.log(`SubscriptionGuarantor already guaranteeing ${subscription.identifier}`)
19
+ }
20
+ this.startGuaranteeing()
21
+ }
22
+
23
+ forget(subscription) {
24
+ logger.log(`SubscriptionGuarantor forgetting ${subscription.identifier}`)
25
+ this.pendingSubscriptions = (this.pendingSubscriptions.filter((s) => s !== subscription))
26
+ }
27
+
28
+ startGuaranteeing() {
29
+ this.stopGuaranteeing()
30
+ this.retrySubscribing()
31
+ }
32
+
33
+ stopGuaranteeing() {
34
+ clearTimeout(this.retryTimeout)
35
+ }
36
+
37
+ retrySubscribing() {
38
+ this.retryTimeout = setTimeout(() => {
39
+ if (this.subscriptions && typeof(this.subscriptions.subscribe) === "function") {
40
+ this.pendingSubscriptions.map((subscription) => {
41
+ logger.log(`SubscriptionGuarantor resubscribing ${subscription.identifier}`)
42
+ this.subscriptions.subscribe(subscription)
43
+ })
44
+ }
45
+ }
46
+ , 500)
47
+ }
48
+ }
49
+
50
+ export default SubscriptionGuarantor
@@ -1,4 +1,6 @@
1
1
  import Subscription from "./subscription"
2
+ import SubscriptionGuarantor from "./subscription_guarantor"
3
+ import logger from "./logger"
2
4
 
3
5
  // Collection class for creating (and internally managing) channel subscriptions.
4
6
  // The only method intended to be triggered by the user is ActionCable.Subscriptions#create,
@@ -13,6 +15,7 @@ import Subscription from "./subscription"
13
15
  export default class Subscriptions {
14
16
  constructor(consumer) {
15
17
  this.consumer = consumer
18
+ this.guarantor = new SubscriptionGuarantor(this)
16
19
  this.subscriptions = []
17
20
  }
18
21
 
@@ -29,7 +32,7 @@ export default class Subscriptions {
29
32
  this.subscriptions.push(subscription)
30
33
  this.consumer.ensureActiveConnection()
31
34
  this.notify(subscription, "initialized")
32
- this.sendCommand(subscription, "subscribe")
35
+ this.subscribe(subscription)
33
36
  return subscription
34
37
  }
35
38
 
@@ -50,6 +53,7 @@ export default class Subscriptions {
50
53
  }
51
54
 
52
55
  forget(subscription) {
56
+ this.guarantor.forget(subscription)
53
57
  this.subscriptions = (this.subscriptions.filter((s) => s !== subscription))
54
58
  return subscription
55
59
  }
@@ -60,7 +64,7 @@ export default class Subscriptions {
60
64
 
61
65
  reload() {
62
66
  return this.subscriptions.map((subscription) =>
63
- this.sendCommand(subscription, "subscribe"))
67
+ this.subscribe(subscription))
64
68
  }
65
69
 
66
70
  notifyAll(callbackName, ...args) {
@@ -80,6 +84,18 @@ export default class Subscriptions {
80
84
  (typeof subscription[callbackName] === "function" ? subscription[callbackName](...args) : undefined))
81
85
  }
82
86
 
87
+ subscribe(subscription) {
88
+ if (this.sendCommand(subscription, "subscribe")) {
89
+ this.guarantor.guarantee(subscription)
90
+ }
91
+ }
92
+
93
+ confirmSubscription(identifier) {
94
+ logger.log(`Subscription confirmed ${identifier}`)
95
+ this.findAll(identifier).map((subscription) =>
96
+ this.guarantor.forget(subscription))
97
+ }
98
+
83
99
  sendCommand(subscription, command) {
84
100
  const {identifier} = subscription
85
101
  return this.consumer.send({command, identifier})