anycable-rails-core 1.6.0 → 1.6.2
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 +8 -0
- data/lib/anycable/rails/action_cable_ext/remote_connections.rb +1 -1
- data/lib/anycable/rails/compatibility.rb +1 -0
- data/lib/anycable/rails/config.rb +2 -0
- data/lib/anycable/rails/connection.rb +5 -1
- data/lib/anycable/rails/railtie.rb +1 -0
- data/lib/anycable/rails/socket_id_tracking.rb +2 -2
- data/lib/anycable/rails/version.rb +1 -1
- data/lib/generators/anycable/bin/templates/bin/anycable-go.tt +5 -0
- data/lib/generators/anycable/setup/setup_generator.rb +262 -35
- data/lib/generators/anycable/setup/templates/Procfile.dev.tt +2 -2
- data/lib/generators/anycable/setup/templates/anycable.toml.tt +40 -42
- data/lib/generators/anycable/setup/templates/bin/anycable-go.tt +5 -0
- data/lib/generators/anycable/setup/templates/bin/dev +17 -0
- data/lib/generators/anycable/setup/templates/config/anycable.yml.tt +18 -35
- data/lib/generators/anycable/setup/templates/config/cable.yml.tt +2 -5
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ae5f5e00ae334a317de5b59685ff57de668c2f102125f48bc8309a7330787950
|
|
4
|
+
data.tar.gz: f15f057412a3c0a0dbf759bd8c8d47abee1bee60a9b68ca62983ced577ea9397
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8b780c7ca124e8f84d708e94ec78a27b50e9b36cbf524264cea3582bb171b037e40f4f92d8292f115810b988dfe93d45a942c779550943484bfad9810c1865f3
|
|
7
|
+
data.tar.gz: 916571c822234a92ec9bbb1839c06c8a0cc9a6f434c370c0b9bccd6486a450c2dc2ec88e27069d3b14bff093e245d0a83e6aed71fc7bcd1f20b298ae479edde7
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
## main
|
|
4
4
|
|
|
5
|
+
## 1.6.2 (2026-04-02)
|
|
6
|
+
|
|
7
|
+
- Upgrade setup generator. ([@palkan][])
|
|
8
|
+
|
|
9
|
+
## 1.6.1 (2025-12-18)
|
|
10
|
+
|
|
11
|
+
- Ensure `bin/dist/anycable-go` has execution permission as part of `bin/anycable-go` ([@dmorgan-fa][])
|
|
12
|
+
|
|
5
13
|
## 1.6.0 (2025-03-18)
|
|
6
14
|
|
|
7
15
|
- Update `anycable:download` generator to support v1.6+. ([@palkan][])
|
|
@@ -6,7 +6,7 @@ ActionCable::RemoteConnections::RemoteConnection.include(AnyCable::Rails::Connec
|
|
|
6
6
|
ActionCable::RemoteConnections::RemoteConnection.prepend(Module.new do
|
|
7
7
|
def disconnect(reconnect: true)
|
|
8
8
|
# Legacy Action Cable functionality if case we're not fully migrated yet
|
|
9
|
-
super unless AnyCable::Rails.enabled?
|
|
9
|
+
return super unless AnyCable::Rails.enabled?
|
|
10
10
|
::AnyCable.broadcast_adapter.broadcast_command("disconnect", identifier: identifiers_json, reconnect: reconnect)
|
|
11
11
|
end
|
|
12
12
|
end)
|
|
@@ -9,6 +9,7 @@ require "anyway/rails"
|
|
|
9
9
|
# - `access_logs_disabled` (defaults to true) — whether to print Started/Finished logs
|
|
10
10
|
# - `persistent_session_enabled` (defaults to false) — whether to store session changes in the connection state
|
|
11
11
|
# - `embedded` (defaults to false) — whether to run RPC server inside a Rails server process
|
|
12
|
+
# - `http_rpc` (default to false) - whether to mount HTTP RPC server or not
|
|
12
13
|
# - `http_rpc_mount_path` (defaults to nil) — path to mount HTTP RPC server
|
|
13
14
|
# - `batch_broadcasts` (defaults to false) — whether to batch broadcasts automatically for code wrapped with Rails executor
|
|
14
15
|
# - `jwt_param` (defaults to 'jid') — the name of the JWT authentication query paramter or header
|
|
@@ -18,6 +19,7 @@ AnyCable::Config.attr_config(
|
|
|
18
19
|
persistent_session_enabled: false,
|
|
19
20
|
embedded: false,
|
|
20
21
|
jwt_param: "jid",
|
|
22
|
+
http_rpc: false,
|
|
21
23
|
http_rpc_mount_path: nil,
|
|
22
24
|
batch_broadcasts: false,
|
|
23
25
|
socket_id_header: "X-Socket-ID",
|
|
@@ -80,7 +80,11 @@ module AnyCable
|
|
|
80
80
|
|
|
81
81
|
def subscription_class_from_identifier(id_key)
|
|
82
82
|
id_options = ActiveSupport::JSON.decode(id_key).with_indifferent_access
|
|
83
|
-
id_options[:channel]
|
|
83
|
+
if id_options[:channel] == "$pubsub"
|
|
84
|
+
PubSubChannel
|
|
85
|
+
else
|
|
86
|
+
id_options[:channel].safe_constantize
|
|
87
|
+
end
|
|
84
88
|
end
|
|
85
89
|
|
|
86
90
|
def subscription_from_identifier(id_key)
|
|
@@ -113,6 +113,7 @@ module AnyCable
|
|
|
113
113
|
initializer "anycable.routes" do
|
|
114
114
|
config.after_initialize do |app|
|
|
115
115
|
config = AnyCable.config
|
|
116
|
+
config.http_rpc_mount_path ||= "/_anycable" if config.http_rpc?
|
|
116
117
|
unless config.http_rpc_mount_path.nil?
|
|
117
118
|
app.routes.prepend do
|
|
118
119
|
mount AnyCable::HTTRPC::Server.new => config.http_rpc_mount_path, :internal => true
|
|
@@ -11,8 +11,8 @@ module AnyCable
|
|
|
11
11
|
|
|
12
12
|
private
|
|
13
13
|
|
|
14
|
-
def anycable_tracking_socket_id(&)
|
|
15
|
-
Rails.with_socket_id(request.headers[AnyCable.config.socket_id_header], &)
|
|
14
|
+
def anycable_tracking_socket_id(&block)
|
|
15
|
+
Rails.with_socket_id(request.headers[AnyCable.config.socket_id_header], &block)
|
|
16
16
|
end
|
|
17
17
|
end
|
|
18
18
|
|
|
@@ -10,6 +10,11 @@ if [ ! -f ./bin/dist/anycable-go ]; then
|
|
|
10
10
|
./bin/rails g anycable:download --version=$version --bin-path=./bin/dist
|
|
11
11
|
fi
|
|
12
12
|
|
|
13
|
+
if [ -x ./bin/dist/anycable-go ]; then
|
|
14
|
+
echo "Setting execution permission for AnyCable server"
|
|
15
|
+
chmod +x ./bin/dist/anycable-go
|
|
16
|
+
fi
|
|
17
|
+
|
|
13
18
|
curVersion=$(./bin/dist/anycable-go -v)
|
|
14
19
|
|
|
15
20
|
if [[ "$version" != "latest" ]]; then
|
|
@@ -9,11 +9,11 @@ module AnyCableRailsGenerators
|
|
|
9
9
|
source_root File.expand_path("templates", __dir__)
|
|
10
10
|
|
|
11
11
|
DOCS_ROOT = "https://docs.anycable.io"
|
|
12
|
-
DEVELOPMENT_METHODS = %w[skip
|
|
13
|
-
DEPLOYMENT_METHODS = %w[
|
|
12
|
+
DEVELOPMENT_METHODS = %w[skip bin docker].freeze
|
|
13
|
+
DEPLOYMENT_METHODS = %w[skip thruster fly heroku anycable_plus].freeze
|
|
14
14
|
RPC_IMPL = %w[none grpc http].freeze
|
|
15
15
|
|
|
16
|
-
class_option :
|
|
16
|
+
class_option :development,
|
|
17
17
|
type: :string,
|
|
18
18
|
desc: "Select your development environment (options: #{DEVELOPMENT_METHODS.reverse.join(", ")})"
|
|
19
19
|
class_option :rpc,
|
|
@@ -31,37 +31,85 @@ module AnyCableRailsGenerators
|
|
|
31
31
|
say ""
|
|
32
32
|
say "👋 Welcome to AnyCable interactive installer. We'll guide you through the process of installing AnyCable for your Rails application. Buckle up!"
|
|
33
33
|
say ""
|
|
34
|
+
@todos = []
|
|
34
35
|
end
|
|
35
36
|
|
|
36
37
|
def rpc_implementation
|
|
37
|
-
|
|
38
|
-
|
|
38
|
+
if RPC_IMPL.include?(options[:rpc])
|
|
39
|
+
@rpc_impl = options[:rpc]
|
|
40
|
+
return
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
if hotwire? && !custom_channels?
|
|
44
|
+
say_status :info, <<~MSG
|
|
45
|
+
⚡️ Hotwire application has been detected, installing AnyCable in a standalone mode.
|
|
46
|
+
MSG
|
|
47
|
+
@rpc_impl = "none"
|
|
48
|
+
return
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
if custom_channels?
|
|
52
|
+
answer = RPC_IMPL.index(options[:rpc]) || 99
|
|
53
|
+
|
|
54
|
+
unless RPC_IMPL[answer.to_i]
|
|
55
|
+
say ""
|
|
56
|
+
say <<~MSG
|
|
57
|
+
AnyCable connects to your Rails server to communicate with Action Cable channels either via HTTP or gRPC.
|
|
39
58
|
|
|
40
|
-
|
|
59
|
+
gRPC provides better performance and scalability but requires running
|
|
60
|
+
a separate component (a gRPC server).
|
|
41
61
|
|
|
42
|
-
|
|
43
|
-
|
|
62
|
+
HTTP is a good option for a quick start or in case your deployment platform doesn't
|
|
63
|
+
support running multiple web services (e.g., Heroku).
|
|
64
|
+
|
|
65
|
+
If you only use Action Cable for Turbo Streams, you don't need RPC at all.
|
|
66
|
+
|
|
67
|
+
Learn more from the docs 👉 #{DOCS_ROOT}/anycable-go/rpc
|
|
68
|
+
MSG
|
|
69
|
+
say ""
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
answer = ask "Which RPC implementation would you like to use?", limited_to: %w[grpc http none], default: "grpc"
|
|
73
|
+
|
|
74
|
+
@rpc_impl = answer
|
|
75
|
+
return
|
|
44
76
|
end
|
|
45
77
|
|
|
46
|
-
|
|
78
|
+
# no Hotwire, no custom channels
|
|
79
|
+
say_status :info, "Looks like you don't have any real-time functionality yet. Let's start with a miminal AnyCable setup!"
|
|
80
|
+
@rpc_impl = "none"
|
|
47
81
|
end
|
|
48
82
|
|
|
49
83
|
def development_method
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
84
|
+
if DEVELOPMENT_METHODS.include?(options[:development])
|
|
85
|
+
@development = options[:development]
|
|
86
|
+
end
|
|
53
87
|
|
|
54
|
-
|
|
55
|
-
|
|
88
|
+
# Fast-track for local development
|
|
89
|
+
if file_exists?("bin/dev") && file_exists?("Procfile.dev")
|
|
90
|
+
@development = "bin"
|
|
56
91
|
end
|
|
57
92
|
|
|
58
|
-
@
|
|
93
|
+
unless @development
|
|
94
|
+
say ""
|
|
95
|
+
say <<~MSG
|
|
96
|
+
You can run AnyCable server locally (recommended for most cases) or as a Docker container (in case you develop in a containerized environment).
|
|
97
|
+
|
|
98
|
+
For a local installation, we provide a convenient binstub (`bin/anycable-go`) which automatically
|
|
99
|
+
installs AnyCable server for the current platform.
|
|
100
|
+
MSG
|
|
101
|
+
say ""
|
|
102
|
+
|
|
103
|
+
answer = ask "Which way to run AnyCable server locally would you prefer?", limited_to: %w[bin docker skip], default: "bin"
|
|
104
|
+
|
|
105
|
+
@development = answer
|
|
106
|
+
end
|
|
59
107
|
|
|
60
|
-
case @
|
|
108
|
+
case @development
|
|
61
109
|
when "skip"
|
|
62
|
-
|
|
110
|
+
@todos << "Install AnyCable server for local development: #{DOCS_ROOT}/anycable-go/getting_started"
|
|
63
111
|
else
|
|
64
|
-
send "install_for_#{@
|
|
112
|
+
send "install_for_#{@development}"
|
|
65
113
|
end
|
|
66
114
|
end
|
|
67
115
|
|
|
@@ -80,29 +128,112 @@ module AnyCableRailsGenerators
|
|
|
80
128
|
|
|
81
129
|
say_status :info, "🤖 Running static compatibility checks with RuboCop"
|
|
82
130
|
res = run "bundle exec rubocop -r 'anycable/rails/compatibility/rubocop' --only AnyCable/InstanceVars,AnyCable/PeriodicalTimers,AnyCable/InstanceVars"
|
|
83
|
-
|
|
131
|
+
|
|
132
|
+
unless res
|
|
133
|
+
say_status :help, "⚠️ Please, take a look at the incompatibilities above and fix them"
|
|
134
|
+
|
|
135
|
+
@todos << "Fix Action Cable compatibility issues (listed above): #{DOCS_ROOT}/rails/compatibility"
|
|
136
|
+
end
|
|
84
137
|
end
|
|
85
138
|
|
|
86
139
|
def cable_url_info
|
|
87
|
-
|
|
88
|
-
|
|
140
|
+
meta_tag = norpc? ? "action_cable_with_jwt_meta_tag" : "action_cable_meta_tag"
|
|
141
|
+
|
|
142
|
+
begin
|
|
143
|
+
app_layout = nil
|
|
144
|
+
inside("app/views/layouts") do
|
|
145
|
+
next unless File.file?("application.html.erb")
|
|
146
|
+
app_layout = File.read("application.html.erb")
|
|
147
|
+
end
|
|
148
|
+
return if app_layout&.include?(meta_tag)
|
|
149
|
+
|
|
150
|
+
if norpc? && app_layout&.include?("action_cable_meta_tag")
|
|
151
|
+
gsub_file "app/views/layouts/application.html.erb", %r{^\s+<%= action_cable_meta_tag %>.*$} do |match|
|
|
152
|
+
match.sub("action_cable_meta_tag", "action_cable_with_jwt_meta_tag")
|
|
153
|
+
end
|
|
154
|
+
inform_jwt_identifiers("app/views/layouts/application.html.erb")
|
|
155
|
+
return
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
found = false
|
|
159
|
+
gsub_file "app/views/layouts/application.html.erb", %r{^\s+<%= csp_meta_tag %>.*$} do |match|
|
|
160
|
+
found = true
|
|
161
|
+
match << "\n <%= #{meta_tag} %>"
|
|
162
|
+
end
|
|
163
|
+
if found
|
|
164
|
+
inform_jwt_identifiers("app/views/layouts/application.html.erb") if norpc?
|
|
165
|
+
return
|
|
166
|
+
end
|
|
167
|
+
rescue Errno::ENOENT
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
@todos << "⚠️ Ensure you have `action_cable_meta_tag`\n" \
|
|
171
|
+
" or `action_cable_with_jwt_meta_tag` included in your HTML layout:\n" \
|
|
172
|
+
" 👉 https://docs.anycable.io/rails/getting_started"
|
|
89
173
|
end
|
|
90
174
|
|
|
91
|
-
def
|
|
175
|
+
def action_cable_engine
|
|
92
176
|
return unless application_rb
|
|
93
177
|
return if application_rb.match?(/^require\s+['"](action_cable\/engine|rails\/all)['"]/)
|
|
94
178
|
|
|
95
|
-
|
|
179
|
+
found = false
|
|
180
|
+
gsub_file "config/application.rb", %r{^require ['"]rails['"].*$} do |match|
|
|
181
|
+
found = true
|
|
182
|
+
match << %(\nrequire "action_cable/engine")
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
return if found
|
|
186
|
+
|
|
187
|
+
@todos << "⚠️ Ensure Action Cable is loaded. Add `require \"action_cable/engine\"` to your `config/application.rb` file"
|
|
96
188
|
end
|
|
97
189
|
|
|
98
|
-
def
|
|
99
|
-
|
|
190
|
+
def anycable_client
|
|
191
|
+
if hotwire? && install_js_packages
|
|
192
|
+
gsub_file "app/javascript/application.js", /^import "@hotwired\/turbo-rails".*$/, <<~JS
|
|
193
|
+
import "@hotwired/turbo"
|
|
194
|
+
import { createCable } from "@anycable/web"
|
|
195
|
+
import { start } from "@anycable/turbo-stream"
|
|
196
|
+
|
|
197
|
+
// Use extended Action Cable protocol to support reliable streams and presence
|
|
198
|
+
// See https://github.com/anycable/anycable-client
|
|
199
|
+
const cable = createCable({ protocol: 'actioncable-v1-ext-json' })
|
|
200
|
+
// Prevent frequent resubscriptions during morphing or navigation
|
|
201
|
+
start(cable, { delayedUnsubscribe: true })
|
|
202
|
+
JS
|
|
203
|
+
return
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
@todos << "⚠️ Install AnyCable JS client to use advanced features (presence, reliable streams): 👉 https://github.com/anycable/anycable-client\n"
|
|
207
|
+
end
|
|
100
208
|
|
|
101
|
-
|
|
209
|
+
def turbo_verifier_key
|
|
210
|
+
return unless hotwire?
|
|
211
|
+
return if application_rb.include?("config.turbo.signed_stream_verifier_key = AnyCable.config.secret")
|
|
212
|
+
|
|
213
|
+
gsub_file "config/application.rb", %r{\s+end\nend} do |match|
|
|
214
|
+
"\n\n" \
|
|
215
|
+
" # Use AnyCable secret to sign Turbo Streams\n" \
|
|
216
|
+
" # #{DOCS_ROOT}/guides/hotwire?id=rails-applications\n" \
|
|
217
|
+
" config.turbo.signed_stream_verifier_key = AnyCable.config.secret#{match}"
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def deployment_method
|
|
222
|
+
@todos << "🚢 Learn how to run AnyCable in production: 👉 #{DOCS_ROOT}/deployment\n" \
|
|
223
|
+
" For the quick start, consider using AnyCable+ (https://plus.anycable.io)\n" \
|
|
224
|
+
" or AnyCable Thruster (https://github.com/anycable/thruster)"
|
|
102
225
|
end
|
|
103
226
|
|
|
104
227
|
def finish
|
|
105
|
-
say_status :info, "✅ AnyCable has been configured
|
|
228
|
+
say_status :info, "✅ AnyCable has been configured"
|
|
229
|
+
|
|
230
|
+
if @todos.any?
|
|
231
|
+
say ""
|
|
232
|
+
say "📋 Please, check the following actions required to complete the setup:\n"
|
|
233
|
+
@todos.each do |todo|
|
|
234
|
+
say "- [ ] #{todo}"
|
|
235
|
+
end
|
|
236
|
+
end
|
|
106
237
|
end
|
|
107
238
|
|
|
108
239
|
private
|
|
@@ -124,7 +255,7 @@ module AnyCableRailsGenerators
|
|
|
124
255
|
end
|
|
125
256
|
|
|
126
257
|
def local?
|
|
127
|
-
@
|
|
258
|
+
@development == "local"
|
|
128
259
|
end
|
|
129
260
|
|
|
130
261
|
def grpc?
|
|
@@ -135,6 +266,26 @@ module AnyCableRailsGenerators
|
|
|
135
266
|
@rpc_impl == "http"
|
|
136
267
|
end
|
|
137
268
|
|
|
269
|
+
def norpc?
|
|
270
|
+
@rpc_impl == "none"
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
def hotwire?
|
|
274
|
+
!!gemfile_lock&.match?(/^\s+turbo-rails\b/) &&
|
|
275
|
+
application_js&.match?(/^import\s+"@hotwired\/turbo/)
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
def custom_channels?
|
|
279
|
+
@has_custom_channels ||= begin
|
|
280
|
+
res = nil
|
|
281
|
+
in_root do
|
|
282
|
+
next unless File.directory?("app/channels")
|
|
283
|
+
res = Dir["app/channels/*_channel.rb"].any?
|
|
284
|
+
end
|
|
285
|
+
res
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
|
|
138
289
|
def gemfile_lock
|
|
139
290
|
@gemfile_lock ||= begin
|
|
140
291
|
res = nil
|
|
@@ -157,6 +308,17 @@ module AnyCableRailsGenerators
|
|
|
157
308
|
end
|
|
158
309
|
end
|
|
159
310
|
|
|
311
|
+
def application_js
|
|
312
|
+
@application_js ||= begin
|
|
313
|
+
res = nil
|
|
314
|
+
in_root do
|
|
315
|
+
next unless File.file?("app/javascript/application.js")
|
|
316
|
+
res = File.read("app/javascript/application.js")
|
|
317
|
+
end
|
|
318
|
+
res
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
|
|
160
322
|
def install_for_docker
|
|
161
323
|
say_status :help, "️️⚠️ Docker development configuration could vary", :yellow
|
|
162
324
|
|
|
@@ -179,7 +341,7 @@ module AnyCableRailsGenerators
|
|
|
179
341
|
condition: service_started
|
|
180
342
|
|
|
181
343
|
ws:
|
|
182
|
-
image: anycable/anycable-go:1.
|
|
344
|
+
image: anycable/anycable-go:1.6
|
|
183
345
|
ports:
|
|
184
346
|
- '8080:8080'
|
|
185
347
|
- '8090'
|
|
@@ -235,11 +397,12 @@ module AnyCableRailsGenerators
|
|
|
235
397
|
end
|
|
236
398
|
end
|
|
237
399
|
|
|
238
|
-
def
|
|
400
|
+
def install_for_bin
|
|
239
401
|
unless file_exists?("bin/anycable-go")
|
|
240
402
|
generate "anycable:bin", "--version #{options[:version]}"
|
|
241
403
|
end
|
|
242
404
|
template_proc_files
|
|
405
|
+
update_bin_dev
|
|
243
406
|
true
|
|
244
407
|
end
|
|
245
408
|
|
|
@@ -252,7 +415,23 @@ module AnyCableRailsGenerators
|
|
|
252
415
|
adapter = Regexp.last_match[1]
|
|
253
416
|
next match if adapter == "test" || adapter.include?("any_cable")
|
|
254
417
|
|
|
255
|
-
match.sub(adapter,
|
|
418
|
+
match.sub(adapter, "any_cable")
|
|
419
|
+
end
|
|
420
|
+
|
|
421
|
+
# Try removing all lines contaning options for previous adapters,
|
|
422
|
+
# only keep aliases (<<:*), adapter and channel_prefix options.
|
|
423
|
+
new_clean_contents = new_contents.lines.select do |line|
|
|
424
|
+
line.match?(/^(\S|\s+adapter:|\s+channel_prefix:|\s+<<:)/) || line.match?(/^\s*$/)
|
|
425
|
+
end.join
|
|
426
|
+
|
|
427
|
+
# Verify new config
|
|
428
|
+
begin
|
|
429
|
+
clean_config = YAML.safe_load(new_clean_contents, aliases: true).deep_symbolize_keys
|
|
430
|
+
orig_config = YAML.safe_load(contents, aliases: true).deep_symbolize_keys
|
|
431
|
+
|
|
432
|
+
new_contents = new_clean_contents if clean_config.keys == orig_config.keys
|
|
433
|
+
rescue => _e
|
|
434
|
+
# something went wrong, keep older options
|
|
256
435
|
end
|
|
257
436
|
|
|
258
437
|
File.write "config/cable.yml", new_contents
|
|
@@ -270,8 +449,6 @@ module AnyCableRailsGenerators
|
|
|
270
449
|
if file_exists?(file_name)
|
|
271
450
|
update_procfile(file_name)
|
|
272
451
|
else
|
|
273
|
-
say_status :help, "💡 We recommend using Overmind to manage multiple processes in development 👉 https://github.com/DarthSim/overmind", :yellow
|
|
274
|
-
|
|
275
452
|
return if options[:skip_procfile_dev]
|
|
276
453
|
|
|
277
454
|
template file_name
|
|
@@ -282,13 +459,36 @@ module AnyCableRailsGenerators
|
|
|
282
459
|
in_root do
|
|
283
460
|
contents = File.read(file_name)
|
|
284
461
|
|
|
285
|
-
|
|
462
|
+
if grpc?
|
|
286
463
|
unless contents.match?(/^anycable:\s/)
|
|
287
464
|
append_file file_name, "anycable: bundle exec anycable\n", force: true
|
|
288
465
|
end
|
|
289
466
|
end
|
|
290
467
|
unless contents.match?(/^ws:\s/)
|
|
291
|
-
append_file file_name, "ws: bin/anycable-go", force: true
|
|
468
|
+
append_file file_name, "ws: bin/anycable-go --port 8080", force: true
|
|
469
|
+
end
|
|
470
|
+
end
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
def update_bin_dev
|
|
474
|
+
unless file_exists?("bin/dev")
|
|
475
|
+
template "bin/dev"
|
|
476
|
+
chmod "bin/dev", 0755, verbose: false # rubocop:disable Style/NumericLiteralPrefix
|
|
477
|
+
|
|
478
|
+
@todos << "Now you should use bin/dev to run your application with AnyCable services"
|
|
479
|
+
return
|
|
480
|
+
end
|
|
481
|
+
|
|
482
|
+
in_root do
|
|
483
|
+
contents = File.read("bin/dev")
|
|
484
|
+
|
|
485
|
+
return if contents.include?("Procfile.dev")
|
|
486
|
+
|
|
487
|
+
if contents.include?(%(exec "./bin/rails"))
|
|
488
|
+
template "bin/dev", force: true
|
|
489
|
+
chmod "bin/dev", 0755, verbose: false # rubocop:disable Style/NumericLiteralPrefix
|
|
490
|
+
else
|
|
491
|
+
@todos << "Please, check your bin/dev file and ensure it runs Procfile.dev with AnyCable services"
|
|
292
492
|
end
|
|
293
493
|
end
|
|
294
494
|
end
|
|
@@ -298,5 +498,32 @@ module AnyCableRailsGenerators
|
|
|
298
498
|
return File.file?(name)
|
|
299
499
|
end
|
|
300
500
|
end
|
|
501
|
+
|
|
502
|
+
def inform_jwt_identifiers(path)
|
|
503
|
+
return unless file_exists?("app/channels/application_cable/connection.rb")
|
|
504
|
+
|
|
505
|
+
in_root do
|
|
506
|
+
contents = File.read("app/channels/application_cable/connection.rb")
|
|
507
|
+
|
|
508
|
+
if contents.match?(%r{^\s+identified_by\s})
|
|
509
|
+
@todos << "⚠️ Please, provide the correct connection identifiers to the #action_cable_with_jwt_meta_tag in #{path}. Read more: 👉 #{DOCS_ROOT}/rails/authentication?id=jwt-authentication"
|
|
510
|
+
end
|
|
511
|
+
end
|
|
512
|
+
end
|
|
513
|
+
|
|
514
|
+
def install_js_packages
|
|
515
|
+
if file_exists?("config/importmap.rb") && file_exists?("bin/importmap")
|
|
516
|
+
run "bin/importmap pin @hotwired/turbo @anycable/web @anycable/turbo-stream"
|
|
517
|
+
elsif file_exists?("yarn.lock")
|
|
518
|
+
run "yarn add @anycable/web @anycable/turbo-stream"
|
|
519
|
+
elsif file_exists?("package-json.lock")
|
|
520
|
+
run "npm install @anycable/web @anycable/turbo-stream"
|
|
521
|
+
else
|
|
522
|
+
false
|
|
523
|
+
end
|
|
524
|
+
rescue => e
|
|
525
|
+
say_status :warn, "Failed to install JS packages: #{e.message}. Skipping..."
|
|
526
|
+
false
|
|
527
|
+
end
|
|
301
528
|
end
|
|
302
529
|
end
|
|
@@ -1,14 +1,25 @@
|
|
|
1
|
-
# AnyCable server configuration
|
|
1
|
+
# AnyCable server configuration.
|
|
2
2
|
#
|
|
3
3
|
# Read more at https://docs.anycable.io/anycable-go/configuration
|
|
4
4
|
|
|
5
5
|
# Public mode disables connection authentication, pub/sub streams and broadcasts verification
|
|
6
6
|
# public = false
|
|
7
7
|
|
|
8
|
-
# The application secret key
|
|
8
|
+
# The application secret key: it's used to verify JWT tokens, signed streams, etc.
|
|
9
|
+
# In development, it MUST match the value in the `config/anycable.yml`.
|
|
10
|
+
# IMPORTANT: Make sure you provided a secret in production via the ANYCABLE_SECRET env var
|
|
11
|
+
# if you use this configuration file.
|
|
9
12
|
secret = "anycable-local-secret"
|
|
10
13
|
|
|
11
|
-
#
|
|
14
|
+
# Enable AnyCable power features such as reliable streams, presence and resumable sessions.
|
|
15
|
+
# Read more:
|
|
16
|
+
# - https://docs.anycable.io/anycable-go/reliable_streams
|
|
17
|
+
# - https://docs.anycable.io/anycable-go/presence
|
|
18
|
+
presets = ["broker"]
|
|
19
|
+
|
|
20
|
+
# Broadcasting adapters for app-to-clients messages.
|
|
21
|
+
# You one of the specified adapters in the config/anycable.yml.
|
|
22
|
+
# Read more in https://docs.anycable.io/anycable-go/broadcasting.
|
|
12
23
|
<%- if redis? -%>
|
|
13
24
|
broadcast_adapters = ["http", "redisx"]
|
|
14
25
|
<%- elsif nats? -%>
|
|
@@ -17,67 +28,54 @@ broadcast_adapters = ["http", "nats"]
|
|
|
17
28
|
broadcast_adapters = ["http"]
|
|
18
29
|
<%- end -%>
|
|
19
30
|
|
|
20
|
-
# Pub/sub adapter for inter-node communication
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
<%- elsif nats? -%>
|
|
24
|
-
pubsub_adapter = "nats"
|
|
25
|
-
<%- else -%>
|
|
31
|
+
# Pub/sub adapter for inter-node communication in a production cluster
|
|
32
|
+
# IMPORTANT: In production, when running AnyCable in a cluster mode,
|
|
33
|
+
# make sure to enable pub/sub adapter via the ANYCABLE_PUBSUB_ADAPTER env var
|
|
26
34
|
# pubsub_adapter = "redis" # or "nats"
|
|
27
|
-
<%- end -%>
|
|
28
|
-
|
|
29
|
-
[server]
|
|
30
|
-
host = "localhost"
|
|
31
|
-
port = 8080
|
|
32
35
|
|
|
33
36
|
[logging]
|
|
34
37
|
debug = true
|
|
35
38
|
|
|
36
|
-
#
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
history_ttl = 300
|
|
40
|
-
history_limit = 100
|
|
41
|
-
sessions_ttl = 300
|
|
42
|
-
|
|
39
|
+
# RPC is used to authorized subscriptions and perform channel actions.
|
|
40
|
+
# You only need it if you use custom Action Cable channel classes.
|
|
41
|
+
# Read more: https://docs.anycable.io/anycable-go/rpc
|
|
43
42
|
[rpc]
|
|
44
43
|
<%- if http_rpc? -%>
|
|
44
|
+
# IMPORTANT: In production, provide the URL of the RPC service via the ANYCABLE_RPC_HOST env variable
|
|
45
45
|
host = "http://localhost:3000/_anycable"
|
|
46
|
-
<%-
|
|
46
|
+
<%- elsif grpc? -%>
|
|
47
47
|
host = "localhost:50051"
|
|
48
|
+
<%- else -%>
|
|
49
|
+
# AnyCable is running in a standalone mode.
|
|
50
|
+
# Read more: https://docs.anycable.io/anycable-go/getting_started?id=standalone-mode-pubsub-only
|
|
51
|
+
implementation = "none"
|
|
48
52
|
<%- end -%>
|
|
49
|
-
# Specify HTTP headers that must be proxied to the RPC service
|
|
50
|
-
proxy_headers = ["cookie"]
|
|
51
|
-
# RPC concurrency (max number of concurrent RPC requests)
|
|
52
|
-
concurrency = 28
|
|
53
53
|
|
|
54
|
-
# Read more about AnyCable JWT: https://docs.anycable.io/anycable-go/jwt_identification
|
|
55
|
-
[jwt]
|
|
56
|
-
# param = "jid"
|
|
57
|
-
# force = true
|
|
58
54
|
|
|
59
|
-
#
|
|
55
|
+
# Signed and public streams configuration.
|
|
56
|
+
# Read more: https://docs.anycable.io/anycable-go/signed_streams
|
|
60
57
|
[streams]
|
|
61
58
|
# Enable public (unsigned) streams
|
|
62
59
|
# public = true
|
|
63
60
|
# Enable whispering support for pub/sub streams
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
#
|
|
67
|
-
#
|
|
61
|
+
whisper = true
|
|
62
|
+
#
|
|
63
|
+
# Authorize Turbo Streams at the AnyCable server side.
|
|
64
|
+
# IMPORTANT: Make sure your Turbo verifier key is the same as AnyCable secret.
|
|
65
|
+
# Add this line to your Rails configuration (if missing):
|
|
66
|
+
#
|
|
67
|
+
# config.turbo.signed_stream_verifier_key = AnyCable.config.secret
|
|
68
|
+
#
|
|
69
|
+
turbo = true
|
|
68
70
|
|
|
69
|
-
[redis]
|
|
70
71
|
<%- if redis? -%>
|
|
72
|
+
[redis]
|
|
73
|
+
# IMPORTANT: In production, provide Redis address via the REDIS_URL or ANYCABLE_REDIS_URL env var
|
|
71
74
|
url = "redis://localhost:6379"
|
|
72
|
-
<%- else -%>
|
|
73
|
-
# url = "redis://localhost:6379"
|
|
74
75
|
<%- end -%>
|
|
75
76
|
|
|
76
77
|
<%- if nats? -%>
|
|
77
78
|
[nats]
|
|
79
|
+
# IMPORTANT: In production, provide NATS address via the ANYCABLE_NATS_SERVERS env var
|
|
78
80
|
servers = "nats://127.0.0.1:4222"
|
|
79
81
|
<%- end -%>
|
|
80
|
-
|
|
81
|
-
[http_broadcast]
|
|
82
|
-
port = 8090
|
|
83
|
-
path = "/_broadcast"
|
|
@@ -10,6 +10,11 @@ if [ ! -f ./bin/dist/anycable-go ]; then
|
|
|
10
10
|
./bin/rails g anycable:download --version=$version --bin-path=./bin/dist
|
|
11
11
|
fi
|
|
12
12
|
|
|
13
|
+
if [ -x ./bin/dist/anycable-go ]; then
|
|
14
|
+
echo "Setting execution permission for AnyCable server"
|
|
15
|
+
chmod +x ./bin/dist/anycable-go
|
|
16
|
+
fi
|
|
17
|
+
|
|
13
18
|
curVersion=$(./bin/dist/anycable-go -v)
|
|
14
19
|
|
|
15
20
|
if [[ "$version" != "latest" ]]; then
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
#!/usr/bin/env sh
|
|
2
|
+
|
|
3
|
+
# Let the debug gem allow remote connections,
|
|
4
|
+
# but avoid loading until `debugger` is called
|
|
5
|
+
export RUBY_DEBUG_OPEN="true"
|
|
6
|
+
export RUBY_DEBUG_LAZY="true"
|
|
7
|
+
|
|
8
|
+
if ! command -v overmind &> /dev/null; then
|
|
9
|
+
if ! gem list foreman -i --silent; then
|
|
10
|
+
echo "Installing foreman..."
|
|
11
|
+
gem install foreman
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
exec foreman start -f Procfile.dev "$@"
|
|
15
|
+
else
|
|
16
|
+
exec overmind start -f Procfile.dev "$@"
|
|
17
|
+
fi
|
|
@@ -1,57 +1,40 @@
|
|
|
1
|
-
# This file contains per-environment settings for AnyCable
|
|
1
|
+
# This file contains per-environment settings for AnyCable Rails integration
|
|
2
|
+
# (NOT the AnyCable server).
|
|
2
3
|
#
|
|
3
|
-
#
|
|
4
|
-
#
|
|
5
|
-
# E.g., `rpc_host` is overridden by ANYCABLE_RPC_HOST, `debug` by ANYCABLE_DEBUG etc.
|
|
6
|
-
#
|
|
7
|
-
# Note that AnyCable recognizes REDIS_URL env variable for Redis pub/sub adapter. If you want to
|
|
8
|
-
# use another Redis instance for AnyCable, provide ANYCABLE_REDIS_URL variable.
|
|
9
|
-
#
|
|
10
|
-
# Read more about AnyCable configuration here: <%= DOCS_ROOT %>/ruby/configuration
|
|
4
|
+
# The settings specified here would be overriden by the corresponding values in Rails credentials (e.g., `anycable.secret`), or environment variables (e.g., ANYCABLE_SECRET), or any other configuration
|
|
5
|
+
# sources supported by Anyway Config (https://github.com/palkan/anyway_config).
|
|
11
6
|
#
|
|
12
7
|
default: &default
|
|
13
8
|
# Turn on/off access logs ("Started..." and "Finished...")
|
|
14
9
|
access_logs_disabled: false
|
|
15
10
|
# Whether to enable gRPC level logging or not
|
|
16
11
|
log_grpc: false
|
|
17
|
-
|
|
18
|
-
# Use Redis Streams to broadcast messages to AnyCable server
|
|
19
|
-
broadcast_adapter: redisx
|
|
20
|
-
<%- elsif nats? -%>
|
|
21
|
-
# Use NATS to broadcast messages to AnyCable server
|
|
22
|
-
broadcast_adapter: nats
|
|
23
|
-
<%- else -%>
|
|
24
|
-
# Use HTTP broadcaster
|
|
12
|
+
# Use HTTP broadcaster by default
|
|
25
13
|
broadcast_adapter: http
|
|
26
|
-
http_broadcast_url: "http://localhost:8090/_broadcast"
|
|
27
|
-
<%- end -%>
|
|
28
|
-
<%- if redis? -%>
|
|
29
|
-
# You can use REDIS_URL env var to configure Redis URL.
|
|
30
|
-
# Localhost is used by default.
|
|
31
|
-
# redis_url: "redis://localhost:6379/1"
|
|
32
|
-
# Use the same channel name for WebSocket server, e.g.:
|
|
33
|
-
# $ anycable-go --redis_channel="__anycable__"
|
|
34
|
-
# redis_channel: "__anycable__"
|
|
35
|
-
<%- end -%>
|
|
36
14
|
<%- if http_rpc? -%>
|
|
37
|
-
# Use HTTP RPC mounted at the
|
|
38
|
-
# Read more
|
|
39
|
-
|
|
15
|
+
# Use HTTP RPC mounted at the "/_anycable" path of your web server
|
|
16
|
+
# Read more: https://docs.anycable.io/anycable-go/rpc?id=rpc-over-http
|
|
17
|
+
http_rpc: true
|
|
40
18
|
<%- end -%>
|
|
41
|
-
#
|
|
19
|
+
# This values MUST be the same as in your AnyCable server configuration
|
|
42
20
|
secret: "anycable-local-secret"
|
|
21
|
+
# WebSocket endpoint of your AnyCable server for clients to connect to
|
|
22
|
+
# IMPORTANT: Make sure you have the `action_cable_meta_tag` in your HTML layout
|
|
23
|
+
# to propogate this value to the client app.
|
|
24
|
+
# Make sure your AnyCable server runs on port 8080 in development.
|
|
25
|
+
websocket_url: "ws://localhost:8080/cable"
|
|
43
26
|
|
|
44
27
|
development:
|
|
45
28
|
<<: *default
|
|
46
|
-
# WebSocket endpoint of your AnyCable server for clients to connect to
|
|
47
|
-
# Make sure you have the `action_cable_meta_tag` in your HTML layout
|
|
48
|
-
# to propogate this value to the client app
|
|
49
|
-
websocket_url: "ws://localhost:8080/cable"
|
|
50
29
|
|
|
30
|
+
# Read more about running AnyCable in test env:
|
|
31
|
+
# https://docs.anycable.io/rails/getting_started?id=testing-with-anycable
|
|
51
32
|
test:
|
|
52
33
|
<<: *default
|
|
53
34
|
|
|
54
35
|
production:
|
|
55
36
|
<<: *default
|
|
37
|
+
# Use ANYCABLE_WEBSOCKET_URL and ANYCABLE_SECRET environment variables
|
|
38
|
+
# or credentials or whatever.
|
|
56
39
|
websocket_url: ~
|
|
57
40
|
secret: ~
|
|
@@ -1,11 +1,8 @@
|
|
|
1
|
-
# Make it possible to switch adapters by passing the ACTION_CABLE_ADAPTER env variable.
|
|
2
|
-
# For example, you can use it fallback to the standard Action Cable in staging/review
|
|
3
|
-
# environments (by setting `ACTION_CABLE_ADAPTER=redis`).
|
|
4
1
|
development:
|
|
5
|
-
adapter:
|
|
2
|
+
adapter: any_cable
|
|
6
3
|
|
|
7
4
|
test:
|
|
8
5
|
adapter: test
|
|
9
6
|
|
|
10
7
|
production:
|
|
11
|
-
adapter:
|
|
8
|
+
adapter: any_cable
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: anycable-rails-core
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.6.
|
|
4
|
+
version: 1.6.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- palkan
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-04-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: anycable-core
|
|
@@ -120,6 +120,7 @@ files:
|
|
|
120
120
|
- lib/generators/anycable/setup/templates/Procfile.dev.tt
|
|
121
121
|
- lib/generators/anycable/setup/templates/anycable.toml.tt
|
|
122
122
|
- lib/generators/anycable/setup/templates/bin/anycable-go.tt
|
|
123
|
+
- lib/generators/anycable/setup/templates/bin/dev
|
|
123
124
|
- lib/generators/anycable/setup/templates/config/anycable.yml.tt
|
|
124
125
|
- lib/generators/anycable/setup/templates/config/cable.yml.tt
|
|
125
126
|
- lib/generators/anycable/with_os_helpers.rb
|
|
@@ -133,6 +134,7 @@ metadata:
|
|
|
133
134
|
homepage_uri: https://anycable.io/
|
|
134
135
|
source_code_uri: http://github.com/anycable/anycable-rails
|
|
135
136
|
funding_uri: https://github.com/sponsors/anycable
|
|
137
|
+
rubygems_mfa_required: 'true'
|
|
136
138
|
post_install_message:
|
|
137
139
|
rdoc_options: []
|
|
138
140
|
require_paths:
|