anycable-rails-core 1.4.4 → 1.5.0.rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +24 -0
- data/lib/action_cable/subscription_adapter/any_cable.rb +1 -1
- data/lib/anycable/rails/action_cable_ext/broadcast_options.rb +5 -0
- data/lib/anycable/rails/action_cable_ext/signed_streams.rb +31 -0
- data/lib/anycable/rails/channel_state.rb +11 -4
- data/lib/anycable/rails/config.rb +6 -2
- data/lib/anycable/rails/connections/serializable_identification.rb +2 -2
- data/lib/anycable/rails/ext/jwt.rb +35 -0
- data/lib/anycable/rails/ext.rb +10 -0
- data/lib/anycable/rails/helper.rb +36 -0
- data/lib/anycable/rails/object_serializer.rb +19 -0
- data/lib/anycable/rails/pubsub_channel.rb +22 -0
- data/lib/anycable/rails/railtie.rb +25 -0
- data/lib/anycable/rails/version.rb +1 -1
- data/lib/anycable/rails.rb +12 -20
- data/lib/generators/anycable/bin/USAGE +10 -0
- data/lib/generators/anycable/bin/bin_generator.rb +52 -0
- data/lib/generators/anycable/bin/templates/bin/anycable-go.tt +22 -0
- data/lib/generators/anycable/download/USAGE +2 -2
- data/lib/generators/anycable/download/download_generator.rb +3 -3
- data/lib/generators/anycable/setup/USAGE +0 -6
- data/lib/generators/anycable/setup/setup_generator.rb +165 -149
- data/lib/generators/anycable/setup/templates/bin/anycable-go.tt +3 -3
- data/lib/generators/anycable/setup/templates/config/anycable.yml.tt +11 -4
- metadata +17 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b614e500208e2a3f4ea896da9228028302800348084305868ea0c22178f858b
|
4
|
+
data.tar.gz: 83c91a4e4aa9dde124ed862addaf6e927a3638fd3187e7df781bfb8745c71319
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 18066377abcddc253760bc1afe77f5701f20fc9c7de4f83ed9ba9f98d91c8c68efe01943b724d39eaf39e58280825fe858b195871386a21acb34a191cede0b8a
|
7
|
+
data.tar.gz: ade05b2cd18c667d69626782031beb41885d3d9162c42042663baee100aaa930ff22a1f939bb3424ca7f7e2ec31225bf6ae9cdefc1b4892e692cd4c6a6d4dcc2
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,30 @@
|
|
2
2
|
|
3
3
|
## master
|
4
4
|
|
5
|
+
## 1.5.0.rc.1
|
6
|
+
|
7
|
+
- Support passing objects to `ActionCable.server.broadcast`. ([@palkan][])
|
8
|
+
|
9
|
+
Make it possible to call `ActionCable.server.broadcast(user, data)` or `ActionCable.server.broadcast([user, :context], data)`. This is a companion functionality for `#signed_stream_name`.
|
10
|
+
|
11
|
+
- Added `websocket_url` configuration option to specify the URL of AnyCable server. ([@palkan][])
|
12
|
+
|
13
|
+
It's used to configure `config.action_cable.url` if AnyCable is activated. No need to set up it manually.
|
14
|
+
|
15
|
+
- Added `rails g anycable:bin` to create a binstub to run AnyCable server. ([@palkan][])
|
16
|
+
|
17
|
+
- Added signed streams helpers. ([@palkan][])
|
18
|
+
|
19
|
+
You can use `#signed_stream_name(streamable)` to generate a signed stream name.
|
20
|
+
|
21
|
+
- Added JWT authentication helpers. ([@palkan][])
|
22
|
+
|
23
|
+
No more need in a separate `anycable-rails-jwt` gem.
|
24
|
+
|
25
|
+
## 1.4.5
|
26
|
+
|
27
|
+
- Restrict `anycable` gem version.
|
28
|
+
|
5
29
|
## 1.4.4 (2024-03-08) 🌷
|
6
30
|
|
7
31
|
- Minor fixes
|
@@ -8,7 +8,7 @@ module ActionCable
|
|
8
8
|
# to AnyCable
|
9
9
|
class AnyCable < Base
|
10
10
|
ACTION_CABLE_SERVER_ERROR_MESSAGE = <<~STR
|
11
|
-
Looks like you
|
11
|
+
Looks like you are trying to connect to Rails Action Cable server, not an AnyCable one.
|
12
12
|
|
13
13
|
Please make sure your client is configured to connect to AnyCable server.
|
14
14
|
|
@@ -10,6 +10,11 @@ ActionCable::Server::Base.prepend(Module.new do
|
|
10
10
|
super(channel, payload)
|
11
11
|
end
|
12
12
|
end
|
13
|
+
|
14
|
+
def broadcaster_for(broadcasting, **options)
|
15
|
+
broadcasting = AnyCable::Rails.stream_name_from(broadcasting)
|
16
|
+
super(broadcasting, **options)
|
17
|
+
end
|
13
18
|
end)
|
14
19
|
|
15
20
|
ActionCable::Channel::Base.singleton_class.prepend(Module.new do
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "action_cable"
|
4
|
+
|
5
|
+
ActionCable::Connection::Base.include(Module.new do
|
6
|
+
# This method is assumed to be overriden in the connection class to enable public
|
7
|
+
# streams
|
8
|
+
def allow_public_streams?
|
9
|
+
false
|
10
|
+
end
|
11
|
+
end)
|
12
|
+
|
13
|
+
# Handle $pubsub channel in Subscriptions
|
14
|
+
ActionCable::Connection::Subscriptions.prepend(Module.new do
|
15
|
+
# The contents are mostly copied from the original,
|
16
|
+
# there is no good way to configure channels mapping due to #safe_constantize
|
17
|
+
# and the layers of JSON
|
18
|
+
# https://github.com/rails/rails/blob/main/actioncable/lib/action_cable/connection/subscriptions.rb
|
19
|
+
def add(data)
|
20
|
+
id_key = data["identifier"]
|
21
|
+
id_options = ActiveSupport::JSON.decode(id_key).with_indifferent_access
|
22
|
+
|
23
|
+
return if subscriptions.key?(id_key)
|
24
|
+
|
25
|
+
return super unless id_options[:channel] == "$pubsub"
|
26
|
+
|
27
|
+
subscription = AnyCable::Rails::PubSubChannel.new(connection, id_key, id_options)
|
28
|
+
subscriptions[id_key] = subscription
|
29
|
+
subscription.subscribe_to_channel
|
30
|
+
end
|
31
|
+
end)
|
@@ -10,11 +10,15 @@ module AnyCable
|
|
10
10
|
class_eval <<~RUBY, __FILE__, __LINE__ + 1
|
11
11
|
def #{name}
|
12
12
|
return @#{name} if instance_variable_defined?(:@#{name})
|
13
|
-
|
13
|
+
return unless anycabled?
|
14
|
+
|
15
|
+
val = __istate__["#{name}"]
|
16
|
+
|
17
|
+
@#{name} = val.present? ? AnyCable::Serializer.deserialize(JSON.parse(val)) : nil
|
14
18
|
end
|
15
19
|
|
16
20
|
def #{name}=(val)
|
17
|
-
__istate__["#{name}"] = AnyCable::
|
21
|
+
__istate__["#{name}"] = AnyCable::Serializer.serialize(val).to_json if anycabled?
|
18
22
|
instance_variable_set(:@#{name}, val)
|
19
23
|
end
|
20
24
|
RUBY
|
@@ -53,11 +57,14 @@ module AnyCable
|
|
53
57
|
class_eval <<~RUBY, __FILE__, __LINE__ + 1
|
54
58
|
def #{name}
|
55
59
|
return @#{name} if instance_variable_defined?(:@#{name})
|
56
|
-
|
60
|
+
return unless anycabled?
|
61
|
+
|
62
|
+
val = __cstate__["#{name}"]
|
63
|
+
@#{name} = val.present? ? AnyCable::Serializer.deserialize(JSON.parse(val)) : nil
|
57
64
|
end
|
58
65
|
|
59
66
|
def #{name}=(val)
|
60
|
-
__cstate__["#{name}"] = AnyCable::
|
67
|
+
__cstate__["#{name}"] = AnyCable::Serializer.serialize(val).to_json if anycabled?
|
61
68
|
instance_variable_set(:@#{name}, val)
|
62
69
|
end
|
63
70
|
RUBY
|
@@ -9,15 +9,19 @@ 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_mount_path` (
|
12
|
+
# - `http_rpc_mount_path` (defaults to nil) — path to mount HTTP RPC server
|
13
13
|
# - `batch_broadcasts` (defaults to false) — whether to batch broadcasts automatically for code wrapped with Rails executor
|
14
|
+
# - `jwt_param` (defaults to 'jid') — the name of the JWT authentication query paramter or header
|
15
|
+
# - `websocket_url` (defaults to nil) — the URL of AnyCable server WebSocket endpoint
|
14
16
|
AnyCable::Config.attr_config(
|
15
17
|
access_logs_disabled: true,
|
16
18
|
persistent_session_enabled: false,
|
17
19
|
embedded: false,
|
20
|
+
jwt_param: "jid",
|
18
21
|
http_rpc_mount_path: nil,
|
19
22
|
batch_broadcasts: false,
|
20
23
|
socket_id_header: "X-Socket-ID",
|
21
|
-
disable_rpc_pool_size_warning: false
|
24
|
+
disable_rpc_pool_size_warning: false,
|
25
|
+
websocket_url: nil
|
22
26
|
)
|
23
27
|
AnyCable::Config.ignore_options :access_logs_disabled, :persistent_session_enabled
|
@@ -24,7 +24,7 @@ module AnyCable
|
|
24
24
|
obj = instance_variable_get("@#{id}")
|
25
25
|
next unless obj
|
26
26
|
|
27
|
-
acc[id] = AnyCable::
|
27
|
+
acc[id] = AnyCable::Serializer.serialize(obj)
|
28
28
|
end.compact
|
29
29
|
end
|
30
30
|
|
@@ -37,7 +37,7 @@ module AnyCable
|
|
37
37
|
return unless @cached_ids
|
38
38
|
|
39
39
|
@cached_ids[name] ||= @cached_ids.fetch(name) do
|
40
|
-
AnyCable::
|
40
|
+
AnyCable::Serializer.deserialize(@serialized_ids[name.to_s])
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AnyCable
|
4
|
+
module Rails
|
5
|
+
module Ext
|
6
|
+
# This module adds AnyCable JWT helpers to Action Cable
|
7
|
+
module JWT
|
8
|
+
# Handle expired tokens here to respond with a different disconnect reason
|
9
|
+
def handle_open
|
10
|
+
super
|
11
|
+
rescue AnyCable::JWT::ExpiredSignature
|
12
|
+
logger.error "An expired JWT token was rejected"
|
13
|
+
close(reason: "token_expired", reconnect: false) if websocket&.alive?
|
14
|
+
end
|
15
|
+
|
16
|
+
def anycable_jwt_present?
|
17
|
+
request.params[AnyCable.config.jwt_param].present? ||
|
18
|
+
request.headers["x-#{AnyCable.config.jwt_param}"].present?
|
19
|
+
end
|
20
|
+
|
21
|
+
def identify_from_anycable_jwt!
|
22
|
+
token = request.params[AnyCable.config.jwt_param].presence ||
|
23
|
+
request.headers["x-#{AnyCable.config.jwt_param}"].presence
|
24
|
+
|
25
|
+
identifiers = AnyCable::JWT.decode(token)
|
26
|
+
identifiers.each do |k, v|
|
27
|
+
public_send("#{k}=", v)
|
28
|
+
end
|
29
|
+
rescue AnyCable::JWT::VerificationError
|
30
|
+
reject_unauthorized_connection
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "uri"
|
4
|
+
|
5
|
+
module AnyCable
|
6
|
+
module Rails
|
7
|
+
module Helper
|
8
|
+
def action_cable_with_jwt_meta_tag(**identifiers)
|
9
|
+
# From: https://github.com/rails/rails/blob/main/actioncable/lib/action_cable/helpers/action_cable_helper.rb
|
10
|
+
base_url = ActionCable.server.config.url ||
|
11
|
+
ActionCable.server.config.mount_path ||
|
12
|
+
raise("No Action Cable URL configured -- please configure this at config.action_cable.url")
|
13
|
+
|
14
|
+
token = JWT.encode(identifiers)
|
15
|
+
|
16
|
+
parts = [base_url, "#{AnyCable.config.jwt_param}=#{token}"]
|
17
|
+
|
18
|
+
uri = URI.parse(base_url)
|
19
|
+
|
20
|
+
url = parts.join(uri.query ? "&" : "?")
|
21
|
+
|
22
|
+
tag "meta", name: "action-cable-url", content: url
|
23
|
+
end
|
24
|
+
|
25
|
+
def any_cable_jwt_meta_tag(**identifiers)
|
26
|
+
token = JWT.encode(identifiers)
|
27
|
+
|
28
|
+
tag "meta", name: "any-cable-jwt", content: token
|
29
|
+
end
|
30
|
+
|
31
|
+
def signed_stream_name(streamables)
|
32
|
+
Rails.signed_stream_name(streamables)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AnyCable
|
4
|
+
module Rails
|
5
|
+
module ObjectSerializer
|
6
|
+
module_function
|
7
|
+
|
8
|
+
# Serialize via GlobalID if available
|
9
|
+
def serialize(obj)
|
10
|
+
obj.try(:to_gid_param)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Deserialize from GlobalID
|
14
|
+
def deserialize(str)
|
15
|
+
GlobalID::Locator.locate(str)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module AnyCable
|
4
|
+
module Rails
|
5
|
+
class PubSubChannel < ActionCable::Channel::Base
|
6
|
+
def subscribed
|
7
|
+
stream_name =
|
8
|
+
if params[:stream_name] && connection.allow_public_streams?
|
9
|
+
params[:stream_name]
|
10
|
+
elsif params[:signed_stream_name]
|
11
|
+
AnyCable::Streams.verified(params[:signed_stream_name])
|
12
|
+
end
|
13
|
+
|
14
|
+
if stream_name
|
15
|
+
stream_from stream_name
|
16
|
+
else
|
17
|
+
reject
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -4,6 +4,7 @@ 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
6
|
require "anycable/rails/action_cable_ext/broadcast_options"
|
7
|
+
require "anycable/rails/action_cable_ext/signed_streams"
|
7
8
|
|
8
9
|
require "anycable/rails/channel_state"
|
9
10
|
require "anycable/rails/connection_factory"
|
@@ -17,6 +18,19 @@ module AnyCable
|
|
17
18
|
app.config.action_cable.mount_path = nil
|
18
19
|
end
|
19
20
|
|
21
|
+
initializer "anycable.websocket_url", after: "action_cable.set_configs" do |app|
|
22
|
+
next unless AnyCable::Rails.enabled?
|
23
|
+
|
24
|
+
websocket_url = AnyCable.config.websocket_url.presence
|
25
|
+
next unless websocket_url
|
26
|
+
|
27
|
+
app.config.action_cable.url = websocket_url
|
28
|
+
|
29
|
+
ActiveSupport.on_load(:action_cable) do
|
30
|
+
::ActionCable.server.config.url = websocket_url
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
20
34
|
initializer "anycable.logger", after: "action_cable.logger" do |_app|
|
21
35
|
AnyCable.logger = ::ActionCable.server.config.logger
|
22
36
|
|
@@ -51,6 +65,11 @@ module AnyCable
|
|
51
65
|
end
|
52
66
|
end
|
53
67
|
|
68
|
+
initializer "anycable.object_serializer" do |_app|
|
69
|
+
require "anycable/rails/object_serializer"
|
70
|
+
AnyCable::Serializer.object_serializer = AnyCable::Rails::ObjectSerializer
|
71
|
+
end
|
72
|
+
|
54
73
|
initializer "anycable.executor" do |app|
|
55
74
|
require "anycable/rails/middlewares/executor"
|
56
75
|
# see https://github.com/rails/rails/pull/33469/files
|
@@ -131,6 +150,12 @@ module AnyCable
|
|
131
150
|
end
|
132
151
|
end
|
133
152
|
|
153
|
+
initializer "anycable.helpers" do
|
154
|
+
ActiveSupport.on_load(:action_view) do
|
155
|
+
include AnyCable::Rails::Helper
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
134
159
|
# Since Rails 6.1
|
135
160
|
if respond_to?(:server)
|
136
161
|
server do
|
data/lib/anycable/rails.rb
CHANGED
@@ -8,9 +8,14 @@ require "anycable/rails/rack"
|
|
8
8
|
require "globalid"
|
9
9
|
require "active_support/core_ext/module/attribute_accessors_per_thread"
|
10
10
|
|
11
|
+
require "anycable/rails/ext"
|
12
|
+
|
11
13
|
module AnyCable
|
12
14
|
# Rails handler for AnyCable
|
13
15
|
module Rails
|
16
|
+
autoload :Helper, "anycable/rails/helper"
|
17
|
+
autoload :PubSubChannel, "anycable/rails/pubsub_channel"
|
18
|
+
|
14
19
|
require "anycable/rails/railtie"
|
15
20
|
|
16
21
|
ADAPTER_ALIASES = %w[any_cable anycable].freeze
|
@@ -51,28 +56,15 @@ module AnyCable
|
|
51
56
|
end
|
52
57
|
end
|
53
58
|
|
54
|
-
|
55
|
-
|
56
|
-
def serialize(obj, json: false)
|
57
|
-
obj.try(:to_gid_param) || (json ? obj.to_json : obj)
|
59
|
+
def signed_stream_name(streamables)
|
60
|
+
Streams.signed(stream_name_from(streamables))
|
58
61
|
end
|
59
62
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
next val unless val.is_a?(String)
|
66
|
-
|
67
|
-
gval = GlobalID::Locator.locate(val)
|
68
|
-
return gval if gval
|
69
|
-
|
70
|
-
next val unless json
|
71
|
-
|
72
|
-
JSON.parse(val)
|
73
|
-
end.yield_self do |val|
|
74
|
-
next val.with_indifferent_access if val.is_a?(Hash)
|
75
|
-
val
|
63
|
+
def stream_name_from(streamables)
|
64
|
+
if streamables.is_a?(Array)
|
65
|
+
streamables.map { |streamable| stream_name_from(streamable) }.join(":")
|
66
|
+
else
|
67
|
+
streamables.then { |streamable| streamable.try(:to_gid_param) || streamable.to_param }
|
76
68
|
end
|
77
69
|
end
|
78
70
|
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "generators/anycable/with_os_helpers"
|
4
|
+
|
5
|
+
module AnyCableRailsGenerators
|
6
|
+
# Generates bin/anycable-go binstub
|
7
|
+
class BinGenerator < ::Rails::Generators::Base
|
8
|
+
namespace "anycable:bin"
|
9
|
+
|
10
|
+
source_root File.expand_path("templates", __dir__)
|
11
|
+
|
12
|
+
class_option :version,
|
13
|
+
type: :string,
|
14
|
+
desc: "Specify AnyCable server version (defaults to latest release)",
|
15
|
+
version: "latest"
|
16
|
+
|
17
|
+
def generate_bin
|
18
|
+
inside("bin") do
|
19
|
+
template "anycable-go"
|
20
|
+
chmod "anycable-go", 0755, verbose: false # rubocop:disable Style/NumericLiteralPrefix
|
21
|
+
end
|
22
|
+
|
23
|
+
in_root do
|
24
|
+
next unless File.file?(".gitignore")
|
25
|
+
|
26
|
+
ignores = File.read(".gitignore").lines
|
27
|
+
|
28
|
+
if ignores.none? { |line| line.match?(/^bin\/dist$/) }
|
29
|
+
append_file ".gitignore", "bin/dist\n"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
true
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def anycable_go_version
|
39
|
+
@anycable_go_version ||= normalize_version(options[:version]) || "latest"
|
40
|
+
end
|
41
|
+
|
42
|
+
def normalize_version(version)
|
43
|
+
return unless version
|
44
|
+
return if version.chomp == "latest"
|
45
|
+
|
46
|
+
# We need a full version for bin/anycable-go script
|
47
|
+
segments = Gem::Version.new(version).segments
|
48
|
+
segments << 0 until segments.size >= 3
|
49
|
+
segments.join(".")
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/bin/bash
|
2
|
+
|
3
|
+
cd $(dirname $0)/..
|
4
|
+
|
5
|
+
# It's recommended to use the exact version of AnyCable here
|
6
|
+
version="<%= anycable_go_version %>"
|
7
|
+
|
8
|
+
if [ ! -f ./bin/dist/anycable-go ]; then
|
9
|
+
echo "AnyCable server 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 server 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 $@
|
@@ -1,5 +1,5 @@
|
|
1
1
|
Description:
|
2
|
-
Install AnyCable-
|
2
|
+
Install AnyCable real-time server locally (the latest version by default).
|
3
3
|
|
4
4
|
Example:
|
5
5
|
rails generate anycable:download
|
@@ -11,4 +11,4 @@ Example:
|
|
11
11
|
|
12
12
|
rails generate anycable:download --bin-path=/usr/local/bin
|
13
13
|
|
14
|
-
rails generate anycable:download --version=1.
|
14
|
+
rails generate anycable:download --version=1.4.0
|
@@ -13,10 +13,10 @@ module AnyCableRailsGenerators
|
|
13
13
|
|
14
14
|
class_option :bin_path,
|
15
15
|
type: :string,
|
16
|
-
desc: "Where to download AnyCable
|
16
|
+
desc: "Where to download AnyCable server binary (default: #{DEFAULT_BIN_PATH})"
|
17
17
|
class_option :version,
|
18
18
|
type: :string,
|
19
|
-
desc: "Specify the AnyCable
|
19
|
+
desc: "Specify the AnyCable version (defaults to latest release)"
|
20
20
|
|
21
21
|
def download_bin
|
22
22
|
out = options[:bin_path] || DEFAULT_BIN_PATH
|
@@ -74,7 +74,7 @@ module AnyCableRailsGenerators
|
|
74
74
|
if yes? "Path is not writable 😕. Do you have sudo privileges?"
|
75
75
|
sudo = "sudo "
|
76
76
|
else
|
77
|
-
say_status :error, "❌ Failed to install AnyCable-
|
77
|
+
say_status :error, "❌ Failed to install AnyCable real-time server", :red
|
78
78
|
raise StandardError, "Path #{path} is not writable!"
|
79
79
|
end
|
80
80
|
end
|
@@ -10,105 +10,63 @@ module AnyCableRailsGenerators
|
|
10
10
|
|
11
11
|
DOCS_ROOT = "https://docs.anycable.io"
|
12
12
|
DEVELOPMENT_METHODS = %w[skip local docker].freeze
|
13
|
-
|
13
|
+
DEPLOYMENT_METHODS = %w[other fly heroku anycable_plus].freeze
|
14
|
+
RPC_IMPL = %w[none grpc http].freeze
|
14
15
|
|
15
16
|
class_option :devenv,
|
16
17
|
type: :string,
|
17
|
-
desc: "Select your development environment (options: #{DEVELOPMENT_METHODS.join(", ")})"
|
18
|
+
desc: "Select your development environment (options: #{DEVELOPMENT_METHODS.reverse.join(", ")})"
|
18
19
|
class_option :rpc,
|
19
20
|
type: :string,
|
20
|
-
desc: "Select RPC implementation (options: #{RPC_IMPL.join(", ")})"
|
21
|
-
|
22
|
-
class_option :skip_heroku,
|
21
|
+
desc: "Select RPC implementation (options: #{RPC_IMPL.reverse.join(", ")})"
|
22
|
+
class_option :skip_procfile,
|
23
23
|
type: :boolean,
|
24
|
-
desc: "Do not
|
25
|
-
class_option :skip_procfile_dev,
|
26
|
-
type: :boolean,
|
27
|
-
desc: "Do not create Procfile.dev"
|
28
|
-
class_option :skip_jwt,
|
29
|
-
type: :boolean,
|
30
|
-
desc: "Do not install anycable-rails-jwt"
|
31
|
-
class_option :skip_install,
|
32
|
-
type: :boolean,
|
33
|
-
desc: "Do not run bundle install when adding new gems"
|
24
|
+
desc: "Do not create/update Procfile.dev"
|
34
25
|
class_option :version,
|
35
26
|
type: :string,
|
36
|
-
desc: "Specify
|
27
|
+
desc: "Specify AnyCable server version (defaults to latest release)",
|
28
|
+
default: "latest"
|
37
29
|
|
38
30
|
def welcome
|
39
|
-
say "
|
31
|
+
say ""
|
32
|
+
say "👋 Welcome to AnyCable interactive installer. We'll guide you through the process of installing AnyCable for your Rails application. Buckle up!"
|
33
|
+
say ""
|
40
34
|
end
|
41
35
|
|
42
|
-
def
|
43
|
-
|
44
|
-
|
45
|
-
template "anycable.yml"
|
46
|
-
end
|
47
|
-
end
|
36
|
+
def rpc_implementation
|
37
|
+
say "AnyCable connects to your Rails server to communicate with Action Cable channels (via RPC API). Learn more from the docs 👉 #{DOCS_ROOT}/anycable-go/rpc"
|
38
|
+
say ""
|
48
39
|
|
49
|
-
|
50
|
-
environment(nil, env: :development) do
|
51
|
-
<<~SNIPPET
|
52
|
-
# Specify AnyCable WebSocket server URL to use by JS client
|
53
|
-
config.after_initialize do
|
54
|
-
config.action_cable.url = ActionCable.server.config.url = ENV.fetch("CABLE_URL", "ws://localhost:8080/cable") if AnyCable::Rails.enabled?
|
55
|
-
end
|
56
|
-
SNIPPET
|
57
|
-
end
|
40
|
+
answer = RPC_IMPL.index(options[:rpc]) || 99
|
58
41
|
|
59
|
-
|
60
|
-
|
61
|
-
# Specify AnyCable WebSocket server URL to use by JS client
|
62
|
-
config.after_initialize do
|
63
|
-
config.action_cable.url = ActionCable.server.config.url = ENV.fetch("CABLE_URL", "/cable") if AnyCable::Rails.enabled?
|
64
|
-
end
|
65
|
-
SNIPPET
|
42
|
+
until RPC_IMPL[answer.to_i]
|
43
|
+
answer = ask "Do you want to use gRPC or HTTP for AnyCable RPC? (1) gRPC, (2) HTTP, (0) None"
|
66
44
|
end
|
67
45
|
|
68
|
-
|
69
|
-
say_status :help, "⚠️ If you're using JS client make sure you have " \
|
70
|
-
"`action_cable_meta_tag` included before any <script> tag in your application.html"
|
46
|
+
@rpc_impl = RPC_IMPL[answer.to_i]
|
71
47
|
end
|
72
48
|
|
73
49
|
def development_method
|
74
50
|
answer = DEVELOPMENT_METHODS.index(options[:devenv]) || 99
|
75
51
|
|
52
|
+
say ""
|
53
|
+
|
76
54
|
until DEVELOPMENT_METHODS[answer.to_i]
|
77
|
-
answer = ask "Do you want to run anycable-go locally or as a Docker container? (1) Local, (2) Docker, (0) Skip"
|
55
|
+
answer = ask "Do you want to run AnyCable server (anycable-go) locally or as a Docker container? (1) Local, (2) Docker, (0) Skip"
|
78
56
|
end
|
79
57
|
|
80
|
-
|
58
|
+
@devenv = DEVELOPMENT_METHODS[answer.to_i]
|
59
|
+
|
60
|
+
case @devenv
|
81
61
|
when "skip"
|
82
|
-
say_status :help, "⚠️ Please, read this guide on how to install AnyCable
|
62
|
+
say_status :help, "⚠️ Please, read this guide on how to install AnyCable server 👉 #{DOCS_ROOT}/anycable-go/getting_started", :yellow
|
83
63
|
else
|
84
|
-
send "install_for_#{
|
64
|
+
send "install_for_#{@devenv}"
|
85
65
|
end
|
86
66
|
end
|
87
67
|
|
88
|
-
def heroku
|
89
|
-
if options[:skip_heroku].nil?
|
90
|
-
return unless yes? "Do you use Heroku for deployment? [Yn]"
|
91
|
-
elsif options[:skip_heroku]
|
92
|
-
return
|
93
|
-
end
|
94
|
-
|
95
|
-
in_root do
|
96
|
-
next unless File.file?("Procfile")
|
97
|
-
next if http_rpc?
|
98
|
-
|
99
|
-
contents = File.read("Procfile")
|
100
|
-
contents.sub!(/^web: (.*)$/, %q(web: [[ "$ANYCABLE_DEPLOYMENT" == "true" ]] && bundle exec anycable --server-command="anycable-go" || \1))
|
101
|
-
File.write("Procfile", contents)
|
102
|
-
say_status :info, "✅ Procfile updated"
|
103
|
-
end
|
104
|
-
|
105
|
-
say_status :help, "️️⚠️ Please, read the required steps to configure Heroku applications 👉 #{DOCS_ROOT}/deployment/heroku", :yellow
|
106
|
-
end
|
107
|
-
|
108
68
|
def devise
|
109
|
-
|
110
|
-
return unless File.file?("config/initializers/devise.rb")
|
111
|
-
end
|
69
|
+
return unless devise?
|
112
70
|
|
113
71
|
inside("config/initializers") do
|
114
72
|
template "anycable.rb"
|
@@ -117,10 +75,12 @@ module AnyCableRailsGenerators
|
|
117
75
|
say_status :info, "✅ config/initializers/anycable.rb with Devise configuration has been added"
|
118
76
|
end
|
119
77
|
|
120
|
-
def
|
121
|
-
|
78
|
+
def configs
|
79
|
+
inside("config") do
|
80
|
+
template "anycable.yml"
|
81
|
+
end
|
122
82
|
|
123
|
-
|
83
|
+
update_cable_yml
|
124
84
|
end
|
125
85
|
|
126
86
|
def rubocop_compatibility
|
@@ -131,14 +91,15 @@ module AnyCableRailsGenerators
|
|
131
91
|
say_status :help, "⚠️ Please, take a look at the icompatibilities above and fix them. See #{DOCS_ROOT}/rails/compatibility" unless res
|
132
92
|
end
|
133
93
|
|
134
|
-
def
|
135
|
-
|
136
|
-
|
137
|
-
|
94
|
+
def cable_url_info
|
95
|
+
say_status :help, "⚠️ If you're using JS client make sure you have " \
|
96
|
+
"`action_cable_meta_tag` or `action_cable_with_jwt_meta_tag` included in your HTML layout"
|
97
|
+
end
|
138
98
|
|
139
|
-
|
99
|
+
def deployment_method
|
100
|
+
say_status :info, "🚢 See our deployment guide to learn how to run AnyCable in production 👉 #{DOCS_ROOT}/deployment"
|
140
101
|
|
141
|
-
|
102
|
+
say_status :info, "Check out AnyCable+, our hosted AnyCable solution: https://plus.anycable.io"
|
142
103
|
end
|
143
104
|
|
144
105
|
def finish
|
@@ -147,10 +108,6 @@ module AnyCableRailsGenerators
|
|
147
108
|
|
148
109
|
private
|
149
110
|
|
150
|
-
def stimulus_reflex?
|
151
|
-
!!gemfile_lock&.match?(/^\s+stimulus_reflex\b/)
|
152
|
-
end
|
153
|
-
|
154
111
|
def redis?
|
155
112
|
!!gemfile_lock&.match?(/^\s+redis\b/)
|
156
113
|
end
|
@@ -167,8 +124,20 @@ module AnyCableRailsGenerators
|
|
167
124
|
!!gemfile_lock&.match?(/^\s+rubocop\b/)
|
168
125
|
end
|
169
126
|
|
127
|
+
def devise?
|
128
|
+
!!gemfile_lock&.match?(/^\s+devise\b/)
|
129
|
+
end
|
130
|
+
|
131
|
+
def local?
|
132
|
+
@devenv == "local"
|
133
|
+
end
|
134
|
+
|
135
|
+
def grpc?
|
136
|
+
@rpc_impl == "grpc"
|
137
|
+
end
|
138
|
+
|
170
139
|
def http_rpc?
|
171
|
-
|
140
|
+
@rpc_impl == "http"
|
172
141
|
end
|
173
142
|
|
174
143
|
def gemfile_lock
|
@@ -183,83 +152,143 @@ module AnyCableRailsGenerators
|
|
183
152
|
end
|
184
153
|
|
185
154
|
def install_for_docker
|
186
|
-
# Remove localhost from configuraiton
|
187
|
-
gsub_file "config/anycable.yml", /^.*redis_url:.*localhost[^\n]+\n/, ""
|
188
|
-
|
189
155
|
say_status :help, "️️⚠️ Docker development configuration could vary", :yellow
|
190
156
|
|
191
|
-
say "Here is an example snippet for
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
157
|
+
say "Here is an example snippet for Docker Compose:"
|
158
|
+
|
159
|
+
if @rpc_impl == "grpc"
|
160
|
+
say <<~YML
|
161
|
+
─────────────────────────────────────────
|
162
|
+
# your Rails application service
|
163
|
+
rails: &rails
|
164
|
+
# ...
|
165
|
+
ports:
|
166
|
+
- '3000:3000'
|
167
|
+
environment: &rails_environment
|
168
|
+
# ...
|
169
|
+
ANYCABLE_HTTP_BROADCAST_URL: http://ws:8090/_broadcast
|
170
|
+
depends_on: &rails_depends_on
|
171
|
+
#...
|
172
|
+
anycable:
|
173
|
+
condition: service_started
|
174
|
+
|
175
|
+
ws:
|
176
|
+
image: anycable/anycable-go:1.5
|
177
|
+
ports:
|
178
|
+
- '8080:8080'
|
179
|
+
- '8090'
|
180
|
+
environment:
|
181
|
+
ANYCABLE_HOST: "0.0.0.0"
|
182
|
+
ANYCABLE_BROADCAST_ADAPTER: http
|
183
|
+
ANYCABLE_RPC_HOST: anycable:50051
|
184
|
+
ANYCABLE_DEBUG: ${ANYCABLE_DEBUG:-true}
|
185
|
+
|
186
|
+
anycable:
|
187
|
+
<<: *rails
|
188
|
+
command: bundle exec anycable
|
189
|
+
environment:
|
190
|
+
<<: *rails_environment
|
191
|
+
ANYCABLE_RPC_HOST: 0.0.0.0:50051
|
192
|
+
ports:
|
193
|
+
- '50051'
|
194
|
+
depends_on:
|
195
|
+
<<: *rails_depends_on
|
196
|
+
ws:
|
197
|
+
condition: service_started
|
198
|
+
─────────────────────────────────────────
|
199
|
+
YML
|
200
|
+
else
|
201
|
+
say <<~YML
|
202
|
+
─────────────────────────────────────────
|
203
|
+
# Your Rails application service
|
204
|
+
rails: &rails
|
205
|
+
# ...
|
206
|
+
ports:
|
207
|
+
- '3000:3000'
|
208
|
+
environment: &rails_environment
|
209
|
+
# ...
|
210
|
+
ANYCABLE_HTTP_BROADCAST_URL: http://ws:8090/_broadcast
|
211
|
+
depends_on: &rails_depends_on
|
212
|
+
#...
|
213
|
+
anycable:
|
214
|
+
condition: service_started
|
215
|
+
|
216
|
+
ws:
|
217
|
+
image: anycable/anycable-go:1.5
|
218
|
+
ports:
|
219
|
+
- '8080:8080'
|
220
|
+
environment:
|
221
|
+
ANYCABLE_HOST: "0.0.0.0"
|
222
|
+
ANYCABLE_BROADCAST_ADAPTER: http
|
223
|
+
ANYCABLE_RPC_HOST: http://rails:3000/_anycable
|
224
|
+
ANYCABLE_DEBUG: ${ANYCABLE_DEBUG:-true}
|
225
|
+
─────────────────────────────────────────
|
226
|
+
YML
|
227
|
+
end
|
223
228
|
end
|
224
229
|
|
225
230
|
def install_for_local
|
226
|
-
|
227
|
-
|
228
|
-
chmod "anycable-go", 0755, verbose: false # rubocop:disable Style/NumericLiteralPrefix
|
231
|
+
unless file_exists?("bin/anycable-go")
|
232
|
+
generate "anycable:bin", "--version #{options[:version]}"
|
229
233
|
end
|
234
|
+
template_proc_files
|
235
|
+
true
|
236
|
+
end
|
230
237
|
|
231
|
-
|
232
|
-
|
233
|
-
|
238
|
+
def update_cable_yml
|
239
|
+
if file_exists?("config/cable.yml")
|
240
|
+
in_root do
|
241
|
+
contents = File.read("config/cable.yml")
|
242
|
+
# Replace any adapter: x with any_cable unless x == "test"
|
243
|
+
new_contents = contents.gsub(/\sadapter:\s*([^$\n]+)/) do |match|
|
244
|
+
adapter = Regexp.last_match[1]
|
245
|
+
next match if adapter == "test" || adapter.include?("any_cable")
|
234
246
|
|
235
|
-
|
247
|
+
match.sub(adapter, %(<%= ENV.fetch("ACTION_CABLE_ADAPTER", "any_cable") %>))
|
248
|
+
end
|
249
|
+
|
250
|
+
File.write "config/cable.yml", new_contents
|
251
|
+
end
|
252
|
+
else
|
253
|
+
inside("config") do
|
254
|
+
template "cable.yml"
|
255
|
+
end
|
256
|
+
end
|
236
257
|
end
|
237
258
|
|
238
259
|
def template_proc_files
|
239
260
|
file_name = "Procfile.dev"
|
240
261
|
|
241
262
|
if file_exists?(file_name)
|
242
|
-
|
243
|
-
append_file file_name, "anycable: bundle exec anycable\n", force: true
|
244
|
-
end
|
245
|
-
append_file file_name, "ws: bin/anycable-go #{anycable_go_options}", force: true
|
263
|
+
update_procfile(file_name)
|
246
264
|
else
|
247
|
-
say_status :help, "💡 We recommend using
|
265
|
+
say_status :help, "💡 We recommend using Overmind to manage multiple processes in development 👉 https://github.com/DarthSim/overmind", :yellow
|
248
266
|
|
249
|
-
if options[:skip_procfile_dev]
|
250
|
-
return unless yes? "Do you want to create a '#{file_name}' file?"
|
251
|
-
elsif options[:skip_procfile_dev]
|
252
|
-
return
|
253
|
-
end
|
267
|
+
return if options[:skip_procfile_dev]
|
254
268
|
|
255
269
|
template file_name
|
256
270
|
end
|
257
271
|
end
|
258
272
|
|
273
|
+
def update_procfile(file_name)
|
274
|
+
in_root do
|
275
|
+
contents = File.read(file_name)
|
276
|
+
|
277
|
+
unless http_rpc?
|
278
|
+
unless contents.match?(/^anycable:\s/)
|
279
|
+
append_file file_name, "anycable: bundle exec anycable\n", force: true
|
280
|
+
end
|
281
|
+
end
|
282
|
+
unless contents.match?(/^ws:\s/)
|
283
|
+
append_file file_name, "ws: bin/anycable-go #{anycable_go_options}", force: true
|
284
|
+
end
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
259
288
|
def anycable_go_options
|
260
289
|
opts = ["--port=8080"]
|
261
290
|
opts << "--broadcast_adapter=http" unless redis?
|
262
|
-
opts << "--
|
291
|
+
opts << "--rpc_host=http://localhost:3000/_anycable" if http_rpc?
|
263
292
|
opts.join(" ")
|
264
293
|
end
|
265
294
|
|
@@ -268,18 +297,5 @@ module AnyCableRailsGenerators
|
|
268
297
|
return File.file?(name)
|
269
298
|
end
|
270
299
|
end
|
271
|
-
|
272
|
-
def anycable_go_version
|
273
|
-
@anycable_go_version ||= normalize_version(options[:version]) || "latest"
|
274
|
-
end
|
275
|
-
|
276
|
-
def normalize_version(version)
|
277
|
-
return unless version
|
278
|
-
|
279
|
-
# We need a full version for bin/anycable-go script
|
280
|
-
segments = Gem::Version.new(version).segments
|
281
|
-
segments << 0 until segments.size >= 3
|
282
|
-
segments.join(".")
|
283
|
-
end
|
284
300
|
end
|
285
301
|
end
|
@@ -2,11 +2,11 @@
|
|
2
2
|
|
3
3
|
cd $(dirname $0)/..
|
4
4
|
|
5
|
-
# It's recommended to use the exact version of AnyCable
|
5
|
+
# It's recommended to use the exact version of AnyCable here
|
6
6
|
version="<%= anycable_go_version %>"
|
7
7
|
|
8
8
|
if [ ! -f ./bin/dist/anycable-go ]; then
|
9
|
-
echo "AnyCable
|
9
|
+
echo "AnyCable server is not installed, downloading..."
|
10
10
|
./bin/rails g anycable:download --version=$version --bin-path=./bin/dist
|
11
11
|
fi
|
12
12
|
|
@@ -14,7 +14,7 @@ curVersion=$(./bin/dist/anycable-go -v)
|
|
14
14
|
|
15
15
|
if [[ "$version" != "latest" ]]; then
|
16
16
|
if [[ "$curVersion" != "$version"* ]]; then
|
17
|
-
echo "AnyCable
|
17
|
+
echo "AnyCable server version is not $version, downloading a new one..."
|
18
18
|
./bin/rails g anycable:download --version=$version --bin-path=./bin/dist
|
19
19
|
fi
|
20
20
|
fi
|
@@ -21,26 +21,33 @@ default: &default
|
|
21
21
|
# Use NATS to broadcast messages to AnyCable server
|
22
22
|
broadcast_adapter: nats
|
23
23
|
<%- else -%>
|
24
|
-
# Use HTTP
|
24
|
+
# Use HTTP broadcaster
|
25
25
|
broadcast_adapter: http
|
26
26
|
<%- end -%>
|
27
|
-
# Use the same channel name for WebSocket server, e.g.:
|
28
|
-
# $ anycable-go --redis_channel="__anycable__"
|
29
|
-
redis_channel: "__anycable__"
|
30
27
|
<%- if redis? -%>
|
31
28
|
# You can use REDIS_URL env var to configure Redis URL.
|
32
29
|
# Localhost is used by default.
|
33
30
|
# redis_url: "redis://localhost:6379/1"
|
31
|
+
# Use the same channel name for WebSocket server, e.g.:
|
32
|
+
# $ anycable-go --redis_channel="__anycable__"
|
33
|
+
# redis_channel: "__anycable__"
|
34
34
|
<%- end -%>
|
35
35
|
<%- if http_rpc? -%>
|
36
|
+
# Use HTTP RPC mounted at the specified path of your web server
|
37
|
+
# Read more about AnyCable RPC: <%= DOCS_ROOT %>/anycable-go/rpc
|
36
38
|
http_rpc_mount_path: "/_anycable"
|
37
39
|
<%- end -%>
|
38
40
|
|
39
41
|
development:
|
40
42
|
<<: *default
|
43
|
+
# WebSocket endpoint of your AnyCable server for clients to connect to
|
44
|
+
# Make sure you have the `action_cable_meta_tag` in your HTML layout
|
45
|
+
# to propogate this value to the client app
|
46
|
+
websocket_url: "ws://localhost:8080/cable"
|
41
47
|
|
42
48
|
test:
|
43
49
|
<<: *default
|
44
50
|
|
45
51
|
production:
|
46
52
|
<<: *default
|
53
|
+
websocket_url: ~
|
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: anycable-rails-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.0.rc.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- palkan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-03-
|
11
|
+
date: 2024-03-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: anycable-core
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - '='
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 1.5.0.rc.1
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - '='
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version:
|
26
|
+
version: 1.5.0.rc.1
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: actioncable
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -70,6 +70,7 @@ files:
|
|
70
70
|
- lib/anycable/rails/action_cable_ext/channel.rb
|
71
71
|
- lib/anycable/rails/action_cable_ext/connection.rb
|
72
72
|
- lib/anycable/rails/action_cable_ext/remote_connections.rb
|
73
|
+
- lib/anycable/rails/action_cable_ext/signed_streams.rb
|
73
74
|
- lib/anycable/rails/channel_state.rb
|
74
75
|
- lib/anycable/rails/compatibility.rb
|
75
76
|
- lib/anycable/rails/compatibility/rubocop.rb
|
@@ -83,12 +84,20 @@ files:
|
|
83
84
|
- lib/anycable/rails/connections/persistent_session.rb
|
84
85
|
- lib/anycable/rails/connections/serializable_identification.rb
|
85
86
|
- lib/anycable/rails/connections/session_proxy.rb
|
87
|
+
- lib/anycable/rails/ext.rb
|
88
|
+
- lib/anycable/rails/ext/jwt.rb
|
89
|
+
- lib/anycable/rails/helper.rb
|
86
90
|
- lib/anycable/rails/middlewares/executor.rb
|
87
91
|
- lib/anycable/rails/middlewares/log_tagging.rb
|
92
|
+
- lib/anycable/rails/object_serializer.rb
|
93
|
+
- lib/anycable/rails/pubsub_channel.rb
|
88
94
|
- lib/anycable/rails/rack.rb
|
89
95
|
- lib/anycable/rails/railtie.rb
|
90
96
|
- lib/anycable/rails/socket_id_tracking.rb
|
91
97
|
- lib/anycable/rails/version.rb
|
98
|
+
- lib/generators/anycable/bin/USAGE
|
99
|
+
- lib/generators/anycable/bin/bin_generator.rb
|
100
|
+
- lib/generators/anycable/bin/templates/bin/anycable-go.tt
|
92
101
|
- lib/generators/anycable/download/USAGE
|
93
102
|
- lib/generators/anycable/download/download_generator.rb
|
94
103
|
- lib/generators/anycable/setup/USAGE
|
@@ -120,9 +129,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
120
129
|
version: '2.7'
|
121
130
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
122
131
|
requirements:
|
123
|
-
- - "
|
132
|
+
- - ">"
|
124
133
|
- !ruby/object:Gem::Version
|
125
|
-
version:
|
134
|
+
version: 1.3.1
|
126
135
|
requirements: []
|
127
136
|
rubygems_version: 3.4.20
|
128
137
|
signing_key:
|