actioncable 7.0.8.7 → 7.2.2.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.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +34 -180
  3. data/MIT-LICENSE +1 -1
  4. data/README.md +4 -4
  5. data/app/assets/javascripts/action_cable.js +30 -9
  6. data/app/assets/javascripts/actioncable.esm.js +30 -9
  7. data/app/assets/javascripts/actioncable.js +30 -9
  8. data/lib/action_cable/channel/base.rb +114 -90
  9. data/lib/action_cable/channel/broadcasting.rb +25 -16
  10. data/lib/action_cable/channel/callbacks.rb +39 -0
  11. data/lib/action_cable/channel/naming.rb +10 -7
  12. data/lib/action_cable/channel/periodic_timers.rb +7 -7
  13. data/lib/action_cable/channel/streams.rb +77 -62
  14. data/lib/action_cable/channel/test_case.rb +117 -86
  15. data/lib/action_cable/connection/authorization.rb +4 -1
  16. data/lib/action_cable/connection/base.rb +70 -42
  17. data/lib/action_cable/connection/callbacks.rb +57 -0
  18. data/lib/action_cable/connection/client_socket.rb +3 -1
  19. data/lib/action_cable/connection/identification.rb +9 -5
  20. data/lib/action_cable/connection/internal_channel.rb +7 -2
  21. data/lib/action_cable/connection/message_buffer.rb +4 -1
  22. data/lib/action_cable/connection/stream.rb +2 -2
  23. data/lib/action_cable/connection/stream_event_loop.rb +4 -4
  24. data/lib/action_cable/connection/subscriptions.rb +7 -2
  25. data/lib/action_cable/connection/tagged_logger_proxy.rb +12 -7
  26. data/lib/action_cable/connection/test_case.rb +67 -55
  27. data/lib/action_cable/connection/web_socket.rb +11 -7
  28. data/lib/action_cable/deprecator.rb +9 -0
  29. data/lib/action_cable/engine.rb +18 -8
  30. data/lib/action_cable/gem_version.rb +6 -4
  31. data/lib/action_cable/helpers/action_cable_helper.rb +21 -19
  32. data/lib/action_cable/remote_connections.rb +25 -13
  33. data/lib/action_cable/server/base.rb +29 -14
  34. data/lib/action_cable/server/broadcasting.rb +24 -16
  35. data/lib/action_cable/server/configuration.rb +27 -14
  36. data/lib/action_cable/server/connections.rb +13 -5
  37. data/lib/action_cable/server/worker/active_record_connection_management.rb +2 -0
  38. data/lib/action_cable/server/worker.rb +4 -3
  39. data/lib/action_cable/subscription_adapter/async.rb +1 -1
  40. data/lib/action_cable/subscription_adapter/base.rb +2 -0
  41. data/lib/action_cable/subscription_adapter/channel_prefix.rb +2 -0
  42. data/lib/action_cable/subscription_adapter/inline.rb +2 -0
  43. data/lib/action_cable/subscription_adapter/postgresql.rb +4 -3
  44. data/lib/action_cable/subscription_adapter/redis.rb +7 -7
  45. data/lib/action_cable/subscription_adapter/subscriber_map.rb +2 -0
  46. data/lib/action_cable/subscription_adapter/test.rb +6 -5
  47. data/lib/action_cable/test_case.rb +2 -0
  48. data/lib/action_cable/test_helper.rb +89 -59
  49. data/lib/action_cable/version.rb +3 -1
  50. data/lib/action_cable.rb +30 -12
  51. data/lib/rails/generators/channel/USAGE +14 -8
  52. data/lib/rails/generators/channel/channel_generator.rb +23 -7
  53. data/lib/rails/generators/test_unit/channel_generator.rb +2 -0
  54. metadata +27 -15
  55. data/lib/action_cable/channel.rb +0 -17
  56. data/lib/action_cable/connection.rb +0 -22
  57. data/lib/action_cable/server.rb +0 -16
  58. data/lib/action_cable/subscription_adapter.rb +0 -12
  59. /data/lib/rails/generators/channel/templates/application_cable/{channel.rb → channel.rb.tt} +0 -0
  60. /data/lib/rails/generators/channel/templates/application_cable/{connection.rb → connection.rb.tt} +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fa0a11a4b00865a2e2481e468e1f1a56b8b99c832346140a858f2b62ba11623c
