actioncable 6.1.7.9 → 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 (59) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +33 -160
  3. data/MIT-LICENSE +1 -1
  4. data/README.md +5 -5
  5. data/app/assets/javascripts/action_cable.js +239 -302
  6. data/app/assets/javascripts/actioncable.esm.js +512 -0
  7. data/app/assets/javascripts/actioncable.js +510 -0
  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 +81 -68
  14. data/lib/action_cable/channel/test_case.rb +133 -87
  15. data/lib/action_cable/connection/authorization.rb +4 -1
  16. data/lib/action_cable/connection/base.rb +71 -43
  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 +10 -6
  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 +8 -3
  25. data/lib/action_cable/connection/tagged_logger_proxy.rb +14 -9
  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 +28 -9
  30. data/lib/action_cable/gem_version.rb +7 -5
  31. data/lib/action_cable/helpers/action_cable_helper.rb +21 -18
  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 +28 -14
  36. data/lib/action_cable/server/connections.rb +13 -5
  37. data/lib/action_cable/server/worker/active_record_connection_management.rb +4 -2
  38. data/lib/action_cable/server/worker.rb +7 -7
  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 +6 -5
  44. data/lib/action_cable/subscription_adapter/redis.rb +101 -25
  45. data/lib/action_cable/subscription_adapter/subscriber_map.rb +2 -0
  46. data/lib/action_cable/subscription_adapter/test.rb +7 -6
  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 +95 -20
  53. data/lib/rails/generators/channel/templates/javascript/index.js.tt +1 -5
  54. data/lib/rails/generators/test_unit/channel_generator.rb +2 -0
  55. metadata +29 -15
  56. data/lib/action_cable/channel.rb +0 -17
  57. data/lib/action_cable/connection.rb +0 -22
  58. data/lib/action_cable/server.rb +0 -16
  59. data/lib/action_cable/subscription_adapter.rb +0 -12
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "active_support"
4
6
  require "active_support/test_case"
5
7
  require "active_support/core_ext/hash/indifferent_access"
@@ -18,25 +20,33 @@ module ActionCable
18
20
  end
19
21
 
20
22
  module Assertions
21
- # Asserts that the connection is rejected (via +reject_unauthorized_connection+).
23
+ # Asserts that the connection is rejected (via
24
+ # `reject_unauthorized_connection`).
22
25
  #
23
- # # Asserts that connection without user_id fails
24
- # assert_reject_connection { connect params: { user_id: '' } }
26
+ # # Asserts that connection without user_id fails
27
+ # assert_reject_connection { connect params: { user_id: '' } }
25
28
  def assert_reject_connection(&block)
26
29
  assert_raises(Authorization::UnauthorizedError, "Expected to reject connection but no rejection was made", &block)
27
30
  end
28
31
  end
29
32
 
30
- # We don't want to use the whole "encryption stack" for connection
31
- # unit-tests, but we want to make sure that users test against the correct types
32
- # of cookies (i.e. signed or encrypted or plain)
33
- class TestCookieJar < ActiveSupport::HashWithIndifferentAccess
33
+ class TestCookies < ActiveSupport::HashWithIndifferentAccess # :nodoc:
34
+ def []=(name, options)
35
+ value = options.is_a?(Hash) ? options.symbolize_keys[:value] : options
36
+ super(name, value)
37
+ end
38
+ end
39
+
40
+ # We don't want to use the whole "encryption stack" for connection unit-tests,
41
+ # but we want to make sure that users test against the correct types of cookies
42
+ # (i.e. signed or encrypted or plain)
43
+ class TestCookieJar < TestCookies
34
44
  def signed
35
- self[:signed] ||= {}.with_indifferent_access
45
+ @signed ||= TestCookies.new
36
46
  end
37
47
 
38
48
  def encrypted
39
- self[:encrypted] ||= {}.with_indifferent_access
49
+ @encrypted ||= TestCookies.new
40
50
  end
41
51
  end
42
52
 
@@ -56,75 +66,77 @@ module ActionCable
56
66
  end
57
67
  end
58
68
 
