actioncable 7.1.3.4 → 7.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +26 -129
  3. data/app/assets/javascripts/action_cable.js +3 -3
  4. data/app/assets/javascripts/actioncable.esm.js +3 -3
  5. data/app/assets/javascripts/actioncable.js +3 -3
  6. data/lib/action_cable/channel/base.rb +98 -86
  7. data/lib/action_cable/channel/broadcasting.rb +25 -18
  8. data/lib/action_cable/channel/callbacks.rb +27 -25
  9. data/lib/action_cable/channel/naming.rb +9 -8
  10. data/lib/action_cable/channel/periodic_timers.rb +7 -7
  11. data/lib/action_cable/channel/streams.rb +77 -64
  12. data/lib/action_cable/channel/test_case.rb +112 -86
  13. data/lib/action_cable/connection/authorization.rb +4 -1
  14. data/lib/action_cable/connection/base.rb +53 -38
  15. data/lib/action_cable/connection/callbacks.rb +20 -18
  16. data/lib/action_cable/connection/client_socket.rb +3 -1
  17. data/lib/action_cable/connection/identification.rb +9 -5
  18. data/lib/action_cable/connection/internal_channel.rb +5 -2
  19. data/lib/action_cable/connection/message_buffer.rb +4 -1
  20. data/lib/action_cable/connection/stream.rb +2 -0
  21. data/lib/action_cable/connection/stream_event_loop.rb +4 -3
  22. data/lib/action_cable/connection/subscriptions.rb +6 -3
  23. data/lib/action_cable/connection/tagged_logger_proxy.rb +7 -4
  24. data/lib/action_cable/connection/test_case.rb +66 -56
  25. data/lib/action_cable/connection/web_socket.rb +10 -8
  26. data/lib/action_cable/deprecator.rb +2 -0
  27. data/lib/action_cable/engine.rb +5 -3
  28. data/lib/action_cable/gem_version.rb +6 -4
  29. data/lib/action_cable/helpers/action_cable_helper.rb +21 -19
  30. data/lib/action_cable/remote_connections.rb +19 -16
  31. data/lib/action_cable/server/base.rb +27 -15
  32. data/lib/action_cable/server/broadcasting.rb +23 -17
  33. data/lib/action_cable/server/configuration.rb +17 -14
  34. data/lib/action_cable/server/connections.rb +11 -5
  35. data/lib/action_cable/server/worker/active_record_connection_management.rb +2 -0
  36. data/lib/action_cable/server/worker.rb +4 -2
  37. data/lib/action_cable/subscription_adapter/async.rb +2 -0
  38. data/lib/action_cable/subscription_adapter/base.rb +2 -0
  39. data/lib/action_cable/subscription_adapter/channel_prefix.rb +2 -0
  40. data/lib/action_cable/subscription_adapter/inline.rb +2 -0
  41. data/lib/action_cable/subscription_adapter/postgresql.rb +4 -2
  42. data/lib/action_cable/subscription_adapter/redis.rb +5 -2
  43. data/lib/action_cable/subscription_adapter/subscriber_map.rb +2 -0
  44. data/lib/action_cable/subscription_adapter/test.rb +8 -5
  45. data/lib/action_cable/test_case.rb +2 -0
  46. data/lib/action_cable/test_helper.rb +51 -52
  47. data/lib/action_cable/version.rb +3 -1
  48. data/lib/action_cable.rb +13 -7
  49. data/lib/rails/generators/channel/channel_generator.rb +4 -2
  50. data/lib/rails/generators/test_unit/channel_generator.rb +2 -0
  51. metadata +13 -13
  52. /data/lib/rails/generators/channel/templates/application_cable/{channel.rb → channel.rb.tt} +0 -0
  53. /data/lib/rails/generators/channel/templates/application_cable/{connection.rb → connection.rb.tt} +0 -0
@@ -1,12 +1,15 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionCable
4
6
  module Connection
5
- # = Action Cable \Connection \TaggedLoggerProxy
7
+ # # Action Cable Connection TaggedLoggerProxy
6
8
  #