4
- data.tar.gz: 01a1a32f910f093d4ee8c89342f99fae7b9fbdf8a20cb6ef17fe591976d46113
3
+ metadata.gz: 720238323d1411f0913bcc9b65ac89d955c4fc4e708bbab5b5dd1c0c47c4cf00
4
+ data.tar.gz: 10a5cd05102adeda05b151a39c40183bc55c2c55c2c63dca5a13d642fcf49f58
5
5
  SHA512:
6
- metadata.gz: b61ba77c56d8a85549ae61dbe2d696494aa9f45fe1a4444a4060285c773b6b6287ca2624451f79196145ec0180fa7814ec3ec4b378f02f5721255486e1c4db86
7
- data.tar.gz: d8b27954d769da5af3ab1eb6d6f19712df5efa35838d64e6a42d5f6bc9e1993bd14cc80bdfeb7bf9353b1d7437c53a8975b9c320f9117ffe71125f70284806c3
6
+ metadata.gz: '0639a73b1efc8078fe167814911d5694e76781f618ac7fe5bb34ae8448ab495b60f598a76c6a0e8d7c9f45d9674d19564ad14eaae0ccaaf1f75b441d1318d7c8'
7
+ data.tar.gz: 4988a92b2c683bc86c28d60be1d2f92d1efe36bc5d33f814da55ac7328af60597fb0313321aa663b6d5632ecd565661725d12bf1238fa48a153b18d538e6e08e
data/CHANGELOG.md CHANGED
@@ -1,214 +1,68 @@
1
- ## Rails 7.0.8.7 (December 10, 2024) ##
1
+ ## Rails 7.2.2.1 (December 10, 2024) ##
2
2
 
3
3
  * No changes.
4
4
 
5
5
 
6
- ## Rails 7.0.8.6 (October 23, 2024) ##
6
+ ## Rails 7.2.2 (October 30, 2024) ##
7
7
 
8
8
  * No changes.
9
9
 
10
10
 
11
- ## Rails 7.0.8.5 (October 15, 2024) ##
11
+ ## Rails 7.2.1.2 (October 23, 2024) ##
12
12
 
13
13
  * No changes.
14
14
 
15
15
 
16
- ## Rails 7.0.8.4 (June 04, 2024) ##
16
+ ## Rails 7.2.1.1 (October 15, 2024) ##
17
17
 
18
18
  * No changes.
19
19
 
20
20
 
21
- ## Rails 7.0.8.3 (May 17, 2024) ##
21
+ ## Rails 7.2.1 (August 22, 2024) ##
22
22
 
23
23
  * No changes.
24
24
 
25
25
 
26
- ## Rails 7.0.8.2 (May 16, 2024) ##
26
+ ## Rails 7.2.0 (August 09, 2024) ##
27
27
 