69
+ # # Action Cable Connection TestCase
70
+ #
59
71
  # Unit test Action Cable connections.
60
72
  #
61
- # Useful to check whether a connection's +identified_by+ gets assigned properly
73
+ # Useful to check whether a connection's `identified_by` gets assigned properly
62
74
  # and that any improper connection requests are rejected.
63
75
  #
64
- # == Basic example
76
+ # ## Basic example
65
77
  #
66
78
  # Unit tests are written as follows:
67
79
  #
68
- # 1. Simulate a connection attempt by calling +connect+.
69
- # 2. Assert state, e.g. identifiers, has been assigned.
80
+ # 1. Simulate a connection attempt by calling `connect`.
81
+ # 2. Assert state, e.g. identifiers, has been assigned.
70
82
  #
71
83
  #
72
- # class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase
73
- # def test_connects_with_proper_cookie
74
- # # Simulate the connection request with a cookie.
75
- # cookies["user_id"] = users(:john).id
84
+ # class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase
85
+ # def test_connects_with_proper_cookie
86
+ # # Simulate the connection request with a cookie.
87
+ # cookies["user_id"] = users(:john).id
76
88
  #
77
- # connect
89
+ # connect
78
90
  #
79
- # # Assert the connection identifier matches the fixture.
80
- # assert_equal users(:john).id, connection.user.id
81
- # end
91
+ # # Assert the connection identifier matches the fixture.
92
+ # assert_equal users(:john).id, connection.user.id
93
+ # end
82
94
  #
83
- # def test_rejects_connection_without_proper_cookie
84
- # assert_reject_connection { connect }
95
+ # def test_rejects_connection_without_proper_cookie
96
+ # assert_reject_connection { connect }
97
+ # end
85
98
  # end
86
- # end
87
99
  #
88
- # +connect+ accepts additional information about the HTTP request with the
89
- # +params+, +headers+, +session+ and Rack +env+ options.
100
+ # `connect` accepts additional information about the HTTP request with the
101
+ # `params`, `headers`, `session`, and Rack `env` options.
90
102
  #
91
- # def test_connect_with_headers_and_query_string
92
- # connect params: { user_id: 1 }, headers: { "X-API-TOKEN" => "secret-my" }
103
+ # def test_connect_with_headers_and_query_string
104
+ # connect params: { user_id: 1 }, headers: { "X-API-TOKEN" => "secret-my" }
93
105
  #
94
- # assert_equal "1", connection.user.id
95
- # assert_equal "secret-my", connection.token
96
- # end
106
+ # assert_equal "1", connection.user.id
107
+ # assert_equal "secret-my", connection.token
108
+ # end
97
109
  #
98
- # def test_connect_with_params
99
- # connect params: { user_id: 1 }
110
+ # def test_connect_with_params
111
+ # connect params: { user_id: 1 }
100
112
  #
101
- # assert_equal "1", connection.user.id
102
- # end
113
+ # assert_equal "1", connection.user.id
114
+ # end
103
115
  #
104
116
  # You can also set up the correct cookies before the connection request:
105
117
  #
106
- # def test_connect_with_cookies
107
- # # Plain cookies:
108
- # cookies["user_id"] = 1
118
+ # def test_connect_with_cookies
119
+ # # Plain cookies:
120
+ # cookies["user_id"] = 1
109
121
  #
110
- # # Or signed/encrypted:
111
- # # cookies.signed["user_id"] = 1
112
- # # cookies.encrypted["user_id"] = 1
122
+ # # Or signed/encrypted:
123
+ # # cookies.signed["user_id"] = 1
124
+ # # cookies.encrypted["user_id"] = 1
113
125
  #
114
- # connect
126
+ # connect
115
127
  #
116
- # assert_equal "1", connection.user_id
117
- # end
128
+ # assert_equal "1", connection.user_id
129
+ # end
118
130
  #
119
- # == Connection is automatically inferred
131
+ # ## Connection is automatically inferred
120
132
  #