7
- # Allows the use of per-connection tags against the server logger. This wouldn't work using the traditional
8
- # ActiveSupport::TaggedLogging enhanced Rails.logger, as that logger will reset the tags between requests.
9
- # The connection is long-lived, so it needs its own set of tags for its independent duration.
9
+ # Allows the use of per-connection tags against the server logger. This wouldn't
10
+ # work using the traditional ActiveSupport::TaggedLogging enhanced Rails.logger,
11
+ # as that logger will reset the tags between requests. The connection is
12
+ # long-lived, so it needs its own set of tags for its independent duration.
10
13
  class TaggedLoggerProxy
11
14
  attr_reader :tags
12
15
 
@@ -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,77 +66,77 @@ module ActionCable
56
66
  end
57
67
  end
58
68
 
59
- # = Action Cable \Connection \TestCase
69
+ # # Action Cable Connection TestCase
60
70
  #
61
71
  # Unit test Action Cable connections.
62
72
  #
63
- # 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
64
74
  # and that any improper connection requests are rejected.
65
75
  #
66
- # == Basic example
76
+ # ## Basic example
67
77
  #
68
78
  # Unit tests are written as follows:
69
79
  #
70
- # 1. Simulate a connection attempt by calling +connect+.
71
- # 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.
72
82
  #
73
83
  #
74
- # class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase
75
- # def test_connects_with_proper_cookie
76
- # # Simulate the connection request with a cookie.
77
- # 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
78
88
  #
79
- # connect
89
+ # connect
80
90
  #
81
- # # Assert the connection identifier matches the fixture.
82
- # assert_equal users(:john).id, connection.user.id
83
- # end
91
+ # # Assert the connection identifier matches the fixture.
92
+ # assert_equal users(:john).id, connection.user.id
93
+ # end
84
94
  #
85
- # def test_rejects_connection_without_proper_cookie
86
- # assert_reject_connection { connect }
95
+ # def test_rejects_connection_without_proper_cookie
96
+ # assert_reject_connection { connect }
97
+ # end
87
98
  # end
88
- # end
89
99
  #
90
- # +connect+ accepts additional information about the HTTP request with the
91
- # +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.
92
102
  #
93
- # def test_connect_with_headers_and_query_string
94
- # 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" }
95
105
  #
96
- # assert_equal "1", connection.user.id
97
- # assert_equal "secret-my", connection.token
98
- # end
106
+ # assert_equal "1", connection.user.id
107
+ # assert_equal "secret-my", connection.token
108
+ # end
99
109
  #
100
- # def test_connect_with_params
101
- # connect params: { user_id: 1 }
110
+ # def test_connect_with_params
111
+ # connect params: { user_id: 1 }
102
112
  #
103
- # assert_equal "1", connection.user.id
104
- # end
113
+ # assert_equal "1", connection.user.id
114
+ # end
105
115
  #
106
116
  # You can also set up the correct cookies before the connection request:
107
117
  #
108
- # def test_connect_with_cookies
109
- # # Plain cookies:
110
- # cookies["user_id"] = 1
118
+ # def test_connect_with_cookies
119
+ # # Plain cookies:
120
+ # cookies["user_id"] = 1
111
121
  #
112
- # # Or signed/encrypted:
113
- # # cookies.signed["user_id"] = 1
114
- # # cookies.encrypted["user_id"] = 1
122
+ # # Or signed/encrypted:
123
+ # # cookies.signed["user_id"] = 1
124
+ # # cookies.encrypted["user_id"] = 1
115
125
  #
116
- # connect
126
+ # connect
117
127
  #
118
- # assert_equal "1", connection.user_id
119
- # end
128
+ # assert_equal "1", connection.user_id
129
+ # end
120
130
  #
121
- # == \Connection is automatically inferred
131
+ # ## Connection is automatically inferred
122
132
  #
123
- # ActionCable::Connection::TestCase will automatically infer the connection under test
124
- # from the test class name. If the channel cannot be inferred from the test
125
- # 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`.
126
136
  #
127
- # class ConnectionTest < ActionCable::Connection::TestCase
128
- # tests ApplicationCable::Connection
129
- # end
137
+ # class ConnectionTest < ActionCable::Connection::TestCase
138
+ # tests ApplicationCable::Connection
139
+ # end
130
140
  #
