anycable-rails-core 1.4.0 → 1.4.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7bc0b1eac8c453d0054d508826fd33e58b32684c89694fbbc393d2796db8f0c1
4
- data.tar.gz: 82ff10fabf21471a9fdcc14e6d76d294902b89372002734538b66e1e7569ab1d
3
+ metadata.gz: 713258efa713cd94cb2aa57891bf52f2483732f6e84b918a90d77924bc9d78e2
4
+ data.tar.gz: 45151b26a79c7ab05ba42629fcbb2c64a147142a39fe8d9eaff54dbce3b905c6
5
5
  SHA512:
6
- metadata.gz: 53cda30136d94edc95e319a0e80bed3ce19716d15dd0e69eae0fc14ffb0c45d58ec0fb466bece171736f4821a7aeeba6ec774c228e8915deb7b2eea01fed1565
7
- data.tar.gz: 2787f8c23179f2283fe9b68982f0e3f0ea8fde5222ef97dba7294464523d8968f57f1c71f166f0d44583047747bbd40433e7603afb07c45f3b58eac98bba3cf4
6
+ metadata.gz: d98ee91a26f73b7e9ff7c60820211ddebf53566520903f6ca26be838f4c27fed6f0a2a36787fe3207b569f32881c83efd263517eaa71a5f74bdee00dd61c63ff
7
+ data.tar.gz: e0a86e5ccbef6d7735f71663a5a9511dc9dd3a7a7df8fa1ffd4e3cccbf653184c0048cbbd22007f21614f4d78f30ee5aa4bb55b275964f1b9b690e3927c27069
data/CHANGELOG.md CHANGED
@@ -2,6 +2,24 @@
2
2
 
3
3
  ## master
4
4
 
5
+ ## 1.4.2 (2023-10-15)
6
+
7
+ - Print warning if the database pool size is less than RPC pool size. ([@palkan][])
8
+
9
+ - Add support for broadcast options (e.g., `exclude_socket`) and `broadcast ..., to_others: true`. ([@palkan][])
10
+
11
+ - Add `batch_broadcasts` option to automatically batch broadcasts for code wrapped in Rails executor. ([@palkan][])
12
+
13
+ - Fix broadcast logging in Rails 7.1. ([@iuri-gg][])
14
+
15
+ ## 1.4.1 (2023-09-27)
16
+
17
+ - Fix compatibility with Rails 7.1. ([@palkan][])
18
+
19
+ - Upgrade `anycable:setup` generator to support v1.4 features. ([@palkan][])
20
+
21
+ Add `bin/anycable-go` to use `anycable-go` locally. Add `--rpc=http` to configure for using AnyCable with HTTP RPC.
22
+
5
23
  ## 1.4.0 (2023-07-07)
6
24
 
7
25
  - Add HTTP RPC integration. ([@palkan][])
@@ -18,8 +18,11 @@ module ActionCable
18
18
  def initialize(*)
19
19
  end
20
20
 
21
- def broadcast(channel, payload)
22
- ::AnyCable.broadcast(channel, payload)
21
+ def broadcast(channel, payload, **options)
22
+ options.merge!(::AnyCable::Rails.current_broadcast_options || {})
23
+ to_others = options.delete(:to_others)
24
+ options[:exclude_socket] ||= ::AnyCable::Rails.current_socket_id if to_others
25
+ ::AnyCable.broadcast(channel, payload, **options.compact)
23
26
  end
24
27
 
25
28
  def subscribe(*)
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "action_cable"
4
+
5
+ ActionCable::Server::Base.prepend(Module.new do
6
+ def broadcast(channel, payload, **options)
7
+ return super if options.empty?
8
+
9
+ AnyCable::Rails.with_broadcast_options(**options) do
10
+ super(channel, payload)
11
+ end
12
+ end
13
+ end)
14
+
15
+ ActionCable::Channel::Base.singleton_class.prepend(Module.new do
16
+ def broadcast_to(target, payload, **options)
17
+ return super if options.empty?
18
+
19
+ AnyCable::Rails.with_broadcast_options(**options) do
20
+ super(target, payload)
21
+ end
22
+ end
23
+ end)
@@ -10,10 +10,14 @@ require "anyway/rails"
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
12
  # - `http_rpc_mount_path` (default to nil) — path to mount HTTP RPC server
13
+ # - `batch_broadcasts` (defaults to false) — whether to batch broadcasts automatically for code wrapped with Rails executor
13
14
  AnyCable::Config.attr_config(
14
15
  access_logs_disabled: true,
15
16
  persistent_session_enabled: false,
16
17
  embedded: false,
17
- http_rpc_mount_path: nil
18
+ http_rpc_mount_path: nil,
19
+ batch_broadcasts: false,
20
+ socket_id_header: "X-Socket-ID",
21
+ disable_rpc_pool_size_warning: false
18
22
  )
19
23
  AnyCable::Config.ignore_options :access_logs_disabled, :persistent_session_enabled
@@ -13,16 +13,16 @@ module AnyCable
13
13
  end
14
14
 
15
15
  def call(method, message, metadata)
16
+ sid = metadata["sid"]
17
+
16
18
  if ::Rails.respond_to?(:error)
17
19
  executor.wrap do
18
- sid = metadata["sid"]
19
-
20
20
  ::Rails.error.record(context: {method: method, payload: message.to_h, sid: sid}) do
21
- yield
21
+ Rails.with_socket_id(sid) { yield }
22
22
  end
23
23
  end
24
24
  else
25
- executor.wrap { yield }
25
+ executor.wrap { Rails.with_socket_id(sid) { yield } }
26
26
  end
27
27
  end
28
28
  end
@@ -3,6 +3,7 @@
3
3
  require "anycable/rails/action_cable_ext/connection"
4
4
  require "anycable/rails/action_cable_ext/channel"
5
5
  require "anycable/rails/action_cable_ext/remote_connections"
6
+ require "anycable/rails/action_cable_ext/broadcast_options"
6
7
 
7
8
  require "anycable/rails/channel_state"
8
9
  require "anycable/rails/connection_factory"
@@ -21,15 +22,23 @@ module AnyCable
21
22
 
22
23
  AnyCable.configure_server do
23
24
  server_logger = AnyCable.logger = ::ActionCable.server.config.logger
24
- AnyCable.logger = ActiveSupport::TaggedLogging.new(server_logger) if server_logger.is_a?(::Logger)
25
+
25
26
  # Broadcast server logs to STDOUT in development
26
27
  if ::Rails.env.development? &&
27
28
  !ActiveSupport::Logger.logger_outputs_to?(::Rails.logger, $stdout)
28
29
  console = ActiveSupport::Logger.new($stdout)
29
30
  console.formatter = ::Rails.logger.formatter if ::Rails.logger.respond_to?(:formatter)
30
31
  console.level = ::Rails.logger.level if ::Rails.logger.respond_to?(:level)
31
- AnyCable.logger.extend(ActiveSupport::Logger.broadcast(console))
32
+
33
+ # Rails 7.1+
34
+ if AnyCable.logger.respond_to?(:broadcast_to)
35
+ AnyCable.logger.broadcast_to(console)
36
+ else
37
+ AnyCable.logger.extend(ActiveSupport::Logger.broadcast(console))
38
+ end
32
39
  end
40
+
41
+ AnyCable.logger = ActiveSupport::TaggedLogging.new(AnyCable.logger) if server_logger.is_a?(::Logger)
33
42
  end
34
43
 
35
44
  # Add tagging middleware
@@ -51,6 +60,27 @@ module AnyCable
51
60
  ::Rails.error.report(ex, handled: false, context: {method: method.to_sym, payload: message})
52
61
  end
53
62
  end
63
+
64
+ if AnyCable.config.batch_broadcasts?
65
+ if AnyCable.broadcast_adapter.respond_to?(:start_batching)
66
+ app.executor.to_run { AnyCable.broadcast_adapter.start_batching }
67
+ app.executor.to_complete { AnyCable.broadcast_adapter.finish_batching }
68
+ else
69
+ warn "[AnyCable] Auto-batching is enabled for broadcasts but your anycable version doesn't support it. Please, upgrade"
70
+ end
71
+ end
72
+ end
73
+
74
+ initializer "anycable.socket_id_tracking" do
75
+ ActiveSupport.on_load(:action_controller) do
76
+ require "anycable/rails/socket_id_tracking"
77
+ include AnyCable::Rails::SocketIdTrackingController
78
+ end
79
+
80
+ ActiveSupport.on_load(:active_job) do
81
+ require "anycable/rails/socket_id_tracking"
82
+ include AnyCable::Rails::SocketIdTrackingJob
83
+ end
54
84
  end
55
85
 
56
86
  initializer "anycable.connection_factory", after: "action_cable.set_configs" do |app|
@@ -78,6 +108,27 @@ module AnyCable
78
108
  end
79
109
  end
80
110
 
111
+ initializer "anycable.verify_pool_sizes" do
112
+ next if AnyCable.config.disable_rpc_pool_size_warning?
113
+ # Skip if non-gRPC server is used
114
+ next unless AnyCable.config.respond_to?(:rpc_pool_size)
115
+
116
+ # Log current db vs. gRPC pool sizes
117
+ AnyCable.configure_server do
118
+ ActiveSupport.on_load(:active_record) do
119
+ db_pool_size = ::ActiveRecord::Base.connection_pool.size
120
+ rpc_pool_size = AnyCable.config.rpc_pool_size
121
+
122
+ if rpc_pool_size > db_pool_size
123
+ ::Kernel.warn(
124
+ "\n⛔️ WARNING: AnyCable RPC pool size (#{rpc_pool_size}) is greater than DB pool size (#{db_pool_size})\n" \
125
+ "Please, consider adjusting the database pool size to avoid connection wait times and increase throughput of your RPC server\n\n"
126
+ )
127
+ end
128
+ end
129
+ end
130
+ end
131
+
81
132
  # Since Rails 6.1
82
133
  if respond_to?(:server)
83
134
  server do
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AnyCable
4
+ module Rails
5
+ module SocketIdTrackingController
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ around_action :anycable_tracking_socket_id
10
+ end
11
+
12
+ private
13
+
14
+ def anycable_tracking_socket_id(&block)
15
+ Rails.with_socket_id(request.headers[AnyCable.config.socket_id_header], &block)
16
+ end
17
+ end
18
+
19
+ module SocketIdTrackingJob
20
+ extend ActiveSupport::Concern
21
+
22
+ attr_accessor :cable_socket_id
23
+
24
+ def serialize
25
+ return super unless Rails.current_socket_id
26
+
27
+ super.merge("cable_socket_id" => Rails.current_socket_id)
28
+ end
29
+
30
+ def deserialize(job_data)
31
+ super
32
+ self.cable_socket_id = job_data["cable_socket_id"]
33
+ end
34
+
35
+ included do
36
+ around_perform do |job, block|
37
+ Rails.with_socket_id(job.cable_socket_id, &block)
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module AnyCable
4
4
  module Rails
5
- VERSION = "1.4.0"
5
+ VERSION = "1.4.2"
6
6
  end
7
7
  end
@@ -6,6 +6,7 @@ require "anycable/rails/config"
6
6
  require "anycable/rails/rack"
7
7
 
8
8
  require "globalid"
9
+ require "active_support/core_ext/module/attribute_accessors_per_thread"
9
10
 
10
11
  module AnyCable
11
12
  # Rails handler for AnyCable
@@ -14,6 +15,9 @@ module AnyCable
14
15
 
15
16
  ADAPTER_ALIASES = %w[any_cable anycable].freeze
16
17
 
18
+ thread_mattr_accessor :current_socket_id
19
+ thread_mattr_accessor :current_broadcast_options
20
+
17
21
  class << self
18
22
  def enabled?
19
23
  adapter = ::ActionCable.server.config.cable&.fetch("adapter", nil)
@@ -24,6 +28,29 @@ module AnyCable
24
28
  ADAPTER_ALIASES.include?(adapter)
25
29
  end
26
30
 
31
+ def with_socket_id(socket_id)
32
+ old_socket_id, self.current_socket_id = current_socket_id, socket_id
33
+ yield
34
+ ensure
35
+ self.current_socket_id = old_socket_id
36
+ end
37
+
38
+ def with_broadcast_options(**options)
39
+ old_options = current_broadcast_options
40
+ self.current_broadcast_options = options.reverse_merge(old_options || {})
41
+ yield
42
+ ensure
43
+ self.current_broadcast_options = old_options
44
+ end
45
+
46
+ def broadcasting_to_others(socket_id: nil, &block)
47
+ if socket_id
48
+ with_socket_id(socket_id) { with_broadcast_options(to_others: true, &block) }
49
+ else
50
+ with_broadcast_options(to_others: true, &block)
51
+ end
52
+ end
53
+
27
54
  # Serialize connection/channel state variable to string
28
55
  # using GlobalID where possible or JSON (if json: true)
29
56
  def serialize(obj, json: false)
@@ -50,9 +77,9 @@ module AnyCable
50
77
  end
51
78
 
52
79
  module Extension
53
- def broadcast(channel, payload)
80
+ def broadcast(...)
54
81
  super
55
- ::AnyCable.broadcast(channel, payload)
82
+ ::AnyCable.broadcast(...)
56
83
  end
57
84
  end
58
85
 
@@ -1,2 +1,11 @@
1
1
  Description:
2
2
  Configures your application to work with AnyCable interactively.
3
+
4
+ Example:
5
+ rails generate anycable:setup
6
+
7
+ # You can opt-in to use HTTP RPC
8
+ rails generate anycable:setup --rpc=http
9
+
10
+ # You can specify which version of anycable-go to use
11
+ rails generate anycable:setup --version=1.4
@@ -10,14 +10,15 @@ module AnyCableRailsGenerators
10
10
 
11
11
  DOCS_ROOT = "https://docs.anycable.io"
12
12
  DEVELOPMENT_METHODS = %w[skip local docker].freeze
13
- SERVER_SOURCES = %w[skip brew binary].freeze
13
+ RPC_IMPL = %w[grpc http].freeze
14
14
 
15
15
  class_option :devenv,
16
16
  type: :string,
17
17
  desc: "Select your development environment (options: #{DEVELOPMENT_METHODS.join(", ")})"
18
- class_option :source,
18
+ class_option :rpc,
19
19
  type: :string,
20
- desc: "Choose a way of installing AnyCable-Go server (options: #{SERVER_SOURCES.join(", ")})"
20
+ desc: "Select RPC implementation (options: #{RPC_IMPL.join(", ")})",
21
+ default: "grpc"
21
22
  class_option :skip_heroku,
22
23
  type: :boolean,
23
24
  desc: "Do not copy Heroku configs"
@@ -30,12 +31,6 @@ module AnyCableRailsGenerators
30
31
  class_option :skip_install,
31
32
  type: :boolean,
32
33
  desc: "Do not run bundle install when adding new gems"
33
-
34
- include WithOSHelpers
35
-
36
- class_option :bin_path,
37
- type: :string,
38
- desc: "Where to download AnyCable-Go server binary (default: #{DEFAULT_BIN_PATH})"
39
34
  class_option :version,
40
35
  type: :string,
41
36
  desc: "Specify the AnyCable-Go version (defaults to latest release)"
@@ -99,6 +94,7 @@ module AnyCableRailsGenerators
99
94
 
100
95
  in_root do
101
96
  next unless File.file?("Procfile")
97
+ next if http_rpc?
102
98
 
103
99
  contents = File.read("Procfile")
104
100
  contents.sub!(/^web: (.*)$/, %q(web: [[ "$ANYCABLE_DEPLOYMENT" == "true" ]] && bundle exec anycable --server-command="anycable-go" || \1))
@@ -171,6 +167,10 @@ module AnyCableRailsGenerators
171
167
  !!gemfile_lock&.match?(/^\s+rubocop\b/)
172
168
  end
173
169
 
170
+ def http_rpc?
171
+ options[:rpc] == "http"
172
+ end
173
+
174
174
  def gemfile_lock
175
175
  @gemfile_lock ||= begin
176
176
  res = nil
@@ -192,7 +192,7 @@ module AnyCableRailsGenerators
192
192
  say <<~YML
193
193
  ─────────────────────────────────────────
194
194
  ws:
195
- image: anycable/anycable-go:1.2
195
+ image: anycable/anycable-go:1.4
196
196
  ports:
197
197
  - '8080:8080'
198
198
  environment:
@@ -223,33 +223,25 @@ module AnyCableRailsGenerators
223
223
  end
224
224
 
225
225
  def install_for_local
226
- install_server
227
- template_proc_files
228
- end
229
-
230
- def install_server
231
- answer = SERVER_SOURCES.index(options[:source]) || 99
232
-
233
- until SERVER_SOURCES[answer.to_i]
234
- answer = ask "How do you want to install AnyCable-Go WebSocket server? (1) Homebrew, (2) Download binary, (0) Skip"
226
+ inside("bin") do
227
+ template "anycable-go", chmod: 0o755
235
228
  end
236
229
 
237
- case answer.to_i
238
- when 0
239
- say_status :help, "⚠️ Please, read this guide on how to install AnyCable-Go server 👉 #{DOCS_ROOT}/anycable-go/getting_started", :yellow
240
- return
241
- else
242
- return unless send("install_from_#{SERVER_SOURCES[answer.to_i]}")
230
+ if file_exists?(".gitignore")
231
+ append_file ".gitignore", "bin/dist\n"
243
232
  end
244
233
 
245
- say_status :info, "✅ AnyCable-Go WebSocket server has been successfully installed"
234
+ template_proc_files
246
235
  end
247
236
 
248
237
  def template_proc_files
249
238
  file_name = "Procfile.dev"
250
239
 
251
240
  if file_exists?(file_name)
252
- append_file file_name, "anycable: bundle exec anycable\nws: anycable-go#{anycable_go_options}", force: true
241
+ unless http_rpc?
242
+ append_file file_name, "anycable: bundle exec anycable\n", force: true
243
+ end
244
+ append_file file_name, "ws: bin/anycable-go #{anycable_go_options}", force: true
253
245
  else
254
246
  say_status :help, "💡 We recommend using Hivemind to manage multiple processes in development 👉 https://github.com/DarthSim/hivemind", :yellow
255
247
 
@@ -263,32 +255,11 @@ module AnyCableRailsGenerators
263
255
  end
264
256
  end
265
257
 
266
- def install_from_brew
267
- run "brew install anycable-go", abort_on_failure: true
268
- run "anycable-go -v", abort_on_failure: true
269
- end
270
-
271
- def install_from_binary
272
- bin_path ||= DEFAULT_BIN_PATH if options[:devenv] # User don't want interactive mode
273
- bin_path ||= ask "Please, enter the path to download the AnyCable-Go binary to", default: DEFAULT_BIN_PATH, path: true
274
-
275
- generate "anycable:download", download_options(bin_path: bin_path)
276
-
277
- true
278
- end
279
-
280
- def download_options(**params)
281
- opts = options.merge(params)
282
- [].tap do |args|
283
- args << "--os #{opts[:os]}" if opts[:os]
284
- args << "--cpu #{opts[:cpu]}" if opts[:cpu]
285
- args << "--bin-path=#{opts[:bin_path]}" if opts[:bin_path]
286
- args << "--version #{opts[:version]}" if opts[:version]
287
- end.join(" ")
288
- end
289
-
290
258
  def anycable_go_options
291
- redis? ? " --port=8080" : " --port=8080 --broadcast_adapter=http"
259
+ opts = ["--port=8080"]
260
+ opts << "--broadcast_adapter=http" unless redis?
261
+ opts << "--rpc_impl=http --rpc_host=http://localhost:3000/_anycable" if http_rpc?
262
+ opts.join(" ")
292
263
  end
293
264
 
294
265
  def file_exists?(name)
@@ -296,5 +267,18 @@ module AnyCableRailsGenerators
296
267
  return File.file?(name)
297
268
  end
298
269
  end
270
+
271
+ def anycable_go_version
272
+ @anycable_go_version ||= (normalize_version(options[:version]) || "latest")
273
+ end
274
+
275
+ def normalize_version(version)
276
+ return unless version
277
+
278
+ # We need a full version for bin/anycable-go script
279
+ segments = Gem::Version.new(version).segments
280
+ segments << 0 until segments.size >= 3
281
+ segments.join(".")
282
+ end
299
283
  end
300
284
  end
@@ -1,6 +1,5 @@
1
- server: bundle exec rails s
2
- <%- if webpacker? -%>
3
- assets: bundle exec bin/webpack-dev-server
4
- <%- end -%>
1
+ web: bin/rails s
2
+ <%- unless http_rpc? -%>
5
3
  anycable: bundle exec anycable
6
- ws: anycable-go<%= anycable_go_options %>
4
+ <%- end -%>
5
+ ws: bin/anycable-go <%= anycable_go_options %>
@@ -0,0 +1,22 @@
1
+ #!/bin/bash
2
+
3
+ cd $(dirname $0)/..
4
+
5
+ # It's recommended to use the exact version of AnyCable-Go here
6
+ version="<%= anycable_go_version %>"
7
+
8
+ if [ ! -f ./bin/dist/anycable-go ]; then
9
+ echo "AnyCable-go is not installed, downloading..."
10
+ ./bin/rails g anycable:download --version=$version --bin-path=./bin/dist
11
+ fi
12
+
13
+ curVersion=$(./bin/dist/anycable-go -v)
14
+
15
+ if [[ "$version" != "latest" ]]; then
16
+ if [[ "$curVersion" != "$version"* ]]; then
17
+ echo "AnyCable-go version is not $version, downloading a new one..."
18
+ ./bin/rails g anycable:download --version=$version --bin-path=./bin/dist
19
+ fi
20
+ fi
21
+
22
+ ./bin/dist/anycable-go $@
@@ -32,6 +32,9 @@ default: &default
32
32
  # Localhost is used by default.
33
33
  # redis_url: "redis://localhost:6379/1"
34
34
  <%- end -%>
35
+ <%- if http_rpc? -%>
36
+ http_rpc_mount_path: "/_anycable"
37
+ <%- end -%>
35
38
 
36
39
  development:
37
40
  <<: *default
@@ -41,8 +44,3 @@ test:
41
44
 
42
45
  production:
43
46
  <<: *default
44
- <%- if !redis? && !nats? -%>
45
- # Use Redis or NATS in production
46
- broadcast_adapter: redis
47
- # broadcast_adapter: nats
48
- <%- end -%>
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.4.0
4
+ version: 1.4.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - palkan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-07-12 00:00:00.000000000 Z
11
+ date: 2023-10-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: anycable-core
@@ -66,6 +66,7 @@ files:
66
66
  - lib/action_cable/subscription_adapter/anycable.rb
67
67
  - lib/anycable-rails.rb
68
68
  - lib/anycable/rails.rb
69
+ - lib/anycable/rails/action_cable_ext/broadcast_options.rb
69
70
  - lib/anycable/rails/action_cable_ext/channel.rb
70
71
  - lib/anycable/rails/action_cable_ext/connection.rb
71
72
  - lib/anycable/rails/action_cable_ext/remote_connections.rb
@@ -86,12 +87,14 @@ files:
86
87
  - lib/anycable/rails/middlewares/log_tagging.rb
87
88
  - lib/anycable/rails/rack.rb
88
89
  - lib/anycable/rails/railtie.rb
90
+ - lib/anycable/rails/socket_id_tracking.rb
89
91
  - lib/anycable/rails/version.rb
90
92
  - lib/generators/anycable/download/USAGE
91
93
  - lib/generators/anycable/download/download_generator.rb
92
94
  - lib/generators/anycable/setup/USAGE
93
95
  - lib/generators/anycable/setup/setup_generator.rb
94
96
  - lib/generators/anycable/setup/templates/Procfile.dev.tt
97
+ - lib/generators/anycable/setup/templates/bin/anycable-go.tt
95
98
  - lib/generators/anycable/setup/templates/config/anycable.yml.tt
96
99
  - lib/generators/anycable/setup/templates/config/cable.yml.tt
97
100
  - lib/generators/anycable/setup/templates/config/initializers/anycable.rb.tt