121
- # ActionCable::Connection::TestCase will automatically infer the connection under test
122
- # from the test class name. If the channel cannot be inferred from the test
123
- # class name, you can explicitly set it with +tests+.
133
+ # ActionCable::Connection::TestCase will automatically infer the connection
134
+ # under test from the test class name. If the channel cannot be inferred from
135
+ # the test class name, you can explicitly set it with `tests`.
124
136
  #
125
- # class ConnectionTest < ActionCable::Connection::TestCase
126
- # tests ApplicationCable::Connection
127
- # end
137
+ # class ConnectionTest < ActionCable::Connection::TestCase
138
+ # tests ApplicationCable::Connection
139
+ # end
128
140
  #
129
141
  class TestCase < ActiveSupport::TestCase
130
142
  module Behavior
@@ -176,10 +188,10 @@ module ActionCable
176
188
  #
177
189
  # Accepts request path as the first argument and the following request options:
178
190
  #
179
- # - params – URL parameters (Hash)
180
- # - headers – request headers (Hash)
181
- # - session – session data (Hash)
182
- # - env – additional Rack env configuration (Hash)
191
+ # * params – URL parameters (Hash)
192
+ # * headers – request headers (Hash)
193
+ # * session – session data (Hash)
194
+ # * env – additional Rack env configuration (Hash)
183
195
  def connect(path = ActionCable.server.config.mount_path, **request_params)
184
196
  path ||= DEFAULT_PATH
185
197
 
@@ -1,9 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "websocket/driver"
4
6
 
5
7
  module ActionCable
6
8
  module Connection
9
+ # # Action Cable Connection WebSocket
10
+ #
7
11
  # Wrap the real socket to minimize the externally-presented API
8
12
  class WebSocket # :nodoc:
9
13
  def initialize(env, event_target, event_loop, protocols: ActionCable::INTERNAL[:protocols])
@@ -15,23 +19,23 @@ module ActionCable
15
19
  end
16
20
 
17
21
  def alive?
18
- websocket && websocket.alive?
22
+ websocket&.alive?
19
23
  end
20
24
 
21
- def transmit(data)
22
- websocket.transmit data
25
+ def transmit(...)
26
+ websocket&.transmit(...)
23
27
  end
24
28
 
25
- def close
26
- websocket.close
29
+ def close(...)
30
+ websocket&.close(...)
27
31
  end
28
32
 
29
33
  def protocol
30
- websocket.protocol
34
+ websocket&.protocol
31
35
  end
32
36
 
33
37
  def rack_response
34
- websocket.rack_response
38
+ websocket&.rack_response
35
39
  end
36
40
 
37
41
  private
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ # :markup: markdown
4
+
5
+ module ActionCable
6
+ def self.deprecator # :nodoc:
7
+ @deprecator ||= ActiveSupport::Deprecation.new
8
+ end
9
+ end
@@ -1,16 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "rails"
4
6
  require "action_cable"
5
- require "action_cable/helpers/action_cable_helper"
6
7
  require "active_support/core_ext/hash/indifferent_access"
7
8
 
8
9
  module ActionCable
9
10
  class Engine < Rails::Engine # :nodoc:
10
11
  config.action_cable = ActiveSupport::OrderedOptions.new
11
12
  config.action_cable.mount_path = ActionCable::INTERNAL[:default_mount_path]
13
+ config.action_cable.precompile_assets = true
12
14
 
13
- config.eager_load_namespaces << ActionCable
15
+ initializer "action_cable.deprecator", before: :load_environment_config do |app|
16
+ app.deprecators[:action_cable] = ActionCable.deprecator
17
+ end
14
18
 
15
19
  initializer "action_cable.helpers" do
16
20
  ActiveSupport.on_load(:action_view) do
@@ -22,6 +26,20 @@ module ActionCable
22
26
  ActiveSupport.on_load(:action_cable) { self.logger ||= ::Rails.logger }
23
27
  end
24
28
 
