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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +34 -180
- data/MIT-LICENSE +1 -1
- data/README.md +4 -4
- data/app/assets/javascripts/action_cable.js +30 -9
- data/app/assets/javascripts/actioncable.esm.js +30 -9
- data/app/assets/javascripts/actioncable.js +30 -9
- data/lib/action_cable/channel/base.rb +114 -90
- data/lib/action_cable/channel/broadcasting.rb +25 -16
- data/lib/action_cable/channel/callbacks.rb +39 -0
- data/lib/action_cable/channel/naming.rb +10 -7
- data/lib/action_cable/channel/periodic_timers.rb +7 -7
- data/lib/action_cable/channel/streams.rb +77 -62
- data/lib/action_cable/channel/test_case.rb +117 -86
- data/lib/action_cable/connection/authorization.rb +4 -1
- data/lib/action_cable/connection/base.rb +70 -42
- data/lib/action_cable/connection/callbacks.rb +57 -0
- data/lib/action_cable/connection/client_socket.rb +3 -1
- data/lib/action_cable/connection/identification.rb +9 -5
- data/lib/action_cable/connection/internal_channel.rb +7 -2
- data/lib/action_cable/connection/message_buffer.rb +4 -1
- data/lib/action_cable/connection/stream.rb +2 -2
- data/lib/action_cable/connection/stream_event_loop.rb +4 -4
- data/lib/action_cable/connection/subscriptions.rb +7 -2
- data/lib/action_cable/connection/tagged_logger_proxy.rb +12 -7
- data/lib/action_cable/connection/test_case.rb +67 -55
- data/lib/action_cable/connection/web_socket.rb +11 -7
- data/lib/action_cable/deprecator.rb +9 -0
- data/lib/action_cable/engine.rb +18 -8
- data/lib/action_cable/gem_version.rb +6 -4
- data/lib/action_cable/helpers/action_cable_helper.rb +21 -19
- data/lib/action_cable/remote_connections.rb +25 -13
- data/lib/action_cable/server/base.rb +29 -14
- data/lib/action_cable/server/broadcasting.rb +24 -16
- data/lib/action_cable/server/configuration.rb +27 -14
- data/lib/action_cable/server/connections.rb +13 -5
- data/lib/action_cable/server/worker/active_record_connection_management.rb +2 -0
- data/lib/action_cable/server/worker.rb +4 -3
- data/lib/action_cable/subscription_adapter/async.rb +1 -1
- data/lib/action_cable/subscription_adapter/base.rb +2 -0
- data/lib/action_cable/subscription_adapter/channel_prefix.rb +2 -0
- data/lib/action_cable/subscription_adapter/inline.rb +2 -0
- data/lib/action_cable/subscription_adapter/postgresql.rb +4 -3
- data/lib/action_cable/subscription_adapter/redis.rb +7 -7
- data/lib/action_cable/subscription_adapter/subscriber_map.rb +2 -0
- data/lib/action_cable/subscription_adapter/test.rb +6 -5
- data/lib/action_cable/test_case.rb +2 -0
- data/lib/action_cable/test_helper.rb +89 -59
- data/lib/action_cable/version.rb +3 -1
- data/lib/action_cable.rb +30 -12
- data/lib/rails/generators/channel/USAGE +14 -8
- data/lib/rails/generators/channel/channel_generator.rb +23 -7
- data/lib/rails/generators/test_unit/channel_generator.rb +2 -0
- metadata +27 -15
- data/lib/action_cable/channel.rb +0 -17
- data/lib/action_cable/connection.rb +0 -22
- data/lib/action_cable/server.rb +0 -16
- data/lib/action_cable/subscription_adapter.rb +0 -12
- /data/lib/rails/generators/channel/templates/application_cable/{channel.rb → channel.rb.tt} +0 -0
- /data/lib/rails/generators/channel/templates/application_cable/{connection.rb → connection.rb.tt} +0 -0
@@ -1,99 +1,112 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :markup: markdown
|
4
|
+
|
3
5
|
require "set"
|
4
6
|
require "active_support/rescuable"
|
7
|
+
require "active_support/parameter_filter"
|
5
8
|
|
6
9
|
module ActionCable
|
7
10
|
module Channel
|
8
|
-
#
|
9
|
-
# You can think of a channel like a form of controller, but one that's capable of pushing content to the subscriber in addition to simply
|
10
|
-
# responding to the subscriber's direct requests.
|
11
|
+
# # Action Cable Channel Base
|
11
12
|
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
13
|
+
# The channel provides the basic structure of grouping behavior into logical
|
14
|
+
# units when communicating over the WebSocket connection. You can think of a
|
15
|
+
# channel like a form of controller, but one that's capable of pushing content
|
16
|
+
# to the subscriber in addition to simply responding to the subscriber's direct
|
17
|
+
# requests.
|
16
18
|
#
|
17
|
-
#
|
18
|
-
#
|
19
|
+
# Channel instances are long-lived. A channel object will be instantiated when
|
20
|
+
# the cable consumer becomes a subscriber, and then lives until the consumer
|
21
|
+
# disconnects. This may be seconds, minutes, hours, or even days. That means you
|
22
|
+
# have to take special care not to do anything silly in a channel that would
|
23
|
+
# balloon its memory footprint or whatever. The references are forever, so they
|
24
|
+
# won't be released as is normally the case with a controller instance that gets
|
25
|
+
# thrown away after every request.
|
19
26
|
#
|
20
|
-
#
|
21
|
-
#
|
27
|
+
# Long-lived channels (and connections) also mean you're responsible for
|
28
|
+
# ensuring that the data is fresh. If you hold a reference to a user record, but
|
29
|
+
# the name is changed while that reference is held, you may be sending stale
|
30
|
+
# data if you don't take precautions to avoid it.
|
22
31
|
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
# end
|
32
|
+
# The upside of long-lived channel instances is that you can use instance
|
33
|
+
# variables to keep reference to objects that future subscriber requests can
|
34
|
+
# interact with. Here's a quick example:
|
27
35
|
#
|
28
|
-
#
|
29
|
-
#
|
36
|
+
# class ChatChannel < ApplicationCable::Channel
|
37
|
+
# def subscribed
|
38
|
+
# @room = Chat::Room[params[:room_number]]
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# def speak(data)
|
42
|
+
# @room.speak data, user: current_user
|
43
|
+
# end
|
30
44
|
# end
|
31
|
-
# end
|
32
45
|
#
|
33
|
-
# The #speak action simply uses the Chat::Room object that was created when the
|
34
|
-
#
|
46
|
+
# The #speak action simply uses the Chat::Room object that was created when the
|
47
|
+
# channel was first subscribed to by the consumer when that subscriber wants to
|
48
|
+
# say something in the room.
|
35
49
|
#
|
36
|
-
#
|
50
|
+
# ## Action processing
|
37
51
|
#
|
38
52
|
# Unlike subclasses of ActionController::Base, channels do not follow a RESTful
|
39
53
|
# constraint form for their actions. Instead, Action Cable operates through a
|
40
|
-
# remote-procedure call model. You can declare any public method on the
|
41
|
-
#
|
42
|
-
#
|
54
|
+
# remote-procedure call model. You can declare any public method on the channel
|
55
|
+
# (optionally taking a `data` argument), and this method is automatically
|
56
|
+
# exposed as callable to the client.
|
43
57
|
#
|
44
58
|
# Example:
|
45
59
|
#
|
46
|
-
#
|
47
|
-
#
|
48
|
-
#
|
49
|
-
#
|
50
|
-
#
|
51
|
-
# def unsubscribed
|
52
|
-
# current_user.disappear @connection_token
|
53
|
-
# end
|
60
|
+
# class AppearanceChannel < ApplicationCable::Channel
|
61
|
+
# def subscribed
|
62
|
+
# @connection_token = generate_connection_token
|
63
|
+
# end
|
54
64
|
#
|
55
|
-
#
|
56
|
-
#
|
57
|
-
#
|
65
|
+
# def unsubscribed
|
66
|
+
# current_user.disappear @connection_token
|
67
|
+
# end
|
58
68
|
#
|
59
|
-
#
|
60
|
-
#
|
61
|
-
#
|
69
|
+
# def appear(data)
|
70
|
+
# current_user.appear @connection_token, on: data['appearing_on']
|
71
|
+
# end
|
62
72
|
#
|
63
|
-
#
|
64
|
-
#
|
65
|
-
# SecureRandom.hex(36)
|
73
|
+
# def away
|
74
|
+
# current_user.away @connection_token
|
66
75
|
# end
|
67
|
-
# end
|
68
76
|
#
|
69
|
-
#
|
70
|
-
#
|
71
|
-
#
|
72
|
-
#
|
73
|
-
#
|
74
|
-
#
|
77
|
+
# private
|
78
|
+
# def generate_connection_token
|
79
|
+
# SecureRandom.hex(36)
|
80
|
+
# end
|
81
|
+
# end
|
82
|
+
#
|
83
|
+
# In this example, the subscribed and unsubscribed methods are not callable
|
84
|
+
# methods, as they were already declared in ActionCable::Channel::Base, but
|
85
|
+
# `#appear` and `#away` are. `#generate_connection_token` is also not callable,
|
86
|
+
# since it's a private method. You'll see that appear accepts a data parameter,
|
87
|
+
# which it then uses as part of its model call. `#away` does not, since it's
|
88
|
+
# simply a trigger action.
|
75
89
|
#
|
76
|
-
# Also note that in this example,
|
77
|
-
#
|
78
|
-
#
|
79
|
-
#
|
90
|
+
# Also note that in this example, `current_user` is available because it was
|
91
|
+
# marked as an identifying attribute on the connection. All such identifiers
|
92
|
+
# will automatically create a delegation method of the same name on the channel
|
93
|
+
# instance.
|
80
94
|
#
|
81
|
-
#
|
95
|
+
# ## Rejecting subscription requests
|
82
96
|
#
|
83
97
|
# A channel can reject a subscription request in the #subscribed callback by
|
84
98
|
# invoking the #reject method:
|
85
99
|
#
|
86
|
-
#
|
87
|
-
#
|
88
|
-
#
|
89
|
-
#
|
100
|
+
# class ChatChannel < ApplicationCable::Channel
|
101
|
+
# def subscribed
|
102
|
+
# @room = Chat::Room[params[:room_number]]
|
103
|
+
# reject unless current_user.can_access?(@room)
|
104
|
+
# end
|
90
105
|
# end
|
91
|
-
# end
|
92
106
|
#
|
93
|
-
# In this example, the subscription will be rejected if the
|
94
|
-
#
|
95
|
-
#
|
96
|
-
# the server rejects the subscription request.
|
107
|
+
# In this example, the subscription will be rejected if the `current_user` does
|
108
|
+
# not have access to the chat room. On the client-side, the `Channel#rejected`
|
109
|
+
# callback will get invoked when the server rejects the subscription request.
|
97
110
|
class Base
|
98
111
|
include Callbacks
|
99
112
|
include PeriodicTimers
|
@@ -106,14 +119,13 @@ module ActionCable
|
|
106
119
|
delegate :logger, to: :connection
|
107
120
|
|
108
121
|
class << self
|
109
|
-
# A list of method names that should be considered actions. This
|
110
|
-
#
|
111
|
-
# any
|
112
|
-
#
|
113
|
-
# itself.
|
122
|
+
# A list of method names that should be considered actions. This includes all
|
123
|
+
# public instance methods on a channel, less any internal methods (defined on
|
124
|
+
# Base), adding back in any methods that are internal, but still exist on the
|
125
|
+
# class itself.
|
114
126
|
#
|
115
|
-
#
|
116
|
-
# *
|
127
|
+
# #### Returns
|
128
|
+
# * `Set` - A set of all methods that should be considered actions.
|
117
129
|
def action_methods
|
118
130
|
@action_methods ||= begin
|
119
131
|
# All public instance methods of this class, including ancestors
|
@@ -127,9 +139,9 @@ module ActionCable
|
|
127
139
|
end
|
128
140
|
|
129
141
|
private
|
130
|
-
# action_methods are cached and there is sometimes need to refresh
|
131
|
-
#
|
132
|
-
#
|
142
|
+
# action_methods are cached and there is sometimes need to refresh them.
|
143
|
+
# ::clear_action_methods! allows you to do that, so next time you run
|
144
|
+
# action_methods, they will be recalculated.
|
133
145
|
def clear_action_methods! # :doc:
|
134
146
|
@action_methods = nil
|
135
147
|
end
|
@@ -158,9 +170,9 @@ module ActionCable
|
|
158
170
|
delegate_connection_identifiers
|
159
171
|
end
|
160
172
|
|
161
|
-
# Extract the action name from the passed data and process it via the channel.
|
162
|
-
# that the action requested is a public method on the
|
163
|
-
# like #subscribed).
|
173
|
+
# Extract the action name from the passed data and process it via the channel.
|
174
|
+
# The process will ensure that the action requested is a public method on the
|
175
|
+
# channel declared by the user (so not one of the callbacks like #subscribed).
|
164
176
|
def perform_action(data)
|
165
177
|
action = extract_action(data)
|
166
178
|
|
@@ -174,8 +186,8 @@ module ActionCable
|
|
174
186
|
end
|
175
187
|
end
|
176
188
|
|
177
|
-
# This method is called after subscription has been added to the connection
|
178
|
-
#
|
189
|
+
# This method is called after subscription has been added to the connection and
|
190
|
+
# confirms or rejects the subscription.
|
179
191
|
def subscribe_to_channel
|
180
192
|
run_callbacks :subscribe do
|
181
193
|
subscribed
|
@@ -185,8 +197,9 @@ module ActionCable
|
|
185
197
|
ensure_confirmation_sent
|
186
198
|
end
|
187
199
|
|
188
|
-
# Called by the cable connection when it's cut, so the channel has a chance to
|
189
|
-
# This method is not intended to be called directly by
|
200
|
+
# Called by the cable connection when it's cut, so the channel has a chance to
|
201
|
+
# cleanup with callbacks. This method is not intended to be called directly by
|
202
|
+
# the user. Instead, override the #unsubscribed callback.
|
190
203
|
def unsubscribe_from_channel # :nodoc:
|
191
204
|
run_callbacks :unsubscribe do
|
192
205
|
unsubscribed
|
@@ -194,24 +207,28 @@ module ActionCable
|
|
194
207
|
end
|
195
208
|
|
196
209
|
private
|
197
|
-
# Called once a consumer has become a subscriber of the channel. Usually the
|
198
|
-
# you want this channel to be sending to the
|
210
|
+
# Called once a consumer has become a subscriber of the channel. Usually the
|
211
|
+
# place to set up any streams you want this channel to be sending to the
|
212
|
+
# subscriber.
|
199
213
|
def subscribed # :doc:
|
200
214
|
# Override in subclasses
|
201
215
|
end
|
202
216
|
|
203
|
-
# Called once a consumer has cut its cable connection. Can be used for cleaning
|
204
|
-
# users as offline or the like.
|
217
|
+
# Called once a consumer has cut its cable connection. Can be used for cleaning
|
218
|
+
# up connections or marking users as offline or the like.
|
205
219
|
def unsubscribed # :doc:
|
206
220
|
# Override in subclasses
|
207
221
|
end
|
208
222
|
|
209
|
-
# Transmit a hash of data to the subscriber. The hash will automatically be
|
210
|
-
# the proper channel identifier marked as the
|
223
|
+
# Transmit a hash of data to the subscriber. The hash will automatically be
|
224
|
+
# wrapped in a JSON envelope with the proper channel identifier marked as the
|
225
|
+
# recipient.
|
211
226
|
def transmit(data, via: nil) # :doc:
|
212
|
-
|
213
|
-
|
214
|
-
|
227
|
+
logger.debug do
|
228
|
+
status = "#{self.class.name} transmitting #{data.inspect.truncate(300)}"
|
229
|
+
status += " (via #{via})" if via
|
230
|
+
status
|
231
|
+
end
|
215
232
|
|
216
233
|
payload = { channel_class: self.class.name, data: data, via: via }
|
217
234
|
ActiveSupport::Notifications.instrument("transmit.action_cable", payload) do
|
@@ -262,7 +279,7 @@ module ActionCable
|
|
262
279
|
end
|
263
280
|
|
264
281
|
def dispatch_action(action, data)
|
265
|
-
logger.
|
282
|
+
logger.debug action_signature(action, data)
|
266
283
|
|
267
284
|
if method(action).arity == 1
|
268
285
|
public_send action, data
|
@@ -275,12 +292,19 @@ module ActionCable
|
|
275
292
|
|
276
293
|
def action_signature(action, data)
|
277
294
|
(+"#{self.class.name}##{action}").tap do |signature|
|
278
|
-
|
295
|
+
arguments = data.except("action")
|
296
|
+
|
297
|
+
if arguments.any?
|
298
|
+
arguments = parameter_filter.filter(arguments)
|
279
299
|
signature << "(#{arguments.inspect})"
|
280
300
|
end
|
281
301
|
end
|
282
302
|
end
|
283
303
|
|
304
|
+
def parameter_filter
|
305
|
+
@parameter_filter ||= ActiveSupport::ParameterFilter.new(connection.config.filter_parameters)
|
306
|
+
end
|
307
|
+
|
284
308
|
def transmit_subscription_confirmation
|
285
309
|
unless subscription_confirmation_sent?
|
286
310
|
logger.debug "#{self.class.name} is transmitting the subscription confirmation"
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :markup: markdown
|
4
|
+
|
3
5
|
require "active_support/core_ext/object/to_param"
|
4
6
|
|
5
7
|
module ActionCable
|
@@ -7,34 +9,41 @@ module ActionCable
|
|
7
9
|
module Broadcasting
|
8
10
|
extend ActiveSupport::Concern
|
9
11
|
|
10
|
-
delegate :broadcasting_for, :broadcast_to, to: :class
|
11
|
-
|
12
12
|
module ClassMethods
|
13
|
-
# Broadcast a hash to a unique broadcasting for this
|
13
|
+
# Broadcast a hash to a unique broadcasting for this `model` in this channel.
|
14
14
|
def broadcast_to(model, message)
|
15
15
|
ActionCable.server.broadcast(broadcasting_for(model), message)
|
16
16
|
end
|
17
17
|
|
18
|
-
# Returns a unique broadcasting identifier for this
|
18
|
+
# Returns a unique broadcasting identifier for this `model` in this channel:
|
19
19
|
#
|
20
|
-
#
|
20
|
+
# CommentsChannel.broadcasting_for("all") # => "comments:all"
|
21
21
|
#
|
22
|
-
# You can pass any object as a target (e.g. Active Record model), and it
|
23
|
-
#
|
22
|
+
# You can pass any object as a target (e.g. Active Record model), and it would
|
23
|
+
# be serialized into a string under the hood.
|
24
24
|
def broadcasting_for(model)
|
25
25
|
serialize_broadcasting([ channel_name, model ])
|
26
26
|
end
|
27
27
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
object.
|
32
|
-
|
33
|
-
object.to_gid_param
|
34
|
-
|
35
|
-
|
28
|
+
private
|
29
|
+
def serialize_broadcasting(object) # :nodoc:
|
30
|
+
case
|
31
|
+
when object.is_a?(Array)
|
32
|
+
object.map { |m| serialize_broadcasting(m) }.join(":")
|
33
|
+
when object.respond_to?(:to_gid_param)
|
34
|
+
object.to_gid_param
|
35
|
+
else
|
36
|
+
object.to_param
|
37
|
+
end
|
36
38
|
end
|
37
|
-
|
39
|
+
end
|
40
|
+
|
41
|
+
def broadcasting_for(model)
|
42
|
+
self.class.broadcasting_for(model)
|
43
|
+
end
|
44
|
+
|
45
|
+
def broadcast_to(model, message)
|
46
|
+
self.class.broadcast_to(model, message)
|
38
47
|
end
|
39
48
|
end
|
40
49
|
end
|
@@ -1,9 +1,40 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :markup: markdown
|
4
|
+
|
3
5
|
require "active_support/callbacks"
|
4
6
|
|
5
7
|
module ActionCable
|
6
8
|
module Channel
|
9
|
+
# # Action Cable Channel Callbacks
|
10
|
+
#
|
11
|
+
# Action Cable Channel provides callback hooks that are invoked during the life
|
12
|
+
# cycle of a channel:
|
13
|
+
#
|
14
|
+
# * [before_subscribe](rdoc-ref:ClassMethods#before_subscribe)
|
15
|
+
# * [after_subscribe](rdoc-ref:ClassMethods#after_subscribe) (aliased as
|
16
|
+
# [on_subscribe](rdoc-ref:ClassMethods#on_subscribe))
|
17
|
+
# * [before_unsubscribe](rdoc-ref:ClassMethods#before_unsubscribe)
|
18
|
+
# * [after_unsubscribe](rdoc-ref:ClassMethods#after_unsubscribe) (aliased as
|
19
|
+
# [on_unsubscribe](rdoc-ref:ClassMethods#on_unsubscribe))
|
20
|
+
#
|
21
|
+
#
|
22
|
+
# #### Example
|
23
|
+
#
|
24
|
+
# class ChatChannel < ApplicationCable::Channel
|
25
|
+
# after_subscribe :send_welcome_message, unless: :subscription_rejected?
|
26
|
+
# after_subscribe :track_subscription
|
27
|
+
#
|
28
|
+
# private
|
29
|
+
# def send_welcome_message
|
30
|
+
# broadcast_to(...)
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# def track_subscription
|
34
|
+
# # ...
|
35
|
+
# end
|
36
|
+
# end
|
37
|
+
#
|
7
38
|
module Callbacks
|
8
39
|
extend ActiveSupport::Concern
|
9
40
|
include ActiveSupport::Callbacks
|
@@ -18,6 +49,14 @@ module ActionCable
|
|
18
49
|
set_callback(:subscribe, :before, *methods, &block)
|
19
50
|
end
|
20
51
|
|
52
|
+
# This callback will be triggered after the Base#subscribed method is called,
|
53
|
+
# even if the subscription was rejected with the Base#reject method.
|
54
|
+
#
|
55
|
+
# To trigger the callback only on successful subscriptions, use the
|
56
|
+
# Base#subscription_rejected? method:
|
57
|
+
#
|
58
|
+
# after_subscribe :my_method, unless: :subscription_rejected?
|
59
|
+
#
|
21
60
|
def after_subscribe(*methods, &block)
|
22
61
|
set_callback(:subscribe, :after, *methods, &block)
|
23
62
|
end
|
@@ -1,25 +1,28 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :markup: markdown
|
4
|
+
|
3
5
|
module ActionCable
|
4
6
|
module Channel
|
5
7
|
module Naming
|
6
8
|
extend ActiveSupport::Concern
|
7
9
|
|
8
10
|
module ClassMethods
|
9
|
-
# Returns the name of the channel, underscored, without the
|
10
|
-
#
|
11
|
+
# Returns the name of the channel, underscored, without the `Channel` ending. If
|
12
|
+
# the channel is in a namespace, then the namespaces are represented by single
|
11
13
|
# colon separators in the channel name.
|
12
14
|
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
15
|
+
# ChatChannel.channel_name # => 'chat'
|
16
|
+
# Chats::AppearancesChannel.channel_name # => 'chats:appearances'
|
17
|
+
# FooChats::BarAppearancesChannel.channel_name # => 'foo_chats:bar_appearances'
|
16
18
|
def channel_name
|
17
19
|
@channel_name ||= name.delete_suffix("Channel").gsub("::", ":").underscore
|
18
20
|
end
|
19
21
|
end
|
20
22
|
|
21
|
-
|
22
|
-
|
23
|
+
def channel_name
|
24
|
+
self.class.channel_name
|
25
|
+
end
|
23
26
|
end
|
24
27
|
end
|
25
28
|
end
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# :markup: markdown
|
4
|
+
|
3
5
|
module ActionCable
|
4
6
|
module Channel
|
5
7
|
module PeriodicTimers
|
@@ -13,14 +15,12 @@ module ActionCable
|
|
13
15
|
end
|
14
16
|
|
15
17
|
module ClassMethods
|
16
|
-
# Periodically performs a task on the channel, like updating an online
|
17
|
-
#
|
18
|
-
#
|
19
|
-
# progress updates.
|
18
|
+
# Periodically performs a task on the channel, like updating an online user
|
19
|
+
# counter, polling a backend for new status messages, sending regular
|
20
|
+
# "heartbeat" messages, or doing some internal work and giving progress updates.
|
20
21
|
#
|
21
|
-
# Pass a method name or lambda argument or provide a block to call.
|
22
|
-
#
|
23
|
-
# keyword argument.
|
22
|
+
# Pass a method name or lambda argument or provide a block to call. Specify the
|
23
|
+
# calling period in seconds using the `every:` keyword argument.
|
24
24
|
#
|
25
25
|
# periodically :transmit_progress, every: 5.seconds
|
26
26
|
#
|