131
141
  class TestCase < ActiveSupport::TestCase
132
142
  module Behavior
@@ -178,10 +188,10 @@ module ActionCable
178
188
  #
179
189
  # Accepts request path as the first argument and the following request options:
180
190
  #
181
- # - params – URL parameters (Hash)
182
- # - headers – request headers (Hash)
183
- # - session – session data (Hash)
184
- # - 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)
185
195
  def connect(path = ActionCable.server.config.mount_path, **request_params)
186
196
  path ||= DEFAULT_PATH
187
197
 
@@ -1,10 +1,12 @@
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
7
- # = Action Cable \Connection \WebSocket
9
+ # # Action Cable Connection WebSocket
8
10
  #
9
11
  # Wrap the real socket to minimize the externally-presented API
10
12
  class WebSocket # :nodoc:
@@ -17,23 +19,23 @@ module ActionCable
17
19
  end
18
20
 
19
21
  def alive?
20
- websocket && websocket.alive?
22
+ websocket&.alive?
21
23
  end
22
24
 
23
- def transmit(data)
24
- websocket.transmit data
25
+ def transmit(...)
26
+ websocket&.transmit(...)
25
27
  end
26
28
 
27
- def close
28
- websocket.close
29
+ def close(...)
30
+ websocket&.close(...)
29
31
  end
30
32
 
31
33
  def protocol
32
- websocket.protocol
34
+ websocket&.protocol
33
35
  end
34
36
 
35
37
  def rack_response
36
- websocket.rack_response
38
+ websocket&.rack_response
37
39
  end
38
40
 
39
41
  private
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionCable
4
6
  def self.deprecator # :nodoc:
5
7
  @deprecator ||= ActiveSupport::Deprecation.new
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "rails"
4
6
  require "action_cable"
5
7
  require "active_support/core_ext/hash/indifferent_access"
@@ -72,9 +74,9 @@ module ActionCable
72
74
  ActiveSupport.on_load(:action_cable) do
73
75
  ActionCable::Server::Worker.set_callback :work, :around, prepend: true do |_, inner|
74
76
  app.executor.wrap(source: "application.action_cable") do
75
- # If we took a while to get the lock, we may have been halted
76
- # in the meantime. As we haven't started doing any real work
77
- # yet, we should pretend that we never made it off the queue.
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.
78
80
  unless stopping?
79
81
  inner.call
80
82
  end
@@ -1,16 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionCable
4
- # Returns the currently loaded version of Action Cable as a +Gem::Version+.
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
12
  MAJOR = 7
11
- MINOR = 1
12
- TINY = 3
13
- PRE = "4"
13
+ MINOR = 2
14
+ TINY = 1
15
+ PRE = nil
14
16
 
15
17
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
16
18
  end
@@ -1,35 +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-turbo-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
- # import Cable from "@rails/actioncable"
19
- # window.Cable = Cable
20
- # window.App = {}
21
- # App.cable = Cable.createConsumer()
20
+ # import Cable from "@rails/actioncable"
21
+ # window.Cable = Cable
22
+ # window.App = {}
23
+ # App.cable = Cable.createConsumer()
22
24
  #
23
25
  # Make sure to specify the correct server location in each of your environment
24
26
  # config files:
25
27
  #
26
- # config.action_cable.mount_path = "/cable123"
27
- # <%= action_cable_meta_tag %> would render:
28
- # => <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" />
29
31
  #
30
- # config.action_cable.url = "ws://actioncable.com"
31
- # <%= action_cable_meta_tag %> would render:
32
- # => <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" />
33
35
  #
34
36
  def action_cable_meta_tag