29
+ initializer "action_cable.health_check_application" do
30
+ ActiveSupport.on_load(:action_cable) {
31
+ self.health_check_application = ->(env) { Rails::HealthController.action(:show).call(env) }
32
+ }
33
+ end
34
+
35
+ initializer "action_cable.asset" do
36
+ config.after_initialize do |app|
37
+ if app.config.respond_to?(:assets) && app.config.action_cable.precompile_assets
38
+ app.config.assets.precompile += %w( actioncable.js actioncable.esm.js )
39
+ end
40
+ end
41
+ end
42
+
25
43
  initializer "action_cable.set_configs" do |app|
26
44
  options = app.config.action_cable
27
45
  options.allowed_request_origins ||= /https?:\/\/localhost:\d+/ if ::Rails.env.development?
@@ -30,11 +48,12 @@ module ActionCable
30
48
 
31
49
  ActiveSupport.on_load(:action_cable) do
32
50
  if (config_path = Pathname.new(app.config.paths["config/cable"].first)).exist?
33
- self.cable = Rails.application.config_for(config_path).to_h.with_indifferent_access
51
+ self.cable = app.config_for(config_path).to_h.with_indifferent_access
34
52
  end
35
53
 
36
54
  previous_connection_class = connection_class
37
55
  self.connection_class = -> { "ApplicationCable::Connection".safe_constantize || previous_connection_class.call }
56
+ self.filter_parameters += app.config.filter_parameters
38
57
 
39
58
  options.each { |k, v| send("#{k}=", v) }
40
59
  end
@@ -45,7 +64,7 @@ module ActionCable
45
64
  config = app.config
46
65
  unless config.action_cable.mount_path.nil?
47
66
  app.routes.prepend do
48
- mount ActionCable.server => config.action_cable.mount_path, internal: true
67
+ mount ActionCable.server => config.action_cable.mount_path, internal: true, anchor: true
49
68
  end
50
69
  end
51
70
  end
@@ -54,10 +73,10 @@ module ActionCable
54
73
  initializer "action_cable.set_work_hooks" do |app|
55
74
  ActiveSupport.on_load(:action_cable) do
56
75
  ActionCable::Server::Worker.set_callback :work, :around, prepend: true do |_, inner|
57
- app.executor.wrap do
58
- # If we took a while to get the lock, we may have been halted
59
- # in the meantime. As we haven't started doing any real work
60
- # yet, we should pretend that we never made it off the queue.
76
+ app.executor.wrap(source: "application.action_cable") do
77
+ # If we took a while to get the lock, we may have been halted in the meantime.
78
+ # As we haven't started doing any real work yet, we should pretend that we never
79
+ # made it off the queue.
61
80
  unless stopping?
62
81
  inner.call
63
82
  end
@@ -65,7 +84,7 @@ module ActionCable
65
84
  end
66
85
 
67
86
  wrap = lambda do |_, inner|
68
- app.executor.wrap(&inner)
87
+ app.executor.wrap(source: "application.action_cable", &inner)
69
88
  end
70
89
  ActionCable::Channel::Base.set_callback :subscribe, :around, prepend: true, &wrap
71
90
  ActionCable::Channel::Base.set_callback :unsubscribe, :around, prepend: true, &wrap
@@ -1,16 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionCable
4
- # Returns the version of the currently loaded Action Cable as a <tt>Gem::Version</tt>.
6
+ # Returns the currently loaded version of Action Cable as a `Gem::Version`.
5
7
  def self.gem_version
6
8
  Gem::Version.new VERSION::STRING
7
9
  end
8
10
 
9
11
  module VERSION
10
- MAJOR = 6
11
- MINOR = 1
12
- TINY = 7
13
- PRE = "9"
12
+ MAJOR = 7
13
+ MINOR = 2
14
+ TINY = 2
15
+ PRE = "1"
14
16
 
15
17
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
18
  end
@@ -1,34 +1,37 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionCable
4
6
  module Helpers
5
7
  module ActionCableHelper
6
- # Returns an "action-cable-url" meta tag with the value of the URL specified in your
7
- # configuration. Ensure this is above your JavaScript tag:
8
+ # Returns an "action-cable-url" meta tag with the value of the URL specified in
9
+ # your configuration. Ensure this is above your JavaScript tag:
8
10
  #
