anycable-rails-core 1.5.4 → 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 +25 -1
- data/README.md +10 -71
- data/lib/anycable/rails/action_cable_ext/channel.rb +0 -11
- data/lib/anycable/rails/action_cable_ext/remote_connections.rb +1 -1
- data/lib/anycable/rails/channel/presence.rb +36 -0
- data/lib/anycable/rails/channel.rb +9 -0
- data/lib/anycable/rails/compatibility/rubocop.rb +2 -25
- data/lib/anycable/rails/compatibility.rb +1 -0
- data/lib/anycable/rails/config.rb +2 -0
- data/lib/anycable/rails/connection.rb +62 -33
- data/lib/anycable/rails/connections/serializable_identification.rb +14 -0
- data/lib/anycable/rails/helper.rb +2 -2
- data/lib/anycable/rails/railtie.rb +4 -2
- data/lib/anycable/rails/{compatibility/rubocop → rubocop}/cops/anycable/instance_vars.rb +1 -1
- data/lib/anycable/rails/{compatibility/rubocop → rubocop}/cops/anycable/periodical_timers.rb +3 -8
- data/lib/anycable/rails/{compatibility/rubocop → rubocop}/cops/anycable/stream_from.rb +3 -5
- data/lib/anycable/rails/rubocop.rb +27 -0
- data/lib/anycable/rails/socket_id_tracking.rb +2 -2
- data/lib/anycable/rails/version.rb +1 -1
- data/lib/anycable/rails.rb +2 -1
- data/lib/generators/anycable/bin/templates/bin/anycable-go.tt +5 -0
- data/lib/generators/anycable/download/download_generator.rb +16 -5
- data/lib/generators/anycable/setup/setup_generator.rb +278 -33
- 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 +16 -11
- /data/lib/anycable/rails/{compatibility/rubocop → rubocop}/config/default.yml +0 -0
|
@@ -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.
|
|
58
|
+
|
|
59
|
+
gRPC provides better performance and scalability but requires running
|
|
60
|
+
a separate component (a gRPC server).
|
|
39
61
|
|
|
40
|
-
|
|
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).
|
|
41
64
|
|
|
42
|
-
|
|
43
|
-
|
|
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 ""
|
|
59
102
|
|
|
60
|
-
|
|
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
|
|
107
|
+
|
|
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,22 +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
|
|
92
|
-
|
|
175
|
+
def action_cable_engine
|
|
176
|
+
return unless application_rb
|
|
177
|
+
return if application_rb.match?(/^require\s+['"](action_cable\/engine|rails\/all)['"]/)
|
|
178
|
+
|
|
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"
|
|
188
|
+
end
|
|
189
|
+
|
|
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
|
|
93
205
|
|
|
94
|
-
|
|
206
|
+
@todos << "⚠️ Install AnyCable JS client to use advanced features (presence, reliable streams): 👉 https://github.com/anycable/anycable-client\n"
|
|
207
|
+
end
|
|
208
|
+
|
|
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)"
|
|
95
225
|
end
|
|
96
226
|
|
|
97
227
|
def finish
|
|
98
|
-
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
|
|
99
237
|
end
|
|
100
238
|
|
|
101
239
|
private
|
|
@@ -117,7 +255,7 @@ module AnyCableRailsGenerators
|
|
|
117
255
|
end
|
|
118
256
|
|
|
119
257
|
def local?
|
|
120
|
-
@
|
|
258
|
+
@development == "local"
|
|
121
259
|
end
|
|
122
260
|
|
|
123
261
|
def grpc?
|
|
@@ -128,6 +266,26 @@ module AnyCableRailsGenerators
|
|
|
128
266
|
@rpc_impl == "http"
|
|
129
267
|
end
|
|
130
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
|
+
|
|
131
289
|
def gemfile_lock
|
|
132
290
|
@gemfile_lock ||= begin
|
|
133
291
|
res = nil
|
|
@@ -139,6 +297,28 @@ module AnyCableRailsGenerators
|
|
|
139
297
|
end
|
|
140
298
|
end
|
|
141
299
|
|
|
300
|
+
def application_rb
|
|
301
|
+
@application_rb ||= begin
|
|
302
|
+
res = nil
|
|
303
|
+
in_root do
|
|
304
|
+
next unless File.file?("config/application.rb")
|
|
305
|
+
res = File.read("config/application.rb")
|
|
306
|
+
end
|
|
307
|
+
res
|
|
308
|
+
end
|
|
309
|
+
end
|
|
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
|
+
|
|
142
322
|
def install_for_docker
|
|
143
323
|
say_status :help, "️️⚠️ Docker development configuration could vary", :yellow
|
|
144
324
|
|
|
@@ -161,7 +341,7 @@ module AnyCableRailsGenerators
|
|
|
161
341
|
condition: service_started
|
|
162
342
|
|
|
163
343
|
ws:
|
|
164
|
-
image: anycable/anycable-go:1.
|
|
344
|
+
image: anycable/anycable-go:1.6
|
|
165
345
|
ports:
|
|
166
346
|
- '8080:8080'
|
|
167
347
|
- '8090'
|
|
@@ -217,11 +397,12 @@ module AnyCableRailsGenerators
|
|
|
217
397
|
end
|
|
218
398
|
end
|
|
219
399
|
|
|
220
|
-
def
|
|
400
|
+
def install_for_bin
|
|
221
401
|
unless file_exists?("bin/anycable-go")
|
|
222
402
|
generate "anycable:bin", "--version #{options[:version]}"
|
|
223
403
|
end
|
|
224
404
|
template_proc_files
|
|
405
|
+
update_bin_dev
|
|
225
406
|
true
|
|
226
407
|
end
|
|
227
408
|
|
|
@@ -234,7 +415,23 @@ module AnyCableRailsGenerators
|
|
|
234
415
|
adapter = Regexp.last_match[1]
|
|
235
416
|
next match if adapter == "test" || adapter.include?("any_cable")
|
|
236
417
|
|
|
237
|
-
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
|
|
238
435
|
end
|
|
239
436
|
|
|
240
437
|
File.write "config/cable.yml", new_contents
|
|
@@ -252,8 +449,6 @@ module AnyCableRailsGenerators
|
|
|
252
449
|
if file_exists?(file_name)
|
|
253
450
|
update_procfile(file_name)
|
|
254
451
|
else
|
|
255
|
-
say_status :help, "💡 We recommend using Overmind to manage multiple processes in development 👉 https://github.com/DarthSim/overmind", :yellow
|
|
256
|
-
|
|
257
452
|
return if options[:skip_procfile_dev]
|
|
258
453
|
|
|
259
454
|
template file_name
|
|
@@ -264,13 +459,36 @@ module AnyCableRailsGenerators
|
|
|
264
459
|
in_root do
|
|
265
460
|
contents = File.read(file_name)
|
|
266
461
|
|
|
267
|
-
|
|
462
|
+
if grpc?
|
|
268
463
|
unless contents.match?(/^anycable:\s/)
|
|
269
464
|
append_file file_name, "anycable: bundle exec anycable\n", force: true
|
|
270
465
|
end
|
|
271
466
|
end
|
|
272
467
|
unless contents.match?(/^ws:\s/)
|
|
273
|
-
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"
|
|
274
492
|
end
|
|
275
493
|
end
|
|
276
494
|
end
|
|
@@ -280,5 +498,32 @@ module AnyCableRailsGenerators
|
|
|
280
498
|
return File.file?(name)
|
|
281
499
|
end
|
|
282
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
|
|
283
528
|
end
|
|
284
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/_anycable"
|
|
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
|