28
- * No changes.
29
-
30
-
31
- ## Rails 7.0.8.1 (February 21, 2024) ##
32
-
33
- * No changes.
34
-
35
-
36
- ## Rails 7.0.8 (September 09, 2023) ##
37
-
38
- * No changes.
39
-
40
-
41
- ## Rails 7.0.7.2 (August 22, 2023) ##
42
-
43
- * No changes.
44
-
45
-
46
- ## Rails 7.0.7.1 (August 22, 2023) ##
47
-
48
- * No changes.
49
-
50
-
51
- ## Rails 7.0.7 (August 09, 2023) ##
52
-
53
- * No changes.
54
-
55
-
56
- ## Rails 7.0.6 (June 29, 2023) ##
57
-
58
- * Fix Action Cable Redis configuration with sentinels.
59
-
60
- *Dmitriy Ivliev*
61
-
62
-
63
- ## Rails 7.0.5.1 (June 26, 2023) ##
64
-
65
- * No changes.
66
-
67
-
68
- ## Rails 7.0.5 (May 24, 2023) ##
69
-
70
- * Restore Action Cable Redis pub/sub listener on connection failure.
71
-
72
- *Vladimir Dementyev*
73
-
74
-
75
- ## Rails 7.0.4.3 (March 13, 2023) ##
76
-
77
- * No changes.
78
-
79
-
80
- ## Rails 7.0.4.2 (January 24, 2023) ##
81
-
82
- * No changes.
83
-
84
-
85
- ## Rails 7.0.4.1 (January 17, 2023) ##
86
-
87
- * No changes.
88
-
89
-
90
- ## Rails 7.0.4 (September 09, 2022) ##
91
-
92
- * The Redis adapter is now compatible with redis-rb 5.0
93
-
94
- Compatibility with redis-rb 3.x was dropped.
95
-
96
- *Jean Boussier*
97
-
98
- * The Action Cable server is now mounted with `anchor: true`.
99
-
100
- This means that routes that also start with `/cable` will no longer clash with Action Cable.
101
-
102
- *Alex Ghiculescu*
103
-
104
-
105
- ## Rails 7.0.3.1 (July 12, 2022) ##
106
-
107
- * No changes.
108
-
109
-
110
- ## Rails 7.0.3 (May 09, 2022) ##
111
-
112
- * No changes.
113
-
114
-
115
- ## Rails 7.0.2.4 (April 26, 2022) ##
116
-
117
- * No changes.
118
-
119
-
120
- ## Rails 7.0.2.3 (March 08, 2022) ##
121
-
122
- * No changes.
123
-
124
-
125
- ## Rails 7.0.2.2 (February 11, 2022) ##
126
-
127
- * No changes.
128
-
129
-
130
- ## Rails 7.0.2.1 (February 11, 2022) ##
131
-
132
- * No changes.
133
-
134
-
135
- ## Rails 7.0.2 (February 08, 2022) ##
136
-
137
- * No changes.
138
-
139
-
140
- ## Rails 7.0.1 (January 06, 2022) ##
141
-
142
- * No changes.
143
-
144
-
145
- ## Rails 7.0.0 (December 15, 2021) ##
146
-
147
- * No changes.
148
-
149
-
150
- ## Rails 7.0.0.rc3 (December 14, 2021) ##
151
-
152
- * No changes.
153
-
154
-
155
- ## Rails 7.0.0.rc2 (December 14, 2021) ##
156
-
157
- * No changes.
158
-
159
- ## Rails 7.0.0.rc1 (December 06, 2021) ##
160
-
161
- * The Action Cable client now ensures successful channel subscriptions:
162
-
163
- * The client maintains a set of pending subscriptions until either
164
- the server confirms the subscription or the channel is torn down.
165
- * Rectifies the race condition where an unsubscribe is rapidly followed
166
- by a subscribe (on the same channel identifier) and the requests are
167
- handled out of order by the ActionCable server, thereby ignoring the
168
- subscribe command.
169
-
170
- *Daniel Spinosa*
171
-
172
-
173
- ## Rails 7.0.0.alpha2 (September 15, 2021) ##
174
-
175
- * No changes.
176
-
177
-
178
- ## Rails 7.0.0.alpha1 (September 15, 2021) ##
179
-
180
- * Compile ESM package that can be used directly in the browser as actioncable.esm.js.
181
-
182
- *DHH*
28
+ * Bring `ActionCable::Connection::TestCookieJar` in alignment with `ActionDispatch::Cookies::CookieJar` in regards to setting the cookie value.
183
29
 
184
- * Move action_cable.js to actioncable.js to match naming convention used for other Rails frameworks, and use JS console to communicate the deprecation.
30
+ Before:
185
31
 
186
- *DHH*
32
+ ```ruby
33
+ cookies[:foo] = { value: "bar" }
34
+ puts cookies[:foo] # => { value: "bar" }
35
+ ```
187
36
 
188
- * Stop transpiling the UMD package generated as actioncable.js and drop the IE11 testing that relied on that.
37
+ After:
189
38
 
190
- *DHH*
39
+ ```ruby
40
+ cookies[:foo] = { value: "bar" }
41
+ puts cookies[:foo] # => "bar"
42
+ ```
191
43
 
192
- * Truncate broadcast logging messages.
44
+ *Justin Ko*
193
45
 
194
- *J Smith*
46
+ * Record ping on every Action Cable message.
195
47
 
196
- * OpenSSL constants are now used for Digest computations.
48
+ Previously only `ping` and `welcome` message types were keeping the connection active.
49
+ Now every Action Cable message updates the `pingedAt` value, preventing the connection
50
+ from being marked as stale.
197
51
 