35
37
  tag "meta", name: "action-cable-url", content: (
@@ -1,31 +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
6
- # = Action Cable Remote Connections
8
+ # # Action Cable Remote Connections
7
9
  #
8
10
  # If you need to disconnect a given connection, you can go through the
9
11
  # RemoteConnections. You can find the connections you're looking for by
10
12
  # searching for the identifier declared on the connection. For example:
11
13
  #
12
- # module ApplicationCable
13
- # class Connection < ActionCable::Connection::Base
14
- # identified_by :current_user
15
- # ....
14
+ # module ApplicationCable
15
+ # class Connection < ActionCable::Connection::Base
16
+ # identified_by :current_user
17
+ # ....
18
+ # end
16
19
  # end
17
- # end
18
20
  #
19
- # ActionCable.server.remote_connections.where(current_user: User.find(1)).disconnect
21
+ # ActionCable.server.remote_connections.where(current_user: User.find(1)).disconnect
20
22
  #
21
- # This will disconnect all the connections established for
22
- # <tt>User.find(1)</tt>, across all servers running on all machines, because
23
- # it uses the internal channel that all of these servers are subscribed to.
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.
24
26
  #
25
- # By default, server sends a "disconnect" message with "reconnect" flag set to true.
26
- # You can override it by specifying the +reconnect+ option:
27
+ # By default, server sends a "disconnect" message with "reconnect" flag set to
28
+ # true. You can override it by specifying the `reconnect` option:
27
29
  #
28
- # ActionCable.server.remote_connections.where(current_user: User.find(1)).disconnect(reconnect: false)
30
+ # ActionCable.server.remote_connections.where(current_user: User.find(1)).disconnect(reconnect: false)
29
31
  class RemoteConnections
30
32
  attr_reader :server
31
33
 
@@ -38,10 +40,11 @@ module ActionCable
38
40
  end
39
41
 
40
42
  private
41
- # = Action Cable Remote \Connection
43
+ # # Action Cable Remote Connection
42
44
  #
43
- # Represents a single remote connection found via <tt>ActionCable.server.remote_connections.where(*)</tt>.
44
- # Exists solely for the purpose of calling #disconnect on that connection.
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.
45
48
  class RemoteConnection
46
49
  class InvalidIdentifiersError < StandardError; end
47
50
 
@@ -1,15 +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
- # = Action Cable \Server \Base
9
+ # # Action Cable Server Base
8
10
  #
9
- # A singleton ActionCable::Server instance is available via ActionCable.server. It's used by the Rack process that starts the Action Cable server, but
10
- # is also used by the user to reach the RemoteConnections object, which is used for finding and disconnecting connections across all servers.
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.
11
15
  #
12
- # 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.
13
18
  class Base
14
19
  include ActionCable::Server::Broadcasting
15
20
  include ActionCable::Server::Connections
@@ -36,7 +41,8 @@ module ActionCable
36
41
  config.connection_class.call.new(self, env).process
37
42
  end
38
43
 
39
- # 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.
40
46
  def disconnect(identifiers)
41
47
  remote_connections.where(identifiers).disconnect
42
48
  end
@@ -66,17 +72,22 @@ module ActionCable
66
72
  @event_loop || @mutex.synchronize { @event_loop ||= ActionCable::Connection::StreamEventLoop.new }
67
73
  end
68
74
 
69
- # The worker pool is where we run connection callbacks and channel actions. We do as little as possible on the server's main thread.
70
- # 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
71
- # 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`.
72
80
  #
73
- # Using Active Record, Redis, etc within your channel actions means you'll get a separate connection from each thread in the worker pool.
74
- # Plan your deployment accordingly: 5 servers each running 5 Puma workers each running an 8-thread worker pool means at least 200 database
75
- # 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.
76
85
  #
77
- # Also, ensure that your database connection pool size is as least as large as your worker pool size. Otherwise, workers may oversubscribe
78
- # the database connection pool and block while they wait for other workers to release their connections. Use a smaller worker pool or a larger
79
- # 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.
80
91
  def worker_pool
81
92
  @worker_pool || @mutex.synchronize { @worker_pool ||= ActionCable::Server::Worker.new(max_size: config.worker_pool_size) }
82
93
  end
@@ -86,7 +97,8 @@ module ActionCable
86
97
  @pubsub || @mutex.synchronize { @pubsub ||= config.pubsub_adapter.new(self) }
87
98
  end
88
99
 
89
- # 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.
90
102
  def connection_identifiers
91
103
  config.connection_class.call.identifiers
92
104
  end
@@ -1,34 +1,40 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  module ActionCable
4
6
  module Server
5
- # = Action Cable \Server \Broadcasting
7
+ # # Action Cable Server Broadcasting
6
8
  #
7
- # 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
8
- # broadcastings are streamed directly to the clients subscribed to the named broadcasting. Let's explain with a full-stack example:
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:
9
13
  #
10
- # class WebNotificationsChannel < ApplicationCable::Channel
11
- # def subscribed
12
- # 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
13
18
  # end
14
- # end
15
19
  #
16
- # # Somewhere in your app this is called, perhaps from a NewCommentJob:
17
- # ActionCable.server.broadcast \
18
- # "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" }
19
23
  #
20
- # # Client-side CoffeeScript, which assumes you've already requested the right to send web notifications:
21
- # App.cable.subscriptions.create "WebNotificationsChannel",
22
- # received: (data) ->
23
- # 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']
24
28
  module Broadcasting
25
- # 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.
26
31
  def broadcast(broadcasting, message, coder: ActiveSupport::JSON)
27
32
  broadcaster_for(broadcasting, coder: coder).broadcast(message)
28
33
  end
29
34
 
30
- # Returns a broadcaster for a named <tt>broadcasting</tt> that can be reused. Useful when you have an object that
31
- # 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.
32
38
  def broadcaster_for(broadcasting, coder: ActiveSupport::JSON)
33
39
  Broadcaster.new(self, String(broadcasting), coder: coder)
34
40
  end
@@ -1,13 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ # :markup: markdown
4
+
3
5
  require "rack"
4
6
 
5
7
  module ActionCable
6
8
  module Server
7
- # = Action Cable \Server \Configuration
9
+ # # Action Cable Server Configuration
8
10
  #
9
- # An instance of this configuration object is available via ActionCable.server.config, which allows you to tweak Action Cable configuration
10
- # in a \Rails config initializer.
11
+ # An instance of this configuration object is available via
12
+ # ActionCable.server.config, which allows you to tweak Action Cable
13
+ # configuration in a Rails config initializer.
11
14
  class Configuration
12
15
  attr_accessor :logger, :log_tags
13
16
  attr_accessor :connection_class, :worker_pool_size
@@ -31,28 +34,28 @@ module ActionCable
31
34
  }