9
- # <head>
10
- # <%= action_cable_meta_tag %>
11
- # <%= javascript_include_tag 'application', 'data-turbolinks-track' => 'reload' %>
12
- # </head>
11
+ # <head>
12
+ # <%= action_cable_meta_tag %>
13
+ # <%= javascript_include_tag 'application', 'data-turbo-track' => 'reload' %>
14
+ # </head>
13
15
  #
14
- # This is then used by Action Cable to determine the URL of your WebSocket server.
15
- # Your JavaScript can then connect to the server without needing to specify the
16
- # URL directly:
16
+ # This is then used by Action Cable to determine the URL of your WebSocket
17
+ # server. Your JavaScript can then connect to the server without needing to
18
+ # specify the URL directly:
17
19
  #
18
- # window.Cable = require("@rails/actioncable")
19
- # window.App = {}
20
- # App.cable = Cable.createConsumer()
20
+ # import Cable from "@rails/actioncable"
21
+ # window.Cable = Cable
22
+ # window.App = {}
23
+ # App.cable = Cable.createConsumer()
21
24
  #
22
25
  # Make sure to specify the correct server location in each of your environment
23
26
  # config files:
24
27
  #
25
- # config.action_cable.mount_path = "/cable123"
26
- # <%= action_cable_meta_tag %> would render:
27
- # => <meta name="action-cable-url" content="/cable123" />
28
+ # config.action_cable.mount_path = "/cable123"
29
+ # <%= action_cable_meta_tag %> would render:
30
+ # => <meta name="action-cable-url" content="/cable123" />
28
31
  #
29
- # config.action_cable.url = "ws://actioncable.com"
30
- # <%= action_cable_meta_tag %> would render:
31
- # => <meta name="action-cable-url" content="ws://actioncable.com" />
32
+ # config.action_cable.url = "ws://actioncable.com"
33
+ # <%= action_cable_meta_tag %> would render:
34
+ # => <meta name="action-cable-url" content="ws://actioncable.com" />
32
35
  #
33
36
  def action_cable_meta_tag
34
37
  tag "meta", name: "action-cable-url", content: (
@@ -1,24 +1,33 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "active_support/core_ext/module/redefine_method"
4
6
 
5
7
  module ActionCable
8
+ # # Action Cable Remote Connections
9
+ #
6
10
  # If you need to disconnect a given connection, you can go through the
7
11
  # RemoteConnections. You can find the connections you're looking for by
8
12
  # searching for the identifier declared on the connection. For example:
9
13
  #
10
- # module ApplicationCable
11
- # class Connection < ActionCable::Connection::Base
12
- # identified_by :current_user
13
- # ....
14
+ # module ApplicationCable
15
+ # class Connection < ActionCable::Connection::Base
16
+ # identified_by :current_user
17
+ # ....
18
+ # end
14
19
  # end
15
- # end
16
20
  #
17
- # ActionCable.server.remote_connections.where(current_user: User.find(1)).disconnect
21
+ # ActionCable.server.remote_connections.where(current_user: User.find(1)).disconnect
22
+ #
23
+ # This will disconnect all the connections established for `User.find(1)`,
24
+ # across all servers running on all machines, because it uses the internal
25
+ # channel that all of these servers are subscribed to.
26
+ #
27
+ # By default, server sends a "disconnect" message with "reconnect" flag set to
28
+ # true. You can override it by specifying the `reconnect` option:
18
29
  #
19
- # This will disconnect all the connections established for
20
- # <tt>User.find(1)</tt>, across all servers running on all machines, because
21
- # it uses the internal channel that all of these servers are subscribed to.
30
+ # ActionCable.server.remote_connections.where(current_user: User.find(1)).disconnect(reconnect: false)
22
31
  class RemoteConnections
23
32
  attr_reader :server
24
33
 
@@ -31,8 +40,11 @@ module ActionCable
31
40
  end
32
41
 
33
42
  private
34
- # Represents a single remote connection found via <tt>ActionCable.server.remote_connections.where(*)</tt>.
35
- # Exists solely for the purpose of calling #disconnect on that connection.
43
+ # # Action Cable Remote Connection
44
+ #
45
+ # Represents a single remote connection found via
46
+ # `ActionCable.server.remote_connections.where(*)`. Exists solely for the
47
+ # purpose of calling #disconnect on that connection.
36
48
  class RemoteConnection
37
49
  class InvalidIdentifiersError < StandardError; end
38
50
 
@@ -44,8 +56,8 @@ module ActionCable
44
56
  end
45
57
 
46
58
  # Uses the internal channel to disconnect the connection.
47
- def disconnect
48
- server.broadcast internal_channel, { type: "disconnect" }
59
+ def disconnect(reconnect: true)
60
+ server.broadcast internal_channel, { type: "disconnect", reconnect: reconnect }
49
61
  end
50
62
 
51
63
  # Returns all the identifiers that were applied to this connection.
@@ -1,13 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "monitor"
4
6
 
5
7
  module ActionCable
6
8
  module Server
7
- # A singleton ActionCable::Server instance is available via ActionCable.server. It's used by the Rack process that starts the Action Cable server, but
8
- # is also used by the user to reach the RemoteConnections object, which is used for finding and disconnecting connections across all servers.
9
+ # # Action Cable Server Base
10
+ #
11
+ # A singleton ActionCable::Server instance is available via ActionCable.server.
12
+ # It's used by the Rack process that starts the Action Cable server, but is also
13
+ # used by the user to reach the RemoteConnections object, which is used for
14
+ # finding and disconnecting connections across all servers.
9
15
  #
10
- # Also, this is the server instance used for broadcasting. See Broadcasting for more information.
16
+ # Also, this is the server instance used for broadcasting. See Broadcasting for
17
+ # more information.
11
18
  class Base
12
19
  include ActionCable::Server::Broadcasting
13
20
  include ActionCable::Server::Connections
@@ -29,11 +36,13 @@ module ActionCable
29
36
 
30
37
  # Called by Rack to set up the server.
31
38
  def call(env)
39
+ return config.health_check_application.call(env) if env["PATH_INFO"] == config.health_check_path
32
40
  setup_heartbeat_timer
33
41
  config.connection_class.call.new(self, env).process
34
42
  end
35
43
 
36
- # Disconnect all the connections identified by +identifiers+ on this server or any others via RemoteConnections.
44
+ # Disconnect all the connections identified by `identifiers` on this server or
45
+ # any others via RemoteConnections.
37
46
  def disconnect(identifiers)
38
47
  remote_connections.where(identifiers).disconnect
39
48
  end
@@ -63,17 +72,22 @@ module ActionCable
63
72
  @event_loop || @mutex.synchronize { @event_loop ||= ActionCable::Connection::StreamEventLoop.new }
64
73
  end
65
74
 
66
- # The worker pool is where we run connection callbacks and channel actions. We do as little as possible on the server's main thread.
67
- # The worker pool is an executor service that's backed by a pool of threads working from a task queue. The thread pool size maxes out
68
- # at 4 worker threads by default. Tune the size yourself with <tt>config.action_cable.worker_pool_size</tt>.
75
+ # The worker pool is where we run connection callbacks and channel actions. We
76
+ # do as little as possible on the server's main thread. The worker pool is an
77
+ # executor service that's backed by a pool of threads working from a task queue.
78
+ # The thread pool size maxes out at 4 worker threads by default. Tune the size
79
+ # yourself with `config.action_cable.worker_pool_size`.
69
80
  #
70
- # Using Active Record, Redis, etc within your channel actions means you'll get a separate connection from each thread in the worker pool.
71
- # Plan your deployment accordingly: 5 servers each running 5 Puma workers each running an 8-thread worker pool means at least 200 database
72
- # connections.
81
+ # Using Active Record, Redis, etc within your channel actions means you'll get a
82
+ # separate connection from each thread in the worker pool. Plan your deployment
83
+ # accordingly: 5 servers each running 5 Puma workers each running an 8-thread
84
+ # worker pool means at least 200 database connections.
73
85
  #
74
- # Also, ensure that your database connection pool size is as least as large as your worker pool size. Otherwise, workers may oversubscribe
75
- # the database connection pool and block while they wait for other workers to release their connections. Use a smaller worker pool or a larger
76
- # database connection pool instead.
86
+ # Also, ensure that your database connection pool size is as least as large as
87
+ # your worker pool size. Otherwise, workers may oversubscribe the database
88
+ # connection pool and block while they wait for other workers to release their
89
+ # connections. Use a smaller worker pool or a larger database connection pool
90
+ # instead.
77
91
  def worker_pool
78
92
  @worker_pool || @mutex.synchronize { @worker_pool ||= ActionCable::Server::Worker.new(max_size: config.worker_pool_size) }
79
93
  end
@@ -83,7 +97,8 @@ module ActionCable
83
97
  @pubsub || @mutex.synchronize { @pubsub ||= config.pubsub_adapter.new(self) }
84
98
  end
85
99
 
86
- # All of the identifiers applied to the connection class associated with this server.
100
+ # All of the identifiers applied to the connection class associated with this
101
+ # server.
87
102
  def connection_identifiers
88
103
  config.connection_class.call.identifiers
89
104
  end
@@ -1,32 +1,40 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionCable
4
6
  module Server
5
- # Broadcasting is how other parts of your application can send messages to a channel's subscribers. As explained in Channel, most of the time, these
6
- # broadcastings are streamed directly to the clients subscribed to the named broadcasting. Let's explain with a full-stack example:
7
+ # # Action Cable Server Broadcasting
8
+ #
9
+ # Broadcasting is how other parts of your application can send messages to a
10
+ # channel's subscribers. As explained in Channel, most of the time, these
11
+ # broadcastings are streamed directly to the clients subscribed to the named
12
+ # broadcasting. Let's explain with a full-stack example:
7
13
  #
8
- # class WebNotificationsChannel < ApplicationCable::Channel
9
- # def subscribed
10
- # stream_from "web_notifications_#{current_user.id}"
14
+ # class WebNotificationsChannel < ApplicationCable::Channel
15
+ # def subscribed
16
+ # stream_from "web_notifications_#{current_user.id}"
17
+ # end
11
18
  # end
12
- # end
13
19
  #
14
- # # Somewhere in your app this is called, perhaps from a NewCommentJob:
15
- # ActionCable.server.broadcast \
16
- # "web_notifications_1", { title: "New things!", body: "All that's fit for print" }
20
+ # # Somewhere in your app this is called, perhaps from a NewCommentJob:
21
+ # ActionCable.server.broadcast \
22
+ # "web_notifications_1", { title: "New things!", body: "All that's fit for print" }
17
23
  #
18
- # # Client-side CoffeeScript, which assumes you've already requested the right to send web notifications:
19
- # App.cable.subscriptions.create "WebNotificationsChannel",
20
- # received: (data) ->
21
- # new Notification data['title'], body: data['body']
24
+ # # Client-side CoffeeScript, which assumes you've already requested the right to send web notifications:
25
+ # App.cable.subscriptions.create "WebNotificationsChannel",
26
+ # received: (data) ->
27
+ # new Notification data['title'], body: data['body']
22
28
  module Broadcasting
23
- # Broadcast a hash directly to a named <tt>broadcasting</tt>. This will later be JSON encoded.
29
+ # Broadcast a hash directly to a named `broadcasting`. This will later be JSON
30
+ # encoded.
24
31
  def broadcast(broadcasting, message, coder: ActiveSupport::JSON)
25
32
  broadcaster_for(broadcasting, coder: coder).broadcast(message)
26
33
  end
27
34
 
28
- # Returns a broadcaster for a named <tt>broadcasting</tt> that can be reused. Useful when you have an object that
29
- # may need multiple spots to transmit to a specific broadcasting over and over.
35
+ # Returns a broadcaster for a named `broadcasting` that can be reused. Useful
36
+ # when you have an object that may need multiple spots to transmit to a specific
37
+ # broadcasting over and over.
30
38
  def broadcaster_for(broadcasting, coder: ActiveSupport::JSON)
31
39
  Broadcaster.new(self, String(broadcasting), coder: coder)
32
40
  end