actioncable-next 0.2.0 → 0.3.0
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 +6 -0
- data/lib/action_cable/channel/base.rb +15 -3
- data/lib/action_cable/channel/broadcasting.rb +6 -6
- data/lib/action_cable/channel/callbacks.rb +7 -0
- data/lib/action_cable/channel/streams.rb +5 -3
- data/lib/action_cable/connection/identification.rb +0 -2
- data/lib/action_cable/connection/subscriptions.rb +1 -1
- data/lib/action_cable/connection/test_case.rb +2 -5
- data/lib/action_cable/gem_version.rb +3 -3
- data/lib/action_cable/server/base.rb +1 -1
- data/lib/action_cable/server/broadcasting.rb +6 -4
- data/lib/action_cable/server/worker.rb +1 -1
- data/lib/action_cable/subscription_adapter/base.rb +2 -1
- data/lib/action_cable/subscription_adapter/postgresql.rb +5 -6
- data/lib/action_cable/subscription_adapter/redis.rb +8 -3
- data/lib/actioncable-next.rb +1 -1
- data/lib/rails/generators/channel/channel_generator.rb +4 -4
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a3500aff266cab716b9cc6ef36748f32ecd4e6b5e1d24a1c8ce462c0e3e2dd9d
|
|
4
|
+
data.tar.gz: 74123e275958e25046b8a3a10ac7a3c2b5fa8066c63209baf591f3623100e867
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e6662409e60c2c0a2ac869771d05df9c620529a0cc92642e6bc3b5c953e1f78e3d64460953ecee186d713c8079e0b296fc25a8faadca646128a4c6b28f01c175
|
|
7
|
+
data.tar.gz: 588b659b2eddf199182e25bd7bec23f386621f97abdb169d33c81ac8022556cfa2ad8275cbaad3cf420c8f89306974843f47f851d7db3db0d37363f352d6e120
|
data/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
|
|
3
3
|
# :markup: markdown
|
|
4
4
|
|
|
5
|
-
require "set"
|
|
6
5
|
require "active_support/rescuable"
|
|
7
6
|
require "active_support/parameter_filter"
|
|
8
7
|
|
|
@@ -133,7 +132,10 @@ module ActionCable
|
|
|
133
132
|
# Except for public instance methods of Base and its ancestors
|
|
134
133
|
ActionCable::Channel::Base.public_instance_methods(true) +
|
|
135
134
|
# Be sure to include shadowed public instance methods of this class
|
|
136
|
-
public_instance_methods(false)
|
|
135
|
+
public_instance_methods(false) -
|
|
136
|
+
# Except the internal methods
|
|
137
|
+
internal_methods).uniq
|
|
138
|
+
methods.map!(&:name)
|
|
137
139
|
methods.to_set
|
|
138
140
|
end
|
|
139
141
|
end
|
|
@@ -146,6 +148,10 @@ module ActionCable
|
|
|
146
148
|
@action_methods = nil
|
|
147
149
|
end
|
|
148
150
|
|
|
151
|
+
def internal_methods
|
|
152
|
+
super
|
|
153
|
+
end
|
|
154
|
+
|
|
149
155
|
# Refresh the cached action_methods when a new action_method is added.
|
|
150
156
|
def method_added(name) # :doc:
|
|
151
157
|
super
|
|
@@ -166,6 +172,7 @@ module ActionCable
|
|
|
166
172
|
|
|
167
173
|
@reject_subscription = nil
|
|
168
174
|
@subscription_confirmation_sent = nil
|
|
175
|
+
@unsubscribed = false
|
|
169
176
|
|
|
170
177
|
delegate_connection_identifiers
|
|
171
178
|
end
|
|
@@ -190,7 +197,7 @@ module ActionCable
|
|
|
190
197
|
# confirms or rejects the subscription.
|
|
191
198
|
def subscribe_to_channel
|
|
192
199
|
run_callbacks :subscribe do
|
|
193
|
-
subscribed
|
|
200
|
+
subscribed unless subscription_rejected?
|
|
194
201
|
end
|
|
195
202
|
|
|
196
203
|
reject_subscription if subscription_rejected?
|
|
@@ -201,11 +208,16 @@ module ActionCable
|
|
|
201
208
|
# cleanup with callbacks. This method is not intended to be called directly by
|
|
202
209
|
# the user. Instead, override the #unsubscribed callback.
|
|
203
210
|
def unsubscribe_from_channel # :nodoc:
|
|
211
|
+
@unsubscribed = true
|
|
204
212
|
run_callbacks :unsubscribe do
|
|
205
213
|
unsubscribed
|
|
206
214
|
end
|
|
207
215
|
end
|
|
208
216
|
|
|
217
|
+
def unsubscribed? # :nodoc:
|
|
218
|
+
@unsubscribed
|
|
219
|
+
end
|
|
220
|
+
|
|
209
221
|
private
|
|
210
222
|
# Called once a consumer has become a subscriber of the channel. Usually the
|
|
211
223
|
# place to set up any streams you want this channel to be sending to the
|
|
@@ -10,19 +10,19 @@ module ActionCable
|
|
|
10
10
|
extend ActiveSupport::Concern
|
|
11
11
|
|
|
12
12
|
module ClassMethods
|
|
13
|
-
# Broadcast a hash to a unique broadcasting for this `
|
|
14
|
-
def broadcast_to(
|
|
15
|
-
ActionCable.server.broadcast(broadcasting_for(
|
|
13
|
+
# Broadcast a hash to a unique broadcasting for this array of `broadcastables` in this channel.
|
|
14
|
+
def broadcast_to(broadcastables, message)
|
|
15
|
+
ActionCable.server.broadcast(broadcasting_for(broadcastables), message)
|
|
16
16
|
end
|
|
17
17
|
|
|
18
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
|
|
22
|
+
# You can pass an array of objects as a target (e.g. Active Record model), and it would
|
|
23
23
|
# be serialized into a string under the hood.
|
|
24
|
-
def broadcasting_for(
|
|
25
|
-
serialize_broadcasting([ channel_name
|
|
24
|
+
def broadcasting_for(broadcastables)
|
|
25
|
+
serialize_broadcasting([ channel_name ] + Array(broadcastables))
|
|
26
26
|
end
|
|
27
27
|
|
|
28
28
|
private
|
|
@@ -39,6 +39,8 @@ module ActionCable
|
|
|
39
39
|
extend ActiveSupport::Concern
|
|
40
40
|
include ActiveSupport::Callbacks
|
|
41
41
|
|
|
42
|
+
INTERNAL_METHODS = [:_run_subscribe_callbacks, :_run_unsubscribe_callbacks] # :nodoc:
|
|
43
|
+
|
|
42
44
|
included do
|
|
43
45
|
define_callbacks :subscribe
|
|
44
46
|
define_callbacks :unsubscribe
|
|
@@ -70,6 +72,11 @@ module ActionCable
|
|
|
70
72
|
set_callback(:unsubscribe, :after, *methods, &block)
|
|
71
73
|
end
|
|
72
74
|
alias_method :on_unsubscribe, :after_unsubscribe
|
|
75
|
+
|
|
76
|
+
private
|
|
77
|
+
def internal_methods
|
|
78
|
+
INTERNAL_METHODS
|
|
79
|
+
end
|
|
73
80
|
end
|
|
74
81
|
end
|
|
75
82
|
end
|
|
@@ -88,6 +88,8 @@ module ActionCable
|
|
|
88
88
|
# callback. Defaults to `coder: nil` which does no decoding, passes raw
|
|
89
89
|
# messages.
|
|
90
90
|
def stream_from(broadcasting, callback = nil, coder: nil, &block)
|
|
91
|
+
return if unsubscribed?
|
|
92
|
+
|
|
91
93
|
broadcasting = String(broadcasting)
|
|
92
94
|
|
|
93
95
|
# Don't send the confirmation until pubsub#subscribe is successful
|
|
@@ -104,15 +106,15 @@ module ActionCable
|
|
|
104
106
|
end)
|
|
105
107
|
end
|
|
106
108
|
|
|
107
|
-
# Start streaming the pubsub queue for the `
|
|
109
|
+
# Start streaming the pubsub queue for the `broadcastables` in this channel. Optionally,
|
|
108
110
|
# you can pass a `callback` that'll be used instead of the default of just
|
|
109
111
|
# transmitting the updates straight to the subscriber.
|
|
110
112
|
#
|
|
111
113
|
# Pass `coder: ActiveSupport::JSON` to decode messages as JSON before passing to
|
|
112
114
|
# the callback. Defaults to `coder: nil` which does no decoding, passes raw
|
|
113
115
|
# messages.
|
|
114
|
-
def stream_for(
|
|
115
|
-
stream_from(broadcasting_for(
|
|
116
|
+
def stream_for(broadcastables, ...)
|
|
117
|
+
stream_from(broadcasting_for(broadcastables), ...)
|
|
116
118
|
end
|
|
117
119
|
|
|
118
120
|
# Unsubscribes streams from the named `broadcasting`.
|
|
@@ -142,11 +142,8 @@ module ActionCable
|
|
|
142
142
|
#
|
|
143
143
|
# ## Basic example
|
|
144
144
|
#
|
|
145
|
-
# Unit tests are written
|
|
146
|
-
#
|
|
147
|
-
# 1. Simulate a connection attempt by calling `connect`.
|
|
148
|
-
# 2. Assert state, e.g. identifiers, has been assigned.
|
|
149
|
-
#
|
|
145
|
+
# Unit tests are written by first simulating a connection attempt by calling
|
|
146
|
+
# `connect` and then asserting state, e.g. identifiers, have been assigned.
|
|
150
147
|
#
|
|
151
148
|
# class ApplicationCable::ConnectionTest < ActionCable::Connection::TestCase
|
|
152
149
|
# def test_connects_with_proper_cookie
|
|
@@ -10,7 +10,7 @@ module ActionCable
|
|
|
10
10
|
class ThreadedExecutor # :nodoc:
|
|
11
11
|
def initialize(max_size: 10)
|
|
12
12
|
@executor = Concurrent::ThreadPoolExecutor.new(
|
|
13
|
-
name: "ActionCable
|
|
13
|
+
name: "ActionCable-streamer",
|
|
14
14
|
min_threads: 1,
|
|
15
15
|
max_threads: max_size,
|
|
16
16
|
max_queue: 0,
|
|
@@ -21,10 +21,12 @@ module ActionCable
|
|
|
21
21
|
# ActionCable.server.broadcast \
|
|
22
22
|
# "web_notifications_1", { title: "New things!", body: "All that's fit for print" }
|
|
23
23
|
#
|
|
24
|
-
#
|
|
25
|
-
# App.cable.subscriptions.create
|
|
26
|
-
# received: (data)
|
|
27
|
-
# new Notification
|
|
24
|
+
# // Client-side JavaScript, which assumes you've already requested the right to send web notifications:
|
|
25
|
+
# App.cable.subscriptions.create("WebNotificationsChannel", {
|
|
26
|
+
# received: function(data) {
|
|
27
|
+
# new Notification(data['title'], { body: data['body'] });
|
|
28
|
+
# }
|
|
29
|
+
# });
|
|
28
30
|
module Broadcasting
|
|
29
31
|
# Broadcast a hash directly to a named `broadcasting`. This will later be JSON
|
|
30
32
|
# encoded.
|
|
@@ -36,18 +36,17 @@ module ActionCable
|
|
|
36
36
|
end
|
|
37
37
|
|
|
38
38
|
def with_subscriptions_connection(&block) # :nodoc:
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
end
|
|
39
|
+
# Action Cable is taking ownership over this database connection, and will
|
|
40
|
+
# perform the necessary cleanup tasks.
|
|
41
|
+
# We purposedly avoid #checkout to not end up with a pinned connection
|
|
42
|
+
ar_conn = ActiveRecord::Base.connection_pool.new_connection
|
|
44
43
|
pg_conn = ar_conn.raw_connection
|
|
45
44
|
|
|
46
45
|
verify!(pg_conn)
|
|
47
46
|
pg_conn.exec("SET application_name = #{pg_conn.escape_identifier(identifier)}")
|
|
48
47
|
yield pg_conn
|
|
49
48
|
ensure
|
|
50
|
-
ar_conn
|
|
49
|
+
ar_conn&.disconnect!
|
|
51
50
|
end
|
|
52
51
|
|
|
53
52
|
def with_broadcast_connection(&block) # :nodoc:
|
|
@@ -162,7 +162,7 @@ module ActionCable
|
|
|
162
162
|
begin
|
|
163
163
|
conn = @adapter.redis_connection_for_subscriptions
|
|
164
164
|
listen conn
|
|
165
|
-
rescue
|
|
165
|
+
rescue *CONNECTION_ERRORS => e
|
|
166
166
|
reset
|
|
167
167
|
if retry_connecting?
|
|
168
168
|
logger&.warn "Redis connection failed: #{e.message}. Trying to reconnect..."
|
|
@@ -211,7 +211,7 @@ module ActionCable
|
|
|
211
211
|
end
|
|
212
212
|
|
|
213
213
|
if ::Redis::VERSION < "5"
|
|
214
|
-
|
|
214
|
+
CONNECTION_ERRORS = [::Redis::BaseConnectionError].freeze
|
|
215
215
|
|
|
216
216
|
class SubscribedClient
|
|
217
217
|
def initialize(raw_client)
|
|
@@ -245,7 +245,12 @@ module ActionCable
|
|
|
245
245
|
SubscribedClient.new(conn._client)
|
|
246
246
|
end
|
|
247
247
|
else
|
|
248
|
-
|
|
248
|
+
CONNECTION_ERRORS = [
|
|
249
|
+
::Redis::BaseConnectionError,
|
|
250
|
+
|
|
251
|
+
# Some older versions of redis-rb sometime leak underlying exceptions
|
|
252
|
+
RedisClient::ConnectionError,
|
|
253
|
+
].freeze
|
|
249
254
|
|
|
250
255
|
def extract_subscribed_client(conn)
|
|
251
256
|
conn
|
data/lib/actioncable-next.rb
CHANGED
|
@@ -59,17 +59,17 @@ module Rails
|
|
|
59
59
|
def create_channel_javascript_file
|
|
60
60
|
channel_js_path = File.join("app/javascript/channels", class_path, "#{file_name}_channel")
|
|
61
61
|
js_template "javascript/channel", channel_js_path
|
|
62
|
-
gsub_file "#{channel_js_path}.js", /\.\/consumer/, "channels/consumer"
|
|
62
|
+
gsub_file "#{channel_js_path}.js", /\.\/consumer/, "channels/consumer" if using_importmap?
|
|
63
63
|
end
|
|
64
64
|
|
|
65
65
|
def import_channels_in_javascript_entrypoint
|
|
66
66
|
append_to_file "app/javascript/application.js",
|
|
67
|
-
|
|
67
|
+
using_importmap? ? %(import "channels"\n) : %(import "./channels"\n)
|
|
68
68
|
end
|
|
69
69
|
|
|
70
70
|
def import_channel_in_javascript_entrypoint
|
|
71
71
|
append_to_file "app/javascript/channels/index.js",
|
|
72
|
-
|
|
72
|
+
using_importmap? ? %(import "channels/#{file_name}_channel"\n) : %(import "./#{file_name}_channel"\n)
|
|
73
73
|
end
|
|
74
74
|
|
|
75
75
|
def install_javascript_dependencies
|
|
@@ -105,7 +105,7 @@ pin_all_from "app/javascript/channels", under: "channels"
|
|
|
105
105
|
end
|
|
106
106
|
|
|
107
107
|
def using_bun?
|
|
108
|
-
# Cannot assume
|
|
108
|
+
# Cannot assume Bun lockfile has been generated yet so we look for a file known to
|
|
109
109
|
# be generated by the jsbundling-rails gem
|
|
110
110
|
@using_bun ||= using_js_runtime? && root.join("bun.config.js").exist?
|
|
111
111
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: actioncable-next
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Pratik Naik
|
|
@@ -10,7 +10,7 @@ authors:
|
|
|
10
10
|
autorequire:
|
|
11
11
|
bindir: bin
|
|
12
12
|
cert_chain: []
|
|
13
|
-
date: 2025-
|
|
13
|
+
date: 2025-10-30 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: activesupport
|
|
@@ -167,7 +167,7 @@ licenses:
|
|
|
167
167
|
- MIT
|
|
168
168
|
metadata:
|
|
169
169
|
bug_tracker_uri: https://github.com/anycable/actioncable-next
|
|
170
|
-
changelog_uri: https://github.com/anycable/actioncable-next/blob/v0.
|
|
170
|
+
changelog_uri: https://github.com/anycable/actioncable-next/blob/v0.3.0/CHANGELOG.md
|
|
171
171
|
source_code_uri: https://github.com/anycable/actioncable-next
|
|
172
172
|
rubygems_mfa_required: 'true'
|
|
173
173
|
post_install_message:
|
|
@@ -178,7 +178,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
178
178
|
requirements:
|
|
179
179
|
- - ">="
|
|
180
180
|
- !ruby/object:Gem::Version
|
|
181
|
-
version: 3.
|
|
181
|
+
version: 3.2.0
|
|
182
182
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
183
183
|
requirements:
|
|
184
184
|
- - ">="
|