32
35
  end
33
36
 
34
- # Returns constant of subscription adapter specified in config/cable.yml.
35
- # If the adapter cannot be found, this will default to the Redis adapter.
36
- # Also makes sure proper dependencies are required.
37
+ # Returns constant of subscription adapter specified in config/cable.yml. If the
38
+ # adapter cannot be found, this will default to the Redis adapter. Also makes
39
+ # sure proper dependencies are required.
37
40
  def pubsub_adapter
38
41
  adapter = (cable.fetch("adapter") { "redis" })
39
42
 
40
43
  # Require the adapter itself and give useful feedback about
41
- # 1. Missing adapter gems and
42
- # 2. Adapter gems' missing dependencies.
44
+ # 1. Missing adapter gems and
45
+ # 2. Adapter gems' missing dependencies.
43
46
  path_to_adapter = "action_cable/subscription_adapter/#{adapter}"
44
47
  begin
45
48
  require path_to_adapter
46
49
  rescue LoadError => e
47
- # We couldn't require the adapter itself. Raise an exception that
48
- # points out config typos and missing gems.
50
+ # We couldn't require the adapter itself. Raise an exception that points out
51
+ # config typos and missing gems.
49
52
  if e.path == path_to_adapter
50
- # We can assume that a non-builtin adapter was specified, so it's
51
- # either misspelled or missing from Gemfile.
53
+ # We can assume that a non-builtin adapter was specified, so it's either
54
+ # misspelled or missing from Gemfile.
52
55
  raise e.class, "Could not load the '#{adapter}' Action Cable pubsub adapter. Ensure that the adapter is spelled correctly in config/cable.yml and that you've added the necessary adapter gem to your Gemfile.", e.backtrace
53
56
 
54
- # Bubbled up from the adapter require. Prefix the exception message
55
- # with some guidance about how to address it and reraise.
57
+ # Bubbled up from the adapter require. Prefix the exception message with some
58
+ # guidance about how to address it and reraise.
56
59
  else
57
60
  raise e.class, "Error loading the '#{adapter}' Action Cable pubsub adapter. Missing a gem it depends on? #{e.message}", e.backtrace
58
61
  end