@rails/actioncable 6.1.4 → 6.1.6-1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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",
3
+ "version": "6.1.6-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})
package/CHANGELOG.md DELETED
@@ -1,77 +0,0 @@
1
- ## Rails 6.1.4 (June 24, 2021) ##
2
-
3
- * Fix `ArgumentError` with ruby 3.0 on `RemoteConnection#disconnect`.
4
-
5
- *Vladislav*
6
-
7
-
8
- ## Rails 6.1.3.2 (May 05, 2021) ##
9
-
10
- * No changes.
11
-
12
-
13
- ## Rails 6.1.3.1 (March 26, 2021) ##
14
-
15
- * No changes.
16
-
17
-
18
- ## Rails 6.1.3 (February 17, 2021) ##
19
-
20
- * No changes.
21
-
22
-
23
- ## Rails 6.1.2.1 (February 10, 2021) ##
24
-
25
- * No changes.
26
-
27
-
28
- ## Rails 6.1.2 (February 09, 2021) ##
29
-
30
- * No changes.
31
-
32
-
33
- ## Rails 6.1.1 (January 07, 2021) ##
34
-
35
- * No changes.
36
-
37
-
38
- ## Rails 6.1.0 (December 09, 2020) ##
39
-
40
- * `ActionCable::Connection::Base` now allows intercepting unhandled exceptions
41
- with `rescue_from` before they are logged, which is useful for error reporting
42
- tools and other integrations.
43
-
44
- *Justin Talbott*
45
-
46
- * Add `ActionCable::Channel#stream_or_reject_for` to stream if record is present, otherwise reject the connection
47
-
48
- *Atul Bhosale*
49
-
50
- * Add `ActionCable::Channel#stop_stream_from` and `#stop_stream_for` to unsubscribe from a specific stream.
51
-
52
- *Zhang Kang*
53
-
54
- * Add PostgreSQL subscription connection identificator.
55
-
56
- Now you can distinguish Action Cable PostgreSQL subscription connections among others.
57
- Also, you can set custom `id` in `cable.yml` configuration.
58
-
59
- ```sql
60
- SELECT application_name FROM pg_stat_activity;
61
- /*
62
- application_name
63
- ------------------------
64
- psql
65
- ActionCable-PID-42
66
- (2 rows)
67
- */
68
- ```
69
-
70
- *Sergey Ponomarev*
71
-
72
- * Subscription confirmations and rejections are now logged at the `DEBUG` level instead of `INFO`.
73
-
74
- *DHH*
75
-
76
-
77
- Please check [6-0-stable](https://github.com/rails/rails/blob/6-0-stable/actioncable/CHANGELOG.md) for previous changes.