198
- *Dirkjan Bussink*
52
+ *yauhenininjia*
199
53
 
200
- * The Action Cable client now includes safeguards to prevent a "thundering
201
- herd" of client reconnects after server connectivity loss:
54
+ * Add two new assertion methods for Action Cable test cases: `assert_has_no_stream`
55
+ and `assert_has_no_stream_for`.
202
56
 
203
- * The client will wait a random amount between 1x and 3x of the stale
204
- threshold after the server's last ping before making the first
205
- reconnection attempt.
206
- * Subsequent reconnection attempts now use exponential backoff instead of
207
- logarithmic backoff. To allow the delay between reconnection attempts to
208
- increase slowly at first, the default exponentiation base is < 2.
209
- * Random jitter is applied to each delay between reconnection attempts.
57
+ These methods can be used to assert that a stream has been stopped, e.g. via
58
+ `stop_stream` or `stop_stream_for`. They complement the already existing
59
+ `assert_has_stream` and `assert_has_stream_for` methods.
210
60
 
211
- *Jonathan Hefner*
61
+ ```ruby
62
+ assert_has_no_stream "messages"
63
+ assert_has_no_stream_for User.find(42)
64
+ ```
212
65
 
66
+ *Sebastian Pöll*, *Junichi Sato*
213
67
 
214
- Please check [6-1-stable](https://github.com/rails/rails/blob/6-1-stable/actioncable/CHANGELOG.md) for previous changes.
68
+ Please check [7-1-stable](https://github.com/rails/rails/blob/7-1-stable/actioncable/CHANGELOG.md) for previous changes.
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2015-2022 Basecamp, LLC
1
+ Copyright (c) 37signals 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
data/README.md CHANGED
@@ -1,13 +1,13 @@
1
- # Action Cable – Integrated WebSockets for Rails
1
+ # Action Cable – Integrated WebSockets for \Rails
2
2
 
3
- Action Cable seamlessly integrates WebSockets with the rest of your Rails application.
3
+ Action Cable seamlessly integrates WebSockets with the rest of your \Rails application.
4
4
  It allows for real-time features to be written in Ruby in the same style
5
- and form as the rest of your Rails application, while still being performant
5
+ and form as the rest of your \Rails application, while still being performant
6
6
  and scalable. It's a full-stack offering that provides both a client-side
7
7
  JavaScript framework and a server-side Ruby framework. You have access to your full
8
8
  domain model written with Active Record or your ORM of choice.
9
9
 
10
- You can read more about Action Cable in the [Action Cable Overview](https://edgeguides.rubyonrails.org/action_cable_overview.html) guide.
10
+ You can read more about Action Cable in the [Action Cable Overview](https://guides.rubyonrails.org/action_cable_overview.html) guide.
11
11
 
12
12
  ## Support
13
13
 
@@ -4,8 +4,8 @@
4
4
  })(this, (function(exports) {
5
5
  "use strict";
6
6
  var adapters = {
7
- logger: self.console,
8
- WebSocket: self.WebSocket
7
+ logger: typeof console !== "undefined" ? console : undefined,
8
+ WebSocket: typeof WebSocket !== "undefined" ? WebSocket : undefined
9
9
  };
10
10
  var logger = {
11
11
  log(...messages) {
@@ -43,12 +43,11 @@
43
43
  isRunning() {
44
44
  return this.startedAt && !this.stoppedAt;
45
45
  }
46
- recordPing() {
46
+ recordMessage() {
47
47
  this.pingedAt = now();
48
48
  }
49
49
  recordConnect() {
50
50
  this.reconnectAttempts = 0;
51
- this.recordPing();
52
51
  delete this.disconnectedAt;
53
52
  logger.log("ConnectionMonitor recorded connect");
54
53
  }
@@ -121,7 +120,8 @@
121
120
  disconnect_reasons: {
122
121
  unauthorized: "unauthorized",
123
122
  invalid_request: "invalid_request",
124
- server_restart: "server_restart"
123
+ server_restart: "server_restart",
124
+ remote: "remote"
125
125
  },
126
126
  default_mount_path: "/cable",
127
127
  protocols: [ "actioncable-v1-json", "actioncable-unsupported" ]
@@ -150,11 +150,12 @@
150
150
  logger.log(`Attempted to open WebSocket, but existing socket is ${this.getState()}`);
151
151
  return false;
152
152
  } else {
153
- logger.log(`Opening WebSocket, current state is ${this.getState()}, subprotocols: ${protocols}`);
153
+ const socketProtocols = [ ...protocols, ...this.consumer.subprotocols || [] ];
154
+ logger.log(`Opening WebSocket, current state is ${this.getState()}, subprotocols: ${socketProtocols}`);
154
155
  if (this.webSocket) {
155
156
  this.uninstallEventHandlers();
156
157
  }
157
- this.webSocket = new adapters.WebSocket(this.consumer.url, protocols);
158
+ this.webSocket = new adapters.WebSocket(this.consumer.url, socketProtocols);
158
159
  this.installEventHandlers();
159
160
  this.monitor.start();
160
161
  return true;
@@ -196,6 +197,9 @@
196
197
  isActive() {
197
198
  return this.isState("open", "connecting");
198
199
  }
200
+ triedToReconnect() {
201
+ return this.monitor.reconnectAttempts > 0;
202
+ }
199
203
  isProtocolSupported() {
200
204
  return indexOf.call(supportedProtocols, this.getProtocol()) >= 0;
201
205
  }
@@ -231,8 +235,12 @@
231
235
  return;
232
236
  }
233
237
  const {identifier: identifier, message: message, reason: reason, reconnect: reconnect, type: type} = JSON.parse(event.data);
238
+ this.monitor.recordMessage();
234
239
  switch (type) {
235
240
  case message_types.welcome:
241
+ if (this.triedToReconnect()) {
242
+ this.reconnectAttempted = true;
243
+ }
236
244
  this.monitor.recordConnect();
237
245
  return this.subscriptions.reload();
238
246
 
@@ -243,11 +251,20 @@
243
251
  });
244
252
 
245
253
  case message_types.ping:
246
- return this.monitor.recordPing();
254
+ return null;
247
255
 
248
256
  case message_types.confirmation:
249
257
  this.subscriptions.confirmSubscription(identifier);
250
- return this.subscriptions.notify(identifier, "connected");
258
+ if (this.reconnectAttempted) {
259
+ this.reconnectAttempted = false;
260
+ return this.subscriptions.notify(identifier, "connected", {
261
+ reconnected: true
262
+ });
263
+ } else {
264
+ return this.subscriptions.notify(identifier, "connected", {
265
+ reconnected: false
266
+ });
267
+ }
251
268
 
252
269
  case message_types.rejection:
253
270
  return this.subscriptions.reject(identifier);
@@ -427,6 +444,7 @@
427
444
  this._url = url;
428
445
  this.subscriptions = new Subscriptions(this);
429
446
  this.connection = new Connection(this);
447
+ this.subprotocols = [];
430
448
  }
431
449
  get url() {
432
450
  return createWebSocketURL(this._url);
@@ -447,6 +465,9 @@
447
465
  return this.connection.open();
448
466
  }
449
467
  }
468
+ addSubProtocol(subprotocol) {
469
+ this.subprotocols = [ ...this.subprotocols, subprotocol ];
470
+ }
450
471
  }
451
472
  function createWebSocketURL(url) {
452
473
  if (typeof url === "function") {
@@ -1,6 +1,6 @@
1
1
  var adapters = {
2
- logger: self.console,
3
- WebSocket: self.WebSocket
2
+ logger: typeof console !== "undefined" ? console : undefined,
3
+ WebSocket: typeof WebSocket !== "undefined" ? WebSocket : undefined
4
4
  };
5
5
 
6
6
  var logger = {
@@ -42,12 +42,11 @@ class ConnectionMonitor {
42
42
  isRunning() {
43
43
  return this.startedAt && !this.stoppedAt;
44
44
  }
45
- recordPing() {
45
+ recordMessage() {
46
46
  this.pingedAt = now();
47
47
  }
48
48
  recordConnect() {
49
49
  this.reconnectAttempts = 0;
50
- this.recordPing();
51
50
  delete this.disconnectedAt;
52
51
  logger.log("ConnectionMonitor recorded connect");
53
52
  }
@@ -123,7 +122,8 @@ var INTERNAL = {
123
122
  disconnect_reasons: {
124
123
  unauthorized: "unauthorized",
125
124
  invalid_request: "invalid_request",
126
- server_restart: "server_restart"
125
+ server_restart: "server_restart",
126
+ remote: "remote"
127
127
  },
128
128
  default_mount_path: "/cable",
129
129
  protocols: [ "actioncable-v1-json", "actioncable-unsupported" ]
@@ -156,11 +156,12 @@ class Connection {
156
156
  logger.log(`Attempted to open WebSocket, but existing socket is ${this.getState()}`);
157
157
  return false;
158
158
  } else {
159
- logger.log(`Opening WebSocket, current state is ${this.getState()}, subprotocols: ${protocols}`);
159
+ const socketProtocols = [ ...protocols, ...this.consumer.subprotocols || [] ];
160
+ logger.log(`Opening WebSocket, current state is ${this.getState()}, subprotocols: ${socketProtocols}`);
160
161
  if (this.webSocket) {
161
162
  this.uninstallEventHandlers();
162
163
  }
163
- this.webSocket = new adapters.WebSocket(this.consumer.url, protocols);
164
+ this.webSocket = new adapters.WebSocket(this.consumer.url, socketProtocols);
164
165
  this.installEventHandlers();
165
166
  this.monitor.start();
166
167
  return true;
@@ -202,6 +203,9 @@ class Connection {
202
203
  isActive() {
203
204
  return this.isState("open", "connecting");
204
205
  }
206
+ triedToReconnect() {
207
+ return this.monitor.reconnectAttempts > 0;
208
+ }
205
209
  isProtocolSupported() {
206
210
  return indexOf.call(supportedProtocols, this.getProtocol()) >= 0;
207
211
  }
@@ -239,8 +243,12 @@ Connection.prototype.events = {
239
243
  return;
240
244
  }
241
245
  const {identifier: identifier, message: message, reason: reason, reconnect: reconnect, type: type} = JSON.parse(event.data);
246
+ this.monitor.recordMessage();
242
247
  switch (type) {
243
248
  case message_types.welcome:
249
+ if (this.triedToReconnect()) {
250
+ this.reconnectAttempted = true;
251
+ }
244
252
  this.monitor.recordConnect();
245
253
  return this.subscriptions.reload();
246
254
 
@@ -251,11 +259,20 @@ Connection.prototype.events = {
251
259
  });
252
260
 
253
261
  case message_types.ping:
254
- return this.monitor.recordPing();
262
+ return null;
255
263
 
256
264
  case message_types.confirmation:
257
265
  this.subscriptions.confirmSubscription(identifier);
258
- return this.subscriptions.notify(identifier, "connected");
266
+ if (this.reconnectAttempted) {
267
+ this.reconnectAttempted = false;
268
+ return this.subscriptions.notify(identifier, "connected", {
269
+ reconnected: true
270
+ });
271
+ } else {
272
+ return this.subscriptions.notify(identifier, "connected", {
273
+ reconnected: false
274
+ });
275
+ }
259
276
 
260
277
  case message_types.rejection:
261
278
  return this.subscriptions.reject(identifier);
@@ -440,6 +457,7 @@ class Consumer {
440
457
  this._url = url;
441
458
  this.subscriptions = new Subscriptions(this);
442
459
  this.connection = new Connection(this);
460
+ this.subprotocols = [];
443
461
  }
444
462
  get url() {
445
463
  return createWebSocketURL(this._url);
@@ -460,6 +478,9 @@ class Consumer {
460
478
  return this.connection.open();
461
479
  }
462
480
  }
481
+ addSubProtocol(subprotocol) {
482
+ this.subprotocols = [ ...this.subprotocols, subprotocol ];
483
+ }
463
484
  }
464
485
 
465
486
  function createWebSocketURL(url) {
@@ -4,8 +4,8 @@
4
4
  })(this, (function(exports) {
5
5
  "use strict";
6
6
  var adapters = {
7
- logger: self.console,
8
- WebSocket: self.WebSocket
7
+ logger: typeof console !== "undefined" ? console : undefined,
8
+ WebSocket: typeof WebSocket !== "undefined" ? WebSocket : undefined
9
9
  };
10
10
  var logger = {
11
11
  log(...messages) {
@@ -43,12 +43,11 @@
43
43
  isRunning() {
44
44
  return this.startedAt && !this.stoppedAt;
45
45
  }
46
- recordPing() {
46
+ recordMessage() {
47
47
  this.pingedAt = now();
48
48
  }
49
49
  recordConnect() {
50
50
  this.reconnectAttempts = 0;
51
- this.recordPing();
52
51
  delete this.disconnectedAt;
53
52
  logger.log("ConnectionMonitor recorded connect");
54
53
  }
@@ -121,7 +120,8 @@
121
120
  disconnect_reasons: {
122
121
  unauthorized: "unauthorized",
123
122
  invalid_request: "invalid_request",
124
- server_restart: "server_restart"
123
+ server_restart: "server_restart",
124
+ remote: "remote"
125
125
  },
126
126
  default_mount_path: "/cable",
127
127
  protocols: [ "actioncable-v1-json", "actioncable-unsupported" ]
@@ -150,11 +150,12 @@
150
150
  logger.log(`Attempted to open WebSocket, but existing socket is ${this.getState()}`);
151
151
  return false;
152
152
  } else {
153
- logger.log(`Opening WebSocket, current state is ${this.getState()}, subprotocols: ${protocols}`);
153
+ const socketProtocols = [ ...protocols, ...this.consumer.subprotocols || [] ];
154
+ logger.log(`Opening WebSocket, current state is ${this.getState()}, subprotocols: ${socketProtocols}`);
154
155
  if (this.webSocket) {
155
156
  this.uninstallEventHandlers();
156
157
  }
157
- this.webSocket = new adapters.WebSocket(this.consumer.url, protocols);
158
+ this.webSocket = new adapters.WebSocket(this.consumer.url, socketProtocols);
158
159
  this.installEventHandlers();
159
160
  this.monitor.start();
160
161
  return true;
@@ -196,6 +197,9 @@
196
197
  isActive() {
197
198
  return this.isState("open", "connecting");
198
199
  }
200
+ triedToReconnect() {
201
+ return this.monitor.reconnectAttempts > 0;
202
+ }
199
203
  isProtocolSupported() {
200
204
  return indexOf.call(supportedProtocols, this.getProtocol()) >= 0;
201
205
  }
@@ -231,8 +235,12 @@
231
235
  return;
232
236
  }
233
237
  const {identifier: identifier, message: message, reason: reason, reconnect: reconnect, type: type} = JSON.parse(event.data);
238
+ this.monitor.recordMessage();
234
239
  switch (type) {
235
240
  case message_types.welcome:
241
+ if (this.triedToReconnect()) {
242
+ this.reconnectAttempted = true;
243
+ }
236
244
  this.monitor.recordConnect();
237
245
  return this.subscriptions.reload();
238
246
 
@@ -243,11 +251,20 @@
243
251
  });
244
252
 
245
253
  case message_types.ping:
246
- return this.monitor.recordPing();
254
+ return null;
247
255
 
248
256
  case message_types.confirmation:
249
257
  this.subscriptions.confirmSubscription(identifier);
250
- return this.subscriptions.notify(identifier, "connected");
258
+ if (this.reconnectAttempted) {
259
+ this.reconnectAttempted = false;
260
+ return this.subscriptions.notify(identifier, "connected", {
261
+ reconnected: true
262
+ });
263
+ } else {
264
+ return this.subscriptions.notify(identifier, "connected", {
265
+ reconnected: false
266
+ });
267
+ }
251
268
 
252
269
  case message_types.rejection:
253
270
  return this.subscriptions.reject(identifier);
@@ -427,6 +444,7 @@
427
444
  this._url = url;
428
445
  this.subscriptions = new Subscriptions(this);
429
446
  this.connection = new Connection(this);
447
+ this.subprotocols = [];
430
448
  }
431
449
  get url() {
432
450
  return createWebSocketURL(this._url);
@@ -447,6 +465,9 @@
447
465
  return this.connection.open();
448
466
  }
449
467
  }
468
+ addSubProtocol(subprotocol) {
469
+ this.subprotocols = [ ...this.subprotocols, subprotocol ];
470
+ }
450
471
  }
451
472
  function createWebSocketURL(url) {
452
473
  if (typeof url === "function") {