anycable-rails-core 1.5.3 → 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 +31 -1
- data/README.md +10 -75
- data/lib/anycable/rails/action_cable_ext/channel.rb +20 -11
- data/lib/anycable/rails/action_cable_ext/remote_connections.rb +4 -14
- 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 +2 -0
- data/lib/anycable/rails/config.rb +2 -0
- data/lib/anycable/rails/connection.rb +62 -33
- data/lib/anycable/rails/connection_factory.rb +20 -1
- data/lib/anycable/rails/connections/persistent_session.rb +5 -0
- data/lib/anycable/rails/connections/serializable_identification.rb +19 -0
- data/lib/anycable/rails/connections/session_proxy.rb +2 -2
- data/lib/anycable/rails/ext/jwt.rb +1 -1
- data/lib/anycable/rails/ext/signed_streams.rb +21 -0
- data/lib/anycable/rails/ext/whisper.rb +34 -0
- data/lib/anycable/rails/ext.rb +4 -1
- data/lib/anycable/rails/helper.rb +2 -2
- data/lib/anycable/rails/next/action_cable_ext/channel.rb +36 -0
- data/lib/anycable/rails/next/action_cable_ext/connection.rb +29 -0
- data/lib/anycable/rails/next/connection/persistent_session.rb +39 -0
- data/lib/anycable/rails/next/connection.rb +226 -0
- data/lib/anycable/rails/railtie.rb +4 -8
- 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/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 +280 -38
- data/lib/generators/anycable/setup/templates/Procfile.dev.tt +2 -2
- data/lib/generators/anycable/setup/templates/anycable.toml.tt +81 -0
- 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 +20 -33
- data/lib/generators/anycable/setup/templates/config/cable.yml.tt +2 -5
- metadata +27 -16
- data/lib/anycable/rails/action_cable_ext/signed_streams.rb +0 -31
- /data/lib/anycable/rails/{compatibility/rubocop → rubocop}/config/default.yml +0 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "action_cable"
|
|
4
|
+
require "anycable/rails/connections/serializable_identification"
|
|
5
|
+
|
|
6
|
+
ActionCable::Connection::Base.include(AnyCable::Rails::Connections::SerializableIdentification)
|
|
7
|
+
ActionCable::Connection::Base.prepend(Module.new do
|
|
8
|
+
def anycabled?
|
|
9
|
+
anycable_socket
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Allow overriding #subscriptions to use a custom implementation
|
|
13
|
+
attr_writer :subscriptions
|
|
14
|
+
|
|
15
|
+
# Alias for the #socket which is only set within AnyCable RPC context
|
|
16
|
+
attr_accessor :anycable_socket
|
|
17
|
+
|
|
18
|
+
# Enhance #send_welcome_message to include sid if present
|
|
19
|
+
def send_welcome_message
|
|
20
|
+
transmit({
|
|
21
|
+
type: ActionCable::INTERNAL[:message_types][:welcome],
|
|
22
|
+
sid: env["anycable.sid"]
|
|
23
|
+
}.compact)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def subscribe_to_internal_channel
|
|
27
|
+
super unless anycabled?
|
|
28
|
+
end
|
|
29
|
+
end)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "anycable/rails/connections/session_proxy"
|
|
4
|
+
|
|
5
|
+
module AnyCable
|
|
6
|
+
module Rails
|
|
7
|
+
module Connections
|
|
8
|
+
module PersistentSession
|
|
9
|
+
def handle_open
|
|
10
|
+
super.tap { commit_session! }
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def handle_channel_command(*)
|
|
14
|
+
super.tap { commit_session! }
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def request
|
|
18
|
+
@request ||= super.tap do |req|
|
|
19
|
+
next unless socket.session
|
|
20
|
+
req.env[::Rack::RACK_SESSION] =
|
|
21
|
+
SessionProxy.new(req.env[::Rack::RACK_SESSION], socket.session)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def commit_session!
|
|
28
|
+
return unless defined?(@request) && request.session.respond_to?(:loaded?) && request.session.loaded?
|
|
29
|
+
|
|
30
|
+
socket.session = request.session.to_json
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
AnyCable::Rails::Connection.prepend(
|
|
38
|
+
AnyCable::Rails::Connections::PersistentSession
|
|
39
|
+
)
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "action_cable"
|
|
4
|
+
|
|
5
|
+
module AnyCable
|
|
6
|
+
module Rails
|
|
7
|
+
class Current < ActiveSupport::CurrentAttributes
|
|
8
|
+
attribute :identifier
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
# Wrap ActionCable.server to provide a custom executor
|
|
12
|
+
# and a pubsub adapter
|
|
13
|
+
class Server < SimpleDelegator
|
|
14
|
+
# Implements an executor inteface
|
|
15
|
+
class Executor
|
|
16
|
+
class NoopTimer
|
|
17
|
+
def shutdown = nil
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
NOOP_TIMER = NoopTimer.new.freeze
|
|
21
|
+
|
|
22
|
+
def post(...)
|
|
23
|
+
raise NonImplementedError, "Executor#post is not implemented in AnyCable context"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def timer(...) = NOOP_TIMER
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# A signleton executor for all connections
|
|
30
|
+
EXECUTOR = Executor.new.freeze
|
|
31
|
+
|
|
32
|
+
# PubSub adapter to manage streams configuration
|
|
33
|
+
# for the underlying socket
|
|
34
|
+
class PubSub
|
|
35
|
+
private attr_reader :socket
|
|
36
|
+
|
|
37
|
+
ALL_STREAMS = Data.define(:to_str).new("all")
|
|
38
|
+
|
|
39
|
+
def initialize(socket) = @socket = socket
|
|
40
|
+
|
|
41
|
+
def subscribe(channel, _message_callback, success_callback = nil)
|
|
42
|
+
socket.subscribe identifier, channel
|
|
43
|
+
success_callback&.call
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def unsubscribe(channel, _message_callback)
|
|
47
|
+
if channel == ALL_STREAMS
|
|
48
|
+
socket.unsubscribe_from_all identifier
|
|
49
|
+
else
|
|
50
|
+
socket.unsubscribe identifier, channel
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
private
|
|
55
|
+
|
|
56
|
+
def identifier = Current.identifier
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
attr_accessor :pubsub, :executor
|
|
60
|
+
|
|
61
|
+
def self.for(server, socket)
|
|
62
|
+
new(server).tap do |srv|
|
|
63
|
+
srv.executor = EXECUTOR
|
|
64
|
+
srv.pubsub = PubSub.new(socket)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
class Connection
|
|
70
|
+
class Subscriptions < ::ActionCable::Connection::Subscriptions
|
|
71
|
+
# Wrap the original #execute_command to pre-initialize the channel for unsubscribe/message and
|
|
72
|
+
# return true/false to indicate successful/unsuccessful subscription.
|
|
73
|
+
def execute_command(data)
|
|
74
|
+
cmd = data["command"]
|
|
75
|
+
|
|
76
|
+
# We need the current channel identifier in pub/sub
|
|
77
|
+
Current.identifier = data["identifier"]
|
|
78
|
+
|
|
79
|
+
load(data["identifier"]) unless cmd == "subscribe"
|
|
80
|
+
|
|
81
|
+
super
|
|
82
|
+
|
|
83
|
+
return true unless cmd == "subscribe"
|
|
84
|
+
|
|
85
|
+
subscription = subscriptions[data["identifier"]]
|
|
86
|
+
!(subscription.nil? || subscription.rejected?)
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Restore channels from the list of identifiers and the state
|
|
90
|
+
def restore(subscriptions, istate)
|
|
91
|
+
subscriptions.each do |id|
|
|
92
|
+
channel = load(id)
|
|
93
|
+
channel.__istate__ = ActiveSupport::JSON.decode(istate[id]) if istate[id]
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# Find or create a channel for a given identifier
|
|
98
|
+
def load(identifier)
|
|
99
|
+
return subscriptions[identifier] if subscriptions[identifier]
|
|
100
|
+
|
|
101
|
+
subscription = subscription_from_identifier(identifier)
|
|
102
|
+
raise "Channel not found: #{ActiveSupport::JSON.decode(identifier).fetch("channel")}" unless subscription
|
|
103
|
+
|
|
104
|
+
subscriptions[identifier] = subscription
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# We store logger tags in the connection state to be able
|
|
109
|
+
# to re-use them in the subsequent calls
|
|
110
|
+
LOG_TAGS_IDENTIFIER = "__ltags__"
|
|
111
|
+
|
|
112
|
+
attr_reader :socket, :server
|
|
113
|
+
|
|
114
|
+
delegate :identifiers_json, to: :conn
|
|
115
|
+
delegate :cstate, :istate, to: :socket
|
|
116
|
+
|
|
117
|
+
def initialize(connection_class, socket, identifiers: nil, subscriptions: nil, server: ::ActionCable.server)
|
|
118
|
+
server = Server.for(server, socket)
|
|
119
|
+
|
|
120
|
+
@socket = socket
|
|
121
|
+
@server = server
|
|
122
|
+
# TODO: Move protocol to socket.env as "anycable.protocol"
|
|
123
|
+
@protocol = "actioncable-v1-json"
|
|
124
|
+
|
|
125
|
+
logger_tags = fetch_logger_tags_from_state
|
|
126
|
+
@logger = ActionCable::Server::TaggedLoggerProxy.new(AnyCable.logger, tags: logger_tags)
|
|
127
|
+
|
|
128
|
+
@conn = connection_class.new(server, self)
|
|
129
|
+
conn.subscriptions = Subscriptions.new(conn)
|
|
130
|
+
conn.identifiers_json = identifiers
|
|
131
|
+
conn.anycable_socket = socket
|
|
132
|
+
conn.subscriptions.restore(subscriptions, socket.istate) if subscriptions
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# == AnyCable RPC interface [BEGIN] ==
|
|
136
|
+
def handle_open
|
|
137
|
+
logger.info started_request_message if access_logs?
|
|
138
|
+
|
|
139
|
+
return close unless allow_request_origin?
|
|
140
|
+
|
|
141
|
+
conn.handle_open
|
|
142
|
+
|
|
143
|
+
# Commit log tags to the connection state
|
|
144
|
+
socket.cstate.write(LOG_TAGS_IDENTIFIER, logger.tags.to_json) unless logger.tags.empty?
|
|
145
|
+
|
|
146
|
+
socket.closed?
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def handle_close
|
|
150
|
+
conn.handle_close
|
|
151
|
+
close
|
|
152
|
+
true
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def handle_channel_command(identifier, command, data)
|
|
156
|
+
conn.handle_incoming({"command" => command, "identifier" => identifier, "data" => data})
|
|
157
|
+
end
|
|
158
|
+
# == AnyCable RPC interface [END] ==
|
|
159
|
+
|
|
160
|
+
# == Action Cable socket interface [BEGIN]
|
|
161
|
+
attr_reader :protocol, :logger
|
|
162
|
+
|
|
163
|
+
def request
|
|
164
|
+
@request ||= begin
|
|
165
|
+
env = socket.env
|
|
166
|
+
environment = ::Rails.application.env_config.merge(env) if defined?(::Rails.application) && ::Rails.application
|
|
167
|
+
AnyCable::Rails::Rack.app.call(environment) if environment
|
|
168
|
+
|
|
169
|
+
ActionDispatch::Request.new(environment || env)
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
delegate :env, to: :request
|
|
174
|
+
|
|
175
|
+
def transmit(data)
|
|
176
|
+
socket.transmit ActiveSupport::JSON.encode(data)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def close(...)
|
|
180
|
+
return if socket.closed?
|
|
181
|
+
logger.info finished_request_message if access_logs?
|
|
182
|
+
socket.close(...)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def perform_work(receiver, method_name, *args)
|
|
186
|
+
raise ArgumentError, "Performing work is not supported within AnyCable"
|
|
187
|
+
end
|
|
188
|
+
# == Action Cable socket interface [END]
|
|
189
|
+
|
|
190
|
+
private
|
|
191
|
+
|
|
192
|
+
attr_reader :conn
|
|
193
|
+
|
|
194
|
+
def fetch_logger_tags_from_state
|
|
195
|
+
socket.cstate.read(LOG_TAGS_IDENTIFIER).yield_self do |raw_tags|
|
|
196
|
+
next [] unless raw_tags
|
|
197
|
+
ActiveSupport::JSON.decode(raw_tags)
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
def started_request_message
|
|
202
|
+
format(
|
|
203
|
+
'Started "%s"%s for %s at %s',
|
|
204
|
+
request.filtered_path, " [AnyCable]", request.ip, Time.now.to_s
|
|
205
|
+
)
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def finished_request_message
|
|
209
|
+
format(
|
|
210
|
+
'Finished "%s"%s for %s at %s',
|
|
211
|
+
request.filtered_path, " [AnyCable]", request.ip, Time.now.to_s
|
|
212
|
+
)
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
def allow_request_origin?
|
|
216
|
+
return true unless socket.env.key?("HTTP_ORIGIN")
|
|
217
|
+
|
|
218
|
+
server.allow_request_origin?(socket.env)
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
def access_logs?
|
|
222
|
+
AnyCable.config.access_logs_disabled == false
|
|
223
|
+
end
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
end
|
|
@@ -1,11 +1,5 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "anycable/rails/action_cable_ext/connection"
|
|
4
|
-
require "anycable/rails/action_cable_ext/channel"
|
|
5
|
-
require "anycable/rails/action_cable_ext/remote_connections"
|
|
6
|
-
require "anycable/rails/action_cable_ext/broadcast_options"
|
|
7
|
-
require "anycable/rails/action_cable_ext/signed_streams"
|
|
8
|
-
|
|
9
3
|
require "anycable/rails/channel_state"
|
|
10
4
|
require "anycable/rails/connection_factory"
|
|
11
5
|
|
|
@@ -119,6 +113,7 @@ module AnyCable
|
|
|
119
113
|
initializer "anycable.routes" do
|
|
120
114
|
config.after_initialize do |app|
|
|
121
115
|
config = AnyCable.config
|
|
116
|
+
config.http_rpc_mount_path ||= "/_anycable" if config.http_rpc?
|
|
122
117
|
unless config.http_rpc_mount_path.nil?
|
|
123
118
|
app.routes.prepend do
|
|
124
119
|
mount AnyCable::HTTRPC::Server.new => config.http_rpc_mount_path, :internal => true
|
|
@@ -129,11 +124,12 @@ module AnyCable
|
|
|
129
124
|
|
|
130
125
|
initializer "anycable.verify_pool_sizes" do
|
|
131
126
|
next if AnyCable.config.disable_rpc_pool_size_warning?
|
|
132
|
-
# Skip if non-gRPC server is used
|
|
133
|
-
next unless AnyCable.config.respond_to?(:rpc_pool_size)
|
|
134
127
|
|
|
135
128
|
# Log current db vs. gRPC pool sizes
|
|
136
129
|
AnyCable.configure_server do
|
|
130
|
+
# Skip if non-gRPC server is used
|
|
131
|
+
next unless AnyCable.config.respond_to?(:rpc_pool_size)
|
|
132
|
+
|
|
137
133
|
ActiveSupport.on_load(:active_record) do
|
|
138
134
|
db_pool_size = ::ActiveRecord::Base.connection_pool.size
|
|
139
135
|
rpc_pool_size = AnyCable.config.rpc_pool_size
|
data/lib/anycable/rails/{compatibility/rubocop → rubocop}/cops/anycable/periodical_timers.rb
RENAMED
|
@@ -13,16 +13,11 @@ module RuboCop
|
|
|
13
13
|
# periodically(:do_something, every: 2.seconds)
|
|
14
14
|
# end
|
|
15
15
|
#
|
|
16
|
-
class PeriodicalTimers < RuboCop::Cop::
|
|
16
|
+
class PeriodicalTimers < RuboCop::Cop::Base
|
|
17
17
|
MSG = "Periodical Timers are not supported in AnyCable"
|
|
18
|
+
RESTRICT_ON_SEND = %i[periodically].freeze
|
|
18
19
|
|
|
19
|
-
|
|
20
|
-
(send _ :periodically ...)
|
|
21
|
-
PATTERN
|
|
22
|
-
|
|
23
|
-
def on_send(node)
|
|
24
|
-
add_offense(node) if calls_periodically?(node)
|
|
25
|
-
end
|
|
20
|
+
alias_method :on_send, :add_offense
|
|
26
21
|
end
|
|
27
22
|
end
|
|
28
23
|
end
|
|
@@ -34,7 +34,7 @@ module RuboCop
|
|
|
34
34
|
# end
|
|
35
35
|
# end
|
|
36
36
|
#
|
|
37
|
-
class StreamFrom < RuboCop::Cop::
|
|
37
|
+
class StreamFrom < RuboCop::Cop::Base
|
|
38
38
|
def_node_matcher :stream_from_with_block?, <<-PATTERN
|
|
39
39
|
(block {(send _ :stream_from ...) (send _ :stream_for ...)} ...)
|
|
40
40
|
PATTERN
|
|
@@ -81,16 +81,14 @@ module RuboCop
|
|
|
81
81
|
|
|
82
82
|
def add_callback_offense(node)
|
|
83
83
|
add_offense(
|
|
84
|
-
node,
|
|
85
|
-
location: :expression,
|
|
84
|
+
node.loc.expression,
|
|
86
85
|
message: "Custom stream callbacks are not supported in AnyCable"
|
|
87
86
|
)
|
|
88
87
|
end
|
|
89
88
|
|
|
90
89
|
def add_custom_coder_offense(node)
|
|
91
90
|
add_offense(
|
|
92
|
-
node,
|
|
93
|
-
location: :expression,
|
|
91
|
+
node.loc.expression,
|
|
94
92
|
message: "Custom coders are not supported in AnyCable"
|
|
95
93
|
)
|
|
96
94
|
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rubocop"
|
|
4
|
+
require "pathname"
|
|
5
|
+
|
|
6
|
+
require_relative "rubocop/cops/anycable/stream_from"
|
|
7
|
+
require_relative "rubocop/cops/anycable/periodical_timers"
|
|
8
|
+
require_relative "rubocop/cops/anycable/instance_vars"
|
|
9
|
+
|
|
10
|
+
module RuboCop
|
|
11
|
+
module AnyCable # :nodoc:
|
|
12
|
+
CONFIG_DEFAULT = Pathname.new(__dir__).join("rubocop", "config", "default.yml").freeze
|
|
13
|
+
|
|
14
|
+
# Merge anycable config into default configuration
|
|
15
|
+
# See https://github.com/backus/rubocop-rspec/blob/master/lib/rubocop/rspec/inject.rb
|
|
16
|
+
def self.inject!
|
|
17
|
+
path = CONFIG_DEFAULT.to_s
|
|
18
|
+
puts "configuration from #{path}" if ConfigLoader.debug?
|
|
19
|
+
hash = ConfigLoader.send(:load_yaml_configuration, path)
|
|
20
|
+
config = Config.new(hash, path)
|
|
21
|
+
config = ConfigLoader.merge_with_default(config, path)
|
|
22
|
+
ConfigLoader.instance_variable_set(:@default_configuration, config)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
RuboCop::AnyCable.inject!
|
data/lib/anycable/rails.rb
CHANGED
|
@@ -9,6 +9,7 @@ require "globalid"
|
|
|
9
9
|
require "active_support/core_ext/module/attribute_accessors_per_thread"
|
|
10
10
|
|
|
11
11
|
require "anycable/rails/ext"
|
|
12
|
+
require "anycable/rails/channel"
|
|
12
13
|
|
|
13
14
|
module AnyCable
|
|
14
15
|
# Rails handler for AnyCable
|
|
@@ -84,7 +85,7 @@ end
|
|
|
84
85
|
|
|
85
86
|
# Warn if application has been already initialized.
|
|
86
87
|
# AnyCable should be loaded before initialization in order to work correctly.
|
|
87
|
-
if defined?(::Rails) && ::Rails.application
|
|
88
|
+
if defined?(::Rails) && ::Rails.application&.initialized?
|
|
88
89
|
puts("\n**************************************************")
|
|
89
90
|
puts(
|
|
90
91
|
"⛔️ WARNING: AnyCable loaded after application initialization. Might not work correctly.\n" \
|
|
@@ -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
|
|
@@ -37,24 +37,35 @@ module AnyCableRailsGenerators
|
|
|
37
37
|
return latest_release_url(version) if version == "latest"
|
|
38
38
|
|
|
39
39
|
if Gem::Version.new(version).segments.first >= 1
|
|
40
|
-
new_release_url(
|
|
40
|
+
new_release_url(version)
|
|
41
41
|
else
|
|
42
|
-
legacy_release_url(
|
|
42
|
+
legacy_release_url(version)
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def repository_name(version)
|
|
47
|
+
return "anycable/anycable" if version == "latest"
|
|
48
|
+
|
|
49
|
+
major, minor, = Gem::Version.new(version).segments
|
|
50
|
+
if (major >= 1 && minor >= 6) || (major > 1)
|
|
51
|
+
"anycable/anycable"
|
|
52
|
+
else
|
|
53
|
+
"anycable/anycable-go"
|
|
43
54
|
end
|
|
44
55
|
end
|
|
45
56
|
|
|
46
57
|
def legacy_release_url(version)
|
|
47
|
-
"https://github.com/
|
|
58
|
+
"https://github.com/#{repository_name(version)}/releases/download/v#{version}/" \
|
|
48
59
|
"anycable-go-v#{version}-#{os_name}-#{cpu_name}"
|
|
49
60
|
end
|
|
50
61
|
|
|
51
62
|
def new_release_url(version)
|
|
52
|
-
"https://github.com/
|
|
63
|
+
"https://github.com/#{repository_name(version)}/releases/download/v#{version}/" \
|
|
53
64
|
"anycable-go-#{os_name}-#{cpu_name}"
|
|
54
65
|
end
|
|
55
66
|
|
|
56
67
|
def latest_release_url(version)
|
|
57
|
-
"https://github.com/
|
|
68
|
+
"https://github.com/#{repository_name(version)}/releases/latest/download/" \
|
|
58
69
|
"anycable-go-#{os_name}-#{cpu_name}"
|
|
59
70
|
end
|
|
60
71
|
|