actioncable 6.0.6.1 → 6.1.7.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 882be1e6676b7ce91097561f41e964e5f0d2e1d35c38e157c9d5c86dc4b3d008
4
- data.tar.gz: fcf2c1e56a948ab0d57d70aeaf6ae041bdb860d98dcd3a9e93017746211579e5
3
+ metadata.gz: 9eb88c84ff926e7ab47c12d491e78798b891fdf57095d1379866c15cbad83106
4
+ data.tar.gz: fbb54a006e030cfd1dd711f3e317942aaaae92a853cef920417852a48b7ecbb7
5
5
  SHA512:
6
- metadata.gz: ec8b14e09d3d322f5ecd792bba2f2cc3febff0c84acf0759fc9640922a5f19fb9d190e86016eacd565dc214f0c7b3f605d7cc99f97699c707af7e13bff760399
7
- data.tar.gz: e17602b825c53a4a7ab78b087a31c5a076c3ca642b37f9c3bdd55cff6c7b95533b892314bb518aadada934f26affd2d1fdb597d56ff8b652a60a01c632f8e434
6
+ metadata.gz: eee59b19157d761dad768c8f14195d85ffee31920c19edbf4ed16ceee23827a8365b1ba85057695042bae685191aff6f7d9b4de8994b3a6115711e3bd4391e66
7
+ data.tar.gz: b5a73ade374018bd881461d9ea287707bedfa08cb72b7d256cd32f2de84ba56390c86a996a3335502a75bca53bfbe2c7c04c70fb5519f9c4774cb0a09eb10320
data/CHANGELOG.md CHANGED
@@ -1,299 +1,180 @@
1
- ## Rails 6.0.6.1 (January 17, 2023) ##
1
+ ## Rails 6.1.7.6 (August 22, 2023) ##
2
2
 
3
3
  * No changes.
4
4
 
5
5
 
6
- ## Rails 6.0.6 (September 09, 2022) ##
6
+ ## Rails 6.1.7.5 (August 22, 2023) ##
7
7
 
8
8
  * No changes.
9
9
 
10
10
 
11
- ## Rails 6.0.5.1 (July 12, 2022) ##
11
+ ## Rails 6.1.7.4 (June 26, 2023) ##
12
12
 
13
13
  * No changes.
14
14
 
15
15
 
16
- ## Rails 6.0.5 (May 09, 2022) ##
16
+ ## Rails 6.1.7.3 (March 13, 2023) ##
17
17
 
18
18
  * No changes.
19
19
 
20
20
 
21
- ## Rails 6.0.4.8 (April 26, 2022) ##
21
+ ## Rails 6.1.7.2 (January 24, 2023) ##
22
22
 
23
23
  * No changes.
24
24
 
25
25
 
26
- ## Rails 6.0.4.7 (March 08, 2022) ##
26
+ ## Rails 6.1.7.1 (January 17, 2023) ##
27
27
 
28
28
  * No changes.
29
29
 
30
30
 
31
- ## Rails 6.0.4.6 (February 11, 2022) ##
31
+ ## Rails 6.1.7 (September 09, 2022) ##
32
32
 
33
33
  * No changes.
34
34
 
35
35
 
36
- ## Rails 6.0.4.5 (February 11, 2022) ##
36
+ ## Rails 6.1.6.1 (July 12, 2022) ##
37
37
 
38
38
  * No changes.
39
39
 
40
40
 
41
- ## Rails 6.0.4.4 (December 15, 2021) ##
41
+ ## Rails 6.1.6 (May 09, 2022) ##
42
42
 
43
43
  * No changes.
44
44
 
45
45
 
46
- ## Rails 6.0.4.3 (December 14, 2021) ##
46
+ ## Rails 6.1.5.1 (April 26, 2022) ##
47
47
 
48
48
  * No changes.
49
49
 
50
50
 
51
- ## Rails 6.0.4.2 (December 14, 2021) ##
52
-
53
- * No changes.
51
+ ## Rails 6.1.5 (March 09, 2022) ##
54
52
 
53
+ * The Action Cable client now ensures successful channel subscriptions:
55
54
 
56
- ## Rails 6.0.4.1 (August 19, 2021) ##
57
-
58
- * No changes.
55
+ * The client maintains a set of pending subscriptions until either
56
+ the server confirms the subscription or the channel is torn down.
57
+ * Rectifies the race condition where an unsubscribe is rapidly followed
58
+ by a subscribe (on the same channel identifier) and the requests are
59
+ handled out of order by the ActionCable server, thereby ignoring the
60
+ subscribe command.
59
61
 
62
+ *Daniel Spinosa*
60
63
 
61
- ## Rails 6.0.4 (June 15, 2021) ##
64
+ * Truncate broadcast logging messages.
62
65
 
63
- * No changes.
66
+ *J Smith*
64
67
 
65
68
 
66
- ## Rails 6.0.3.7 (May 05, 2021) ##
69
+ ## Rails 6.1.4.7 (March 08, 2022) ##
67
70
 
68
71
  * No changes.
69
72
 
70
73
 
71
- ## Rails 6.0.3.6 (May 04, 2021) ##
74
+ ## Rails 6.1.4.6 (February 11, 2022) ##
72
75
 
73
76
  * No changes.
74
77
 
75
78
 
76
- ## Rails 6.0.3.6 (March 26, 2021) ##
79
+ ## Rails 6.1.4.5 (February 11, 2022) ##
77
80
 
78
81
  * No changes.
79
82
 
80
83
 
81
- ## Rails 6.0.3.5 (February 10, 2021) ##
84
+ ## Rails 6.1.4.4 (December 15, 2021) ##
82
85
 
83
86
  * No changes.
84
87
 
85
88
 
86
- ## Rails 6.0.3.4 (October 07, 2020) ##
89
+ ## Rails 6.1.4.3 (December 14, 2021) ##
87
90
 
88
91
  * No changes.
89
92
 
90
93
 
91
- ## Rails 6.0.3.3 (September 09, 2020) ##
94
+ ## Rails 6.1.4.2 (December 14, 2021) ##
92
95
 
93
96
  * No changes.
94
97
 
95
98
 
96
- ## Rails 6.0.3.2 (June 17, 2020) ##
99
+ ## Rails 6.1.4.1 (August 19, 2021) ##
97
100
 
98
101
  * No changes.
99
102
 
100
103
 
101
- ## Rails 6.0.3.1 (May 18, 2020) ##
102
-
103
- * No changes.
104
+ ## Rails 6.1.4 (June 24, 2021) ##
104
105
 
106
+ * Fix `ArgumentError` with ruby 3.0 on `RemoteConnection#disconnect`.
105
107
 
106
- ## Rails 6.0.3 (May 06, 2020) ##
108
+ *Vladislav*
107
109
 
108
- * No changes.
109
110
 
110
-
111
- ## Rails 6.0.2.2 (March 19, 2020) ##
111
+ ## Rails 6.1.3.2 (May 05, 2021) ##
112
112
 
113
113
  * No changes.
114
114
 
115
115
 
116
- ## Rails 6.0.2.1 (December 18, 2019) ##
116
+ ## Rails 6.1.3.1 (March 26, 2021) ##
117
117
 
118
118
  * No changes.
119
119
 
120
120
 
121
- ## Rails 6.0.2 (December 13, 2019) ##
121
+ ## Rails 6.1.3 (February 17, 2021) ##
122
122
 
123
123
  * No changes.
124
124
 
125
125
 
126
- ## Rails 6.0.1 (November 5, 2019) ##
126
+ ## Rails 6.1.2.1 (February 10, 2021) ##
127
127
 
128
128
  * No changes.
129
129
 
130
130
 
131
- ## Rails 6.0.0 (August 16, 2019) ##
131
+ ## Rails 6.1.2 (February 09, 2021) ##
132
132
 
133
133
  * No changes.
134
134
 
135
135
 
136
- ## Rails 6.0.0.rc2 (July 22, 2019) ##
136
+ ## Rails 6.1.1 (January 07, 2021) ##
137
137
 
138
138
  * No changes.
139
139
 
140
140
 
141
- ## Rails 6.0.0.rc1 (April 24, 2019) ##
142
-
143
- * No changes.
144
-
145
-
146
- ## Rails 6.0.0.beta3 (March 11, 2019) ##
147
-
148
- * No changes.
141
+ ## Rails 6.1.0 (December 09, 2020) ##
149
142
 
143
+ * `ActionCable::Connection::Base` now allows intercepting unhandled exceptions
144
+ with `rescue_from` before they are logged, which is useful for error reporting
145
+ tools and other integrations.
150
146
 
151
- ## Rails 6.0.0.beta2 (February 25, 2019) ##
147
+ *Justin Talbott*
152
148
 
153
- * PostgreSQL subscription adapters now support `channel_prefix` option in cable.yml
149
+ * Add `ActionCable::Channel#stream_or_reject_for` to stream if record is present, otherwise reject the connection
154
150
 
155
- Avoids channel name collisions when multiple apps use the same database for Action Cable.
156
-
157
- *Vladimir Dementyev*
158
-
159
- * Allow passing custom configuration to `ActionCable::Server::Base`.
160
-
161
- You can now create a standalone Action Cable server with a custom configuration
162
- (e.g. to run it in isolation from the default one):
163
-
164
- ```ruby
165
- config = ActionCable::Server::Configuration.new
166
- config.cable = { adapter: "redis", channel_prefix: "custom_" }
167
-
168
- CUSTOM_CABLE = ActionCable::Server::Base.new(config: config)
169
- ```
170
-
171
- Then you can mount it in the `routes.rb` file:
172
-
173
- ```ruby
174
- Rails.application.routes.draw do
175
- mount CUSTOM_CABLE => "/custom_cable"
176
- # ...
177
- end
178
- ```
179
-
180
- *Vladimir Dementyev*
181
-
182
- * Add `:action_cable_connection` and `:action_cable_channel` load hooks.
183
-
184
- You can use them to extend `ActionCable::Connection::Base` and `ActionCable::Channel::Base`
185
- functionality:
186
-
187
- ```ruby
188
- ActiveSupport.on_load(:action_cable_channel) do
189
- # do something in the context of ActionCable::Channel::Base
190
- end
191
- ```
151
+ *Atul Bhosale*
192
152
 
193
- *Vladimir Dementyev*
153
+ * Add `ActionCable::Channel#stop_stream_from` and `#stop_stream_for` to unsubscribe from a specific stream.
194
154
 
195
- * Add `Channel::Base#broadcast_to`.
155
+ *Zhang Kang*
196
156
 
197
- You can now call `broadcast_to` within a channel action, which equals to
198
- the `self.class.broadcast_to`.
157
+ * Add PostgreSQL subscription connection identificator.
199
158
 
200
- *Vladimir Dementyev*
159
+ Now you can distinguish Action Cable PostgreSQL subscription connections among others.
160
+ Also, you can set custom `id` in `cable.yml` configuration.
201
161
 
202
- * Make `Channel::Base.broadcasting_for` a public API.
203
-
204
- You can use `.broadcasting_for` to generate a unique stream identifier within
205
- a channel for the specified target (e.g. Active Record model):
206
-
207
- ```ruby
208
- ChatChannel.broadcasting_for(model) # => "chat:<model.to_gid_param>"
209
- ```
210
-
211
- *Vladimir Dementyev*
212
-
213
-
214
- ## Rails 6.0.0.beta1 (January 18, 2019) ##
215
-
216
- * [Rename npm package](https://github.com/rails/rails/pull/34905) from
217
- [`actioncable`](https://www.npmjs.com/package/actioncable) to
218
- [`@rails/actioncable`](https://www.npmjs.com/package/@rails/actioncable).
219
-
220
- *Javan Makhmali*
221
-
222
- * Merge [`action-cable-testing`](https://github.com/palkan/action-cable-testing) to Rails.
223
-
224
- *Vladimir Dementyev*
225
-
226
- * The JavaScript WebSocket client will no longer try to reconnect
227
- when you call `reject_unauthorized_connection` on the connection.
228
-
229
- *Mick Staugaard*
230
-
231
- * `ActionCable.Connection#getState` now references the configurable
232
- `ActionCable.adapters.WebSocket` property rather than the `WebSocket` global
233
- variable, matching the behavior of `ActionCable.Connection#open`.
234
-
235
- *Richard Macklin*
236
-
237
- * The ActionCable javascript package has been converted from CoffeeScript
238
- to ES2015, and we now publish the source code in the npm distribution.
239
-
240
- This allows ActionCable users to depend on the javascript source code
241
- rather than the compiled code, which can produce smaller javascript bundles.
242
-
243
- This change includes some breaking changes to optional parts of the
244
- ActionCable javascript API:
245
-
246
- - Configuration of the WebSocket adapter and logger adapter have been moved
247
- from properties of `ActionCable` to properties of `ActionCable.adapters`.
248
- If you are currently configuring these adapters you will need to make
249
- these changes when upgrading:
250
-
251
- ```diff
252
- - ActionCable.WebSocket = MyWebSocket
253
- + ActionCable.adapters.WebSocket = MyWebSocket
254
- ```
255
- ```diff
256
- - ActionCable.logger = myLogger
257
- + ActionCable.adapters.logger = myLogger
258
- ```
259
-
260
- - The `ActionCable.startDebugging()` and `ActionCable.stopDebugging()`
261
- methods have been removed and replaced with the property
262
- `ActionCable.logger.enabled`. If you are currently using these methods you
263
- will need to make these changes when upgrading:
264
-
265
- ```diff
266
- - ActionCable.startDebugging()
267
- + ActionCable.logger.enabled = true
268
- ```
269
- ```diff
270
- - ActionCable.stopDebugging()
271
- + ActionCable.logger.enabled = false
272
- ```
273
-
274
- *Richard Macklin*
275
-
276
- * Add `id` option to redis adapter so now you can distinguish
277
- ActionCable's redis connections among others. Also, you can set
278
- custom id in options.
279
-
280
- Before:
281
- ```
282
- $ redis-cli client list
283
- id=669 addr=127.0.0.1:46442 fd=8 name= age=18 ...
284
- ```
285
-
286
- After:
287
- ```
288
- $ redis-cli client list
289
- id=673 addr=127.0.0.1:46516 fd=8 name=ActionCable-PID-19413 age=2 ...
162
+ ```sql
163
+ SELECT application_name FROM pg_stat_activity;
164
+ /*
165
+ application_name
166
+ ------------------------
167
+ psql
168
+ ActionCable-PID-42
169
+ (2 rows)
170
+ */
290
171
  ```
291
172
 
292
- *Ilia Kasianenko*
173
+ *Sergey Ponomarev*
293
174
 
294
- * Rails 6 requires Ruby 2.5.0 or newer.
175
+ * Subscription confirmations and rejections are now logged at the `DEBUG` level instead of `INFO`.
295
176
 
296
- *Jeremy Daer*, *Kasper Timm Hansen*
177
+ *DHH*
297
178
 
298
179
 
299
- Please check [5-2-stable](https://github.com/rails/rails/blob/5-2-stable/actioncable/CHANGELOG.md) for previous changes.
180
+ Please check [6-0-stable](https://github.com/rails/rails/blob/6-0-stable/actioncable/CHANGELOG.md) for previous changes.
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2015-2019 Basecamp, LLC
1
+ Copyright (c) 2015-2022 Basecamp, LLC
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
@@ -135,7 +135,7 @@
135
135
  if (document.visibilityState === "visible") {
136
136
  setTimeout(function() {
137
137
  if (_this2.connectionIsStale() || !_this2.connection.isOpen()) {
138
- logger.log("ConnectionMonitor reopening stale connection on visibilitychange. visbilityState = " + document.visibilityState);
138
+ logger.log("ConnectionMonitor reopening stale connection on visibilitychange. visibilityState = " + document.visibilityState);
139
139
  _this2.connection.reopen();
140
140
  }
141
141
  }, 200);
@@ -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;
@@ -194,7 +194,7 @@ module ActionCable
194
194
  end
195
195
 
196
196
  private
197
- # Called once a consumer has become a subscriber of the channel. Usually the place to setup any streams
197
+ # Called once a consumer has become a subscriber of the channel. Usually the place to set up any streams
198
198
  # you want this channel to be sending to the subscriber.
199
199
  def subscribed # :doc:
200
200
  # Override in subclasses
@@ -283,7 +283,7 @@ module ActionCable
283
283
 
284
284
  def transmit_subscription_confirmation
285
285
  unless subscription_confirmation_sent?
286
- logger.info "#{self.class.name} is transmitting the subscription confirmation"
286
+ logger.debug "#{self.class.name} is transmitting the subscription confirmation"
287
287
 
288
288
  ActiveSupport::Notifications.instrument("transmit_subscription_confirmation.action_cable", channel_class: self.class.name) do
289
289
  connection.transmit identifier: @identifier, type: ActionCable::INTERNAL[:message_types][:confirmation]
@@ -298,7 +298,7 @@ module ActionCable
298
298
  end
299
299
 
300
300
  def transmit_subscription_rejection
301
- logger.info "#{self.class.name} is transmitting the subscription rejection"
301
+ logger.debug "#{self.class.name} is transmitting the subscription rejection"
302
302
 
303
303
  ActiveSupport::Notifications.instrument("transmit_subscription_rejection.action_cable", channel_class: self.class.name) do
304
304
  connection.transmit identifier: @identifier, type: ActionCable::INTERNAL[:message_types][:rejection]
@@ -14,7 +14,7 @@ module ActionCable
14
14
  # Chats::AppearancesChannel.channel_name # => 'chats:appearances'
15
15
  # FooChats::BarAppearancesChannel.channel_name # => 'foo_chats:bar_appearances'
16
16
  def channel_name
17
- @channel_name ||= name.sub(/Channel$/, "").gsub("::", ":").underscore
17
+ @channel_name ||= name.delete_suffix("Channel").gsub("::", ":").underscore
18
18
  end
19
19
  end
20
20
 
@@ -25,7 +25,7 @@ module ActionCable
25
25
  #
26
26
  # An example broadcasting for this channel looks like so:
27
27
  #
28
- # ActionCable.server.broadcast "comments_for_45", author: 'DHH', content: 'Rails is just swell'
28
+ # ActionCable.server.broadcast "comments_for_45", { author: 'DHH', content: 'Rails is just swell' }
29
29
  #
30
30
  # If you have a stream that is related to a model, then the broadcasting used can be generated from the model and channel.
31
31
  # The following example would subscribe to a broadcasting like <tt>comments:Z2lkOi8vVGVzdEFwcC9Qb3N0LzE</tt>.
@@ -82,7 +82,7 @@ module ActionCable
82
82
  # Build a stream handler by wrapping the user-provided callback with
83
83
  # a decoder or defaulting to a JSON-decoding retransmitter.
84
84
  handler = worker_pool_stream_handler(broadcasting, callback || block, coder: coder)
85
- streams << [ broadcasting, handler ]
85
+ streams[broadcasting] = handler
86
86
 
87
87
  connection.server.event_loop.post do
88
88
  pubsub.subscribe(broadcasting, handler, lambda do
@@ -102,6 +102,20 @@ module ActionCable
102
102
  stream_from(broadcasting_for(model), callback || block, coder: coder)
103
103
  end
104
104
 
105
+ # Unsubscribes streams from the named <tt>broadcasting</tt>.
106
+ def stop_stream_from(broadcasting)
107
+ callback = streams.delete(broadcasting)
108
+ if callback
109
+ pubsub.unsubscribe(broadcasting, callback)
110
+ logger.info "#{self.class.name} stopped streaming from #{broadcasting}"
111
+ end
112
+ end
113
+
114
+ # Unsubscribes streams for the <tt>model</tt>.
115
+ def stop_stream_for(model)
116
+ stop_stream_from(broadcasting_for(model))
117
+ end
118
+
105
119
  # Unsubscribes all streams associated with this channel from the pubsub queue.
106
120
  def stop_all_streams
107
121
  streams.each do |broadcasting, callback|
@@ -110,11 +124,23 @@ module ActionCable
110
124
  end.clear
111
125
  end
112
126
 
127
+ # Calls stream_for if record is present, otherwise calls reject.
128
+ # This method is intended to be called when you're looking
129
+ # for a record based on a parameter, if its found it will start
130
+ # streaming. If the record is nil then it will reject the connection.
131
+ def stream_or_reject_for(record)
132
+ if record
133
+ stream_for record
134
+ else
135
+ reject
136
+ end
137
+ end
138
+
113
139
  private
114
140
  delegate :pubsub, to: :connection
115
141
 
116
142
  def streams
117
- @_streams ||= []
143
+ @_streams ||= {}
118
144
  end
119
145
 
120
146
  # Always wrap the outermost handler to invoke the user handler on the
@@ -15,9 +15,9 @@ module ActionCable
15
15
  end
16
16
  end
17
17
 
18
- # Stub `stream_from` to track streams for the channel.
19
- # Add public aliases for `subscription_confirmation_sent?` and
20
- # `subscription_rejected?`.
18
+ # Stub +stream_from+ to track streams for the channel.
19
+ # Add public aliases for +subscription_confirmation_sent?+ and
20
+ # +subscription_rejected?+.
21
21
  module ChannelStub
22
22
  def confirmed?
23
23
  subscription_confirmation_sent?
@@ -123,7 +123,7 @@ module ActionCable
123
123
  # <b>connection</b>::
124
124
  # An ActionCable::Channel::ConnectionStub, representing the current HTTP connection.
125
125
  # <b>subscription</b>::
126
- # An instance of the current channel, created when you call `subscribe`.
126
+ # An instance of the current channel, created when you call +subscribe+.
127
127
  # <b>transmissions</b>::
128
128
  # A list of all messages that have been transmitted into the channel.
129
129
  #
@@ -159,7 +159,7 @@ module ActionCable
159
159
  # def test_speak
160
160
  # subscribe room_id: rooms(:chat).id
161
161
  #
162
- # assert_broadcasts_on(rooms(:chat), text: "Hello, Rails!") do
162
+ # assert_broadcast_on(rooms(:chat), text: "Hello, Rails!") do
163
163
  # perform :speak, message: "Hello, Rails!"
164
164
  # end
165
165
  # end
@@ -209,7 +209,7 @@ module ActionCable
209
209
  end
210
210
  end
211
211
 
212
- # Setup test connection with the specified identifiers:
212
+ # Set up test connection with the specified identifiers:
213
213
  #
214
214
  # class ApplicationCable < ActionCable::Connection::Base
215
215
  # identified_by :user, :token
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "action_dispatch"
4
+ require "active_support/rescuable"
4
5
 
5
6
  module ActionCable
6
7
  module Connection
@@ -46,6 +47,7 @@ module ActionCable
46
47
  include Identification
47
48
  include InternalChannel
48
49
  include Authorization
50
+ include ActiveSupport::Rescuable
49
51
 
50
52
  attr_reader :server, :env, :subscriptions, :logger, :worker_pool, :protocol
51
53
  delegate :event_loop, :pubsub, to: :server
@@ -21,6 +21,7 @@ module ActionCable
21
21
  logger.error "Received unrecognized command in #{data.inspect}"
22
22
  end
23
23
  rescue Exception => e
24
+ @connection.rescue_with_handler(e)
24
25
  logger.error "Could not execute command from (#{data.inspect}) [#{e.class} - #{e.message}]: #{e.backtrace.first(5).join(" | ")}"
25
26
  end
26
27
 
@@ -85,7 +85,7 @@ module ActionCable
85
85
  # end
86
86
  # end
87
87
  #
88
- # +connect+ accepts additional information the HTTP request with the
88
+ # +connect+ accepts additional information about the HTTP request with the
89
89
  # +params+, +headers+, +session+ and Rack +env+ options.
90
90
  #
91
91
  # def test_connect_with_headers_and_query_string
@@ -101,7 +101,7 @@ module ActionCable
101
101
  # assert_equal "1", connection.user.id
102
102
  # end
103
103
  #
104
- # You can also setup the correct cookies before the connection request:
104
+ # You can also set up the correct cookies before the connection request:
105
105
  #
106
106
  # def test_connect_with_cookies
107
107
  # # Plain cookies:
@@ -30,7 +30,7 @@ module ActionCable
30
30
 
31
31
  ActiveSupport.on_load(:action_cable) do
32
32
  if (config_path = Pathname.new(app.config.paths["config/cable"].first)).exist?
33
- self.cable = Rails.application.config_for(config_path).with_indifferent_access
33
+ self.cable = Rails.application.config_for(config_path).to_h.with_indifferent_access
34
34
  end
35
35
 
36
36
  previous_connection_class = connection_class
@@ -8,9 +8,9 @@ module ActionCable
8
8
 
9
9
  module VERSION
10
10
  MAJOR = 6
11
- MINOR = 0
12
- TINY = 6
13
- PRE = "1"
11
+ MINOR = 1
12
+ TINY = 7
13
+ PRE = "6"
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
16
  end
@@ -12,11 +12,11 @@ module ActionCable
12
12
  # </head>
13
13
  #
14
14
  # This is then used by Action Cable to determine the URL of your WebSocket server.
15
- # Your CoffeeScript can then connect to the server without needing to specify the
15
+ # Your JavaScript can then connect to the server without needing to specify the
16
16
  # URL directly:
17
17
  #
18
- # #= require cable
19
- # @App = {}
18
+ # window.Cable = require("@rails/actioncable")
19
+ # window.App = {}
20
20
  # App.cable = Cable.createConsumer()
21
21
  #
22
22
  # Make sure to specify the correct server location in each of your environment
@@ -45,7 +45,7 @@ module ActionCable
45
45
 
46
46
  # Uses the internal channel to disconnect the connection.
47
47
  def disconnect
48
- server.broadcast internal_channel, type: "disconnect"
48
+ server.broadcast internal_channel, { type: "disconnect" }
49
49
  end
50
50
 
51
51
  # Returns all the identifiers that were applied to this connection.
@@ -27,7 +27,7 @@ module ActionCable
27
27
  @remote_connections = @event_loop = @worker_pool = @pubsub = nil
28
28
  end
29
29
 
30
- # Called by Rack to setup the server.
30
+ # Called by Rack to set up the server.
31
31
  def call(env)
32
32
  setup_heartbeat_timer
33
33
  config.connection_class.call.new(self, env).process
@@ -40,7 +40,7 @@ module ActionCable
40
40
  end
41
41
 
42
42
  def broadcast(message)
43
- server.logger.debug "[ActionCable] Broadcasting to #{broadcasting}: #{message.inspect}"
43
+ server.logger.debug { "[ActionCable] Broadcasting to #{broadcasting}: #{message.inspect.truncate(300)}" }
44
44
 
45
45
  payload = { broadcasting: broadcasting, message: message, coder: coder }
46
46
  ActiveSupport::Notifications.instrument("broadcast.action_cable", payload) do
@@ -2,6 +2,7 @@
2
2
 
3
3
  require "active_support/callbacks"
4
4
  require "active_support/core_ext/module/attribute_accessors_per_thread"
5
+ require "action_cable/server/worker/active_record_connection_management"
5
6
  require "concurrent"
6
7
 
7
8
  module ActionCable
@@ -11,7 +11,6 @@ module ActionCable
11
11
  autoload :Configuration
12
12
 
13
13
  autoload :Worker
14
- autoload :ActiveRecordConnectionManagement, "action_cable/server/worker/active_record_connection_management"
15
14
  end
16
15
  end
17
16
  end
@@ -25,6 +25,10 @@ module ActionCable
25
25
  def shutdown
26
26
  raise NotImplementedError
27
27
  end
28
+
29
+ def identifier
30
+ @server.config.cable[:id] ||= "ActionCable-PID-#{$$}"
31
+ end
28
32
  end
29
33
  end
30
34
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- gem "pg", ">= 0.18", "< 2.0"
3
+ gem "pg", "~> 1.1"
4
4
  require "pg"
5
5
  require "thread"
6
6
  require "digest/sha1"
@@ -42,6 +42,7 @@ module ActionCable
42
42
  pg_conn = ar_conn.raw_connection
43
43
 
44
44
  verify!(pg_conn)
45
+ pg_conn.exec("SET application_name = #{pg_conn.escape_identifier(identifier)}")
45
46
  yield pg_conn
46
47
  ensure
47
48
  ar_conn.disconnect!
@@ -15,7 +15,6 @@ module ActionCable
15
15
  # Overwrite this factory method for Redis connections if you want to use a different Redis library than the redis gem.
16
16
  # This is needed, for example, when using Makara proxies for distributed Redis.
17
17
  cattr_accessor :redis_connector, default: ->(config) do
18
- config[:id] ||= "ActionCable-PID-#{$$}"
19
18
  ::Redis.new(config.except(:adapter, :channel_prefix))
20
19
  end
21
20
 
@@ -57,7 +56,7 @@ module ActionCable
57
56
  end
58
57
 
59
58
  def redis_connection
60
- self.class.redis_connector.call(@server.config.cable)
59
+ self.class.redis_connector.call(@server.config.cable.merge(id: identifier))
61
60
  end
62
61
 
63
62
  class Listener < SubscriberMap
@@ -42,10 +42,10 @@ module ActionCable
42
42
  # end
43
43
  # end
44
44
  #
45
- def assert_broadcasts(stream, number)
45
+ def assert_broadcasts(stream, number, &block)
46
46
  if block_given?
47
47
  original_count = broadcasts_size(stream)
48
- yield
48
+ assert_nothing_raised(&block)
49
49
  new_count = broadcasts_size(stream)
50
50
  actual_count = new_count - original_count
51
51
  else
@@ -94,7 +94,7 @@ module ActionCable
94
94
  # end
95
95
  # end
96
96
  #
97
- def assert_broadcast_on(stream, data)
97
+ def assert_broadcast_on(stream, data, &block)
98
98
  # Encode to JSON and back–we want to use this value to compare
99
99
  # with decoded JSON.
100
100
  # Comparing JSON strings doesn't work due to the order if the keys.
@@ -106,7 +106,7 @@ module ActionCable
106
106
  old_messages = new_messages
107
107
  clear_messages(stream)
108
108
 
109
- yield
109
+ assert_nothing_raised(&block)
110
110
  new_messages = broadcasts(stream)
111
111
  clear_messages(stream)
112
112
 
data/lib/action_cable.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #--
4
- # Copyright (c) 2015-2019 Basecamp, LLC
4
+ # Copyright (c) 2015-2022 Basecamp, LLC
5
5
  #
6
6
  # Permission is hereby granted, free of charge, to any person obtaining
7
7
  # a copy of this software and associated documentation files (the
@@ -1,11 +1,11 @@
1
1
  Description:
2
2
  ============
3
- Stubs out a new cable channel for the server (in Ruby) and client (in JavaScript).
3
+ Generates a new cable channel for the server (in Ruby) and client (in JavaScript).
4
4
  Pass the channel name, either CamelCased or under_scored, and an optional list of channel actions as arguments.
5
5
 
6
6
  Example:
7
7
  ========
8
- rails generate channel Chat speak
8
+ bin/rails generate channel Chat speak
9
9
 
10
10
  creates a Chat channel class, test and JavaScript asset:
11
11
  Channel: app/channels/chat_channel.rb
@@ -1,5 +1,5 @@
1
1
  // Action Cable provides the framework to deal with WebSockets in Rails.
2
- // You can generate new channels where WebSocket features live using the `rails generate channel` command.
2
+ // You can generate new channels where WebSocket features live using the `bin/rails generate channel` command.
3
3
 
4
4
  import { createConsumer } from "@rails/actioncable"
5
5
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: actioncable
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.0.6.1
4
+ version: 6.1.7.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Pratik Naik
@@ -9,22 +9,36 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2023-01-17 00:00:00.000000000 Z
12
+ date: 2023-08-22 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activesupport
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - '='
19
+ - !ruby/object:Gem::Version
20
+ version: 6.1.7.6
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - '='
26
+ - !ruby/object:Gem::Version
27
+ version: 6.1.7.6
14
28
  - !ruby/object:Gem::Dependency
15
29
  name: actionpack
16
30
  requirement: !ruby/object:Gem::Requirement
17
31
  requirements:
18
32
  - - '='
19
33
  - !ruby/object:Gem::Version
20
- version: 6.0.6.1
34
+ version: 6.1.7.6
21
35
  type: :runtime
22
36
  prerelease: false
23
37
  version_requirements: !ruby/object:Gem::Requirement
24
38
  requirements:
25
39
  - - '='
26
40
  - !ruby/object:Gem::Version
27
- version: 6.0.6.1
41
+ version: 6.1.7.6
28
42
  - !ruby/object:Gem::Dependency
29
43
  name: nio4r
30
44
  requirement: !ruby/object:Gem::Requirement
@@ -126,10 +140,10 @@ licenses:
126
140
  - MIT
127
141
  metadata:
128
142
  bug_tracker_uri: https://github.com/rails/rails/issues
129
- changelog_uri: https://github.com/rails/rails/blob/v6.0.6.1/actioncable/CHANGELOG.md
130
- documentation_uri: https://api.rubyonrails.org/v6.0.6.1/
143
+ changelog_uri: https://github.com/rails/rails/blob/v6.1.7.6/actioncable/CHANGELOG.md
144
+ documentation_uri: https://api.rubyonrails.org/v6.1.7.6/
131
145
  mailing_list_uri: https://discuss.rubyonrails.org/c/rubyonrails-talk
132
- source_code_uri: https://github.com/rails/rails/tree/v6.0.6.1/actioncable
146
+ source_code_uri: https://github.com/rails/rails/tree/v6.1.7.6/actioncable
133
147
  rubygems_mfa_required: 'true'
134
148
  post_install_message:
135
149
  rdoc_options: []
@@ -146,7 +160,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
146
160
  - !ruby/object:Gem::Version
147
161
  version: '0'
148
162
  requirements: []
149
- rubygems_version: 3.4.3
163
+ rubygems_version: 3.3.3
150
164
  signing_key:
151
165
  specification_version: 4
152
166
  summary: WebSocket framework for Rails.