anycable 1.0.1 → 1.1.0
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 -0
- data/MIT-LICENSE +1 -1
- data/README.md +1 -4
- metadata +16 -128
- data/bin/anycable +0 -13
- data/bin/anycabled +0 -30
- data/bin/console +0 -7
- data/bin/setup +0 -6
- data/lib/anycable.rb +0 -101
- data/lib/anycable/broadcast_adapters.rb +0 -35
- data/lib/anycable/broadcast_adapters/base.rb +0 -29
- data/lib/anycable/broadcast_adapters/http.rb +0 -130
- data/lib/anycable/broadcast_adapters/redis.rb +0 -43
- data/lib/anycable/cli.rb +0 -353
- data/lib/anycable/config.rb +0 -131
- data/lib/anycable/exceptions_handling.rb +0 -35
- data/lib/anycable/health_server.rb +0 -69
- data/lib/anycable/middleware.rb +0 -27
- data/lib/anycable/middleware_chain.rb +0 -58
- data/lib/anycable/middlewares/check_version.rb +0 -24
- data/lib/anycable/rpc.rb +0 -84
- data/lib/anycable/rpc/rpc_pb.rb +0 -74
- data/lib/anycable/rpc/rpc_services_pb.rb +0 -24
- data/lib/anycable/rpc_handler.rb +0 -183
- data/lib/anycable/rspec.rb +0 -6
- data/lib/anycable/rspec/rpc_command_context.rb +0 -20
- data/lib/anycable/rspec/rpc_stub_context.rb +0 -13
- data/lib/anycable/rspec/with_grpc_server.rb +0 -16
- data/lib/anycable/server.rb +0 -96
- data/lib/anycable/socket.rb +0 -90
- data/lib/anycable/version.rb +0 -5
@@ -1,35 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "anycable/broadcast_adapters/base"
|
4
|
-
|
5
|
-
module AnyCable
|
6
|
-
module BroadcastAdapters # :nodoc:
|
7
|
-
module_function
|
8
|
-
|
9
|
-
# rubocop: disable Metrics/AbcSize, Metrics/MethodLength
|
10
|
-
def lookup_adapter(args)
|
11
|
-
adapter, options = Array(args)
|
12
|
-
path_to_adapter = "anycable/broadcast_adapters/#{adapter}"
|
13
|
-
adapter_class_name = adapter.to_s.split("_").map(&:capitalize).join
|
14
|
-
|
15
|
-
unless BroadcastAdapters.const_defined?(adapter_class_name, false)
|
16
|
-
begin
|
17
|
-
require path_to_adapter
|
18
|
-
rescue LoadError => e
|
19
|
-
# We couldn't require the adapter itself.
|
20
|
-
if e.path == path_to_adapter
|
21
|
-
raise e.class, "Couldn't load the '#{adapter}' broadcast adapter for AnyCable",
|
22
|
-
e.backtrace
|
23
|
-
# Bubbled up from the adapter require.
|
24
|
-
else
|
25
|
-
raise e.class, "Error loading the '#{adapter}' broadcast adapter for AnyCable",
|
26
|
-
e.backtrace
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
BroadcastAdapters.const_get(adapter_class_name, false).new(**(options || {}))
|
32
|
-
end
|
33
|
-
# rubocop: enable Metrics/AbcSize, Metrics/MethodLength
|
34
|
-
end
|
35
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module AnyCable
|
4
|
-
module BroadcastAdapters
|
5
|
-
class Base
|
6
|
-
def raw_broadcast(_data)
|
7
|
-
raise NotImplementedError
|
8
|
-
end
|
9
|
-
|
10
|
-
def broadcast(stream, payload)
|
11
|
-
raw_broadcast({stream: stream, data: payload}.to_json)
|
12
|
-
end
|
13
|
-
|
14
|
-
def broadcast_command(command, **payload)
|
15
|
-
raw_broadcast({command: command, payload: payload}.to_json)
|
16
|
-
end
|
17
|
-
|
18
|
-
def announce!
|
19
|
-
logger.info "Broadcasting via #{self.class.name}"
|
20
|
-
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
def logger
|
25
|
-
AnyCable.logger
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
@@ -1,130 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "json"
|
4
|
-
require "uri"
|
5
|
-
require "net/http"
|
6
|
-
|
7
|
-
module AnyCable
|
8
|
-
module BroadcastAdapters
|
9
|
-
# HTTP adapter for broadcasting.
|
10
|
-
#
|
11
|
-
# Example:
|
12
|
-
#
|
13
|
-
# AnyCable.broadast_adapter = :http
|
14
|
-
#
|
15
|
-
# It uses configuration from global AnyCable config
|
16
|
-
# by default.
|
17
|
-
#
|
18
|
-
# You can override these params:
|
19
|
-
#
|
20
|
-
# AnyCable.broadcast_adapter = :http, url: "http://ws.example.com/_any_cable_"
|
21
|
-
class Http < Base
|
22
|
-
# Taken from: https://github.com/influxdata/influxdb-ruby/blob/886058079c66d4fd019ad74ca11342fddb0b753d/lib/influxdb/errors.rb#L18
|
23
|
-
RECOVERABLE_EXCEPTIONS = [
|
24
|
-
Errno::ECONNABORTED,
|
25
|
-
Errno::ECONNREFUSED,
|
26
|
-
Errno::ECONNRESET,
|
27
|
-
Errno::EHOSTUNREACH,
|
28
|
-
Errno::EINVAL,
|
29
|
-
Errno::ENETUNREACH,
|
30
|
-
Net::HTTPBadResponse,
|
31
|
-
Net::HTTPHeaderSyntaxError,
|
32
|
-
Net::ProtocolError,
|
33
|
-
SocketError,
|
34
|
-
(OpenSSL::SSL::SSLError if defined?(OpenSSL))
|
35
|
-
].compact.freeze
|
36
|
-
|
37
|
-
OPEN_TIMEOUT = 5
|
38
|
-
READ_TIMEOUT = 10
|
39
|
-
|
40
|
-
MAX_ATTEMPTS = 3
|
41
|
-
DELAY = 2
|
42
|
-
|
43
|
-
attr_reader :url, :headers, :authorized
|
44
|
-
alias authorized? authorized
|
45
|
-
|
46
|
-
def initialize(url: AnyCable.config.http_broadcast_url, secret: AnyCable.config.http_broadcast_secret)
|
47
|
-
@url = url
|
48
|
-
@headers = {}
|
49
|
-
if secret
|
50
|
-
headers["Authorization"] = "Bearer #{secret}"
|
51
|
-
@authorized = true
|
52
|
-
end
|
53
|
-
|
54
|
-
@uri = URI.parse(url)
|
55
|
-
@queue = Queue.new
|
56
|
-
end
|
57
|
-
|
58
|
-
def raw_broadcast(payload)
|
59
|
-
ensure_thread_is_alive
|
60
|
-
queue << payload
|
61
|
-
end
|
62
|
-
|
63
|
-
# Wait for background thread to process all the messages
|
64
|
-
# and stop it
|
65
|
-
def shutdown
|
66
|
-
queue << :stop
|
67
|
-
thread.join if thread&.alive?
|
68
|
-
rescue Exception => e # rubocop:disable Lint/RescueException
|
69
|
-
logger.error "Broadcasting thread exited with exception: #{e.message}"
|
70
|
-
end
|
71
|
-
|
72
|
-
def announce!
|
73
|
-
logger.info "Broadcasting HTTP url: #{url}#{authorized? ? " (with authorization)" : ""}"
|
74
|
-
end
|
75
|
-
|
76
|
-
private
|
77
|
-
|
78
|
-
attr_reader :uri, :queue, :thread
|
79
|
-
|
80
|
-
def ensure_thread_is_alive
|
81
|
-
return if thread&.alive?
|
82
|
-
|
83
|
-
@thread = Thread.new do
|
84
|
-
loop do
|
85
|
-
msg = queue.pop
|
86
|
-
break if msg == :stop
|
87
|
-
|
88
|
-
handle_response perform_request(msg)
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
def perform_request(payload)
|
94
|
-
build_http do |http|
|
95
|
-
req = Net::HTTP::Post.new(url, {"Content-Type" => "application/json"}.merge(headers))
|
96
|
-
req.body = payload
|
97
|
-
http.request(req)
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
def handle_response(response)
|
102
|
-
return unless response
|
103
|
-
return if Net::HTTPCreated === response
|
104
|
-
|
105
|
-
logger.error "Broadcast request responded with unexpected status: #{response.code}"
|
106
|
-
end
|
107
|
-
|
108
|
-
def build_http
|
109
|
-
retry_count = 0
|
110
|
-
|
111
|
-
begin
|
112
|
-
http = Net::HTTP.new(uri.host, uri.port)
|
113
|
-
http.open_timeout = OPEN_TIMEOUT
|
114
|
-
http.read_timeout = READ_TIMEOUT
|
115
|
-
http.use_ssl = url.match?(/^https/)
|
116
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
117
|
-
yield http
|
118
|
-
rescue Timeout::Error, *RECOVERABLE_EXCEPTIONS => e
|
119
|
-
retry_count += 1
|
120
|
-
return logger.error("Broadcast request failed: #{e.message}") if MAX_ATTEMPTS < retry_count
|
121
|
-
|
122
|
-
sleep((DELAY**retry_count) * retry_count)
|
123
|
-
retry
|
124
|
-
ensure
|
125
|
-
http.finish if http.started?
|
126
|
-
end
|
127
|
-
end
|
128
|
-
end
|
129
|
-
end
|
130
|
-
end
|
@@ -1,43 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
gem "redis", ">= 3"
|
4
|
-
|
5
|
-
require "redis"
|
6
|
-
require "json"
|
7
|
-
|
8
|
-
module AnyCable
|
9
|
-
module BroadcastAdapters
|
10
|
-
# Redis adapter for broadcasting.
|
11
|
-
#
|
12
|
-
# Example:
|
13
|
-
#
|
14
|
-
# AnyCable.broadast_adapter = :redis
|
15
|
-
#
|
16
|
-
# It uses Redis configuration from global AnyCable config
|
17
|
-
# by default.
|
18
|
-
#
|
19
|
-
# You can override these params:
|
20
|
-
#
|
21
|
-
# AnyCable.broadcast_adapter = :redis, url: "redis://my_redis", channel: "_any_cable_"
|
22
|
-
class Redis < Base
|
23
|
-
attr_reader :redis_conn, :channel
|
24
|
-
|
25
|
-
def initialize(
|
26
|
-
channel: AnyCable.config.redis_channel,
|
27
|
-
**options
|
28
|
-
)
|
29
|
-
options = AnyCable.config.to_redis_params.merge(options)
|
30
|
-
@redis_conn = ::Redis.new(options)
|
31
|
-
@channel = channel
|
32
|
-
end
|
33
|
-
|
34
|
-
def raw_broadcast(payload)
|
35
|
-
redis_conn.publish(channel, payload)
|
36
|
-
end
|
37
|
-
|
38
|
-
def announce!
|
39
|
-
logger.info "Broadcasting Redis channel: #{channel}"
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
data/lib/anycable/cli.rb
DELETED
@@ -1,353 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "optparse"
|
4
|
-
|
5
|
-
require "anycable"
|
6
|
-
|
7
|
-
$stdout.sync = true
|
8
|
-
|
9
|
-
module AnyCable
|
10
|
-
# Command-line interface for running AnyCable gRPC server
|
11
|
-
# rubocop:disable Metrics/ClassLength
|
12
|
-
class CLI
|
13
|
-
# (not-so-big) List of common boot files for
|
14
|
-
# different applications
|
15
|
-
APP_CANDIDATES = %w[
|
16
|
-
./config/anycable.rb
|
17
|
-
./config/environment.rb
|
18
|
-
].freeze
|
19
|
-
|
20
|
-
# Wait for external process termination (s)
|
21
|
-
WAIT_PROCESS = 2
|
22
|
-
|
23
|
-
attr_reader :server, :health_server, :embedded
|
24
|
-
alias embedded? embedded
|
25
|
-
|
26
|
-
def initialize(embedded: false)
|
27
|
-
@embedded = embedded
|
28
|
-
end
|
29
|
-
|
30
|
-
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
31
|
-
def run(args = [])
|
32
|
-
@at_stop = []
|
33
|
-
|
34
|
-
extra_options = parse_cli_options!(args)
|
35
|
-
|
36
|
-
# Boot app first, 'cause it might change
|
37
|
-
# configuration, loggin settings, etc.
|
38
|
-
boot_app! unless embedded?
|
39
|
-
|
40
|
-
parse_gem_options!(extra_options)
|
41
|
-
|
42
|
-
configure_server!
|
43
|
-
|
44
|
-
logger.info "Starting AnyCable gRPC server (pid: #{Process.pid}, workers_num: #{config.rpc_pool_size})"
|
45
|
-
|
46
|
-
print_versions!
|
47
|
-
|
48
|
-
logger.info "Serving #{defined?(::Rails) ? "Rails " : ""}application from #{boot_file}" unless embedded?
|
49
|
-
|
50
|
-
verify_connection_factory!
|
51
|
-
|
52
|
-
log_grpc! if config.log_grpc
|
53
|
-
|
54
|
-
log_errors!
|
55
|
-
|
56
|
-
use_version_check! if config.version_check_enabled?
|
57
|
-
|
58
|
-
@server = AnyCable::Server.new(
|
59
|
-
host: config.rpc_host,
|
60
|
-
**config.to_grpc_params,
|
61
|
-
interceptors: AnyCable.middleware.to_a
|
62
|
-
)
|
63
|
-
|
64
|
-
# Make sure middlewares are not adding after server has started
|
65
|
-
AnyCable.middleware.freeze
|
66
|
-
|
67
|
-
start_health_server! if config.http_health_port_provided?
|
68
|
-
start_pubsub!
|
69
|
-
|
70
|
-
server.start
|
71
|
-
|
72
|
-
run_custom_server_command! unless server_command.nil?
|
73
|
-
|
74
|
-
return if embedded?
|
75
|
-
|
76
|
-
begin
|
77
|
-
wait_till_terminated
|
78
|
-
rescue Interrupt => e
|
79
|
-
logger.info "Stopping... #{e.message}"
|
80
|
-
|
81
|
-
shutdown
|
82
|
-
|
83
|
-
logger.info "Stopped. Good-bye!"
|
84
|
-
exit(0)
|
85
|
-
end
|
86
|
-
end
|
87
|
-
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
88
|
-
|
89
|
-
def shutdown
|
90
|
-
at_stop.each(&:call)
|
91
|
-
server&.stop
|
92
|
-
end
|
93
|
-
|
94
|
-
private
|
95
|
-
|
96
|
-
attr_reader :boot_file, :server_command
|
97
|
-
|
98
|
-
def config
|
99
|
-
AnyCable.config
|
100
|
-
end
|
101
|
-
|
102
|
-
def logger
|
103
|
-
AnyCable.logger
|
104
|
-
end
|
105
|
-
|
106
|
-
def at_stop
|
107
|
-
if block_given?
|
108
|
-
@at_stop << Proc.new
|
109
|
-
else
|
110
|
-
@at_stop
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
def wait_till_terminated
|
115
|
-
self_read = setup_signals
|
116
|
-
|
117
|
-
while readable_io = IO.select([self_read]) # rubocop:disable Lint/AssignmentInCondition
|
118
|
-
signal = readable_io.first[0].gets.strip
|
119
|
-
raise Interrupt, "SIG#{signal} received"
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
def setup_signals
|
124
|
-
self_read, self_write = IO.pipe
|
125
|
-
|
126
|
-
%w[INT TERM].each do |signal|
|
127
|
-
trap signal do
|
128
|
-
self_write.puts signal
|
129
|
-
end
|
130
|
-
end
|
131
|
-
|
132
|
-
self_read
|
133
|
-
end
|
134
|
-
|
135
|
-
def print_versions!
|
136
|
-
logger.info "AnyCable version: #{AnyCable::VERSION} (proto_version: #{AnyCable::PROTO_VERSION})"
|
137
|
-
logger.info "gRPC version: #{GRPC::VERSION}"
|
138
|
-
end
|
139
|
-
|
140
|
-
# rubocop:disable Metrics/MethodLength
|
141
|
-
def boot_app!
|
142
|
-
@boot_file ||= try_detect_app
|
143
|
-
|
144
|
-
if boot_file.nil?
|
145
|
-
$stdout.puts(
|
146
|
-
"Couldn't find an application to load. " \
|
147
|
-
"Please specify the explicit path via -r option, e.g:" \
|
148
|
-
" anycable -r ./config/boot.rb or anycable -r /app/config/load_me.rb"
|
149
|
-
)
|
150
|
-
exit(1)
|
151
|
-
end
|
152
|
-
|
153
|
-
begin
|
154
|
-
require boot_file
|
155
|
-
rescue LoadError => e
|
156
|
-
$stdout.puts(
|
157
|
-
"Failed to load application: #{e.message}. " \
|
158
|
-
"Please specify the explicit path via -r option, e.g:" \
|
159
|
-
" anycable -r ./config/boot.rb or anycable -r /app/config/load_me.rb"
|
160
|
-
)
|
161
|
-
exit(1)
|
162
|
-
end
|
163
|
-
end
|
164
|
-
# rubocop:enable Metrics/MethodLength
|
165
|
-
|
166
|
-
def try_detect_app
|
167
|
-
APP_CANDIDATES.detect { |path| File.exist?(path) }
|
168
|
-
end
|
169
|
-
|
170
|
-
def configure_server!
|
171
|
-
AnyCable.server_callbacks.each(&:call)
|
172
|
-
end
|
173
|
-
|
174
|
-
def use_version_check!
|
175
|
-
require "anycable/middlewares/check_version"
|
176
|
-
|
177
|
-
AnyCable.middleware.use(
|
178
|
-
AnyCable::Middlewares::CheckVersion.new(AnyCable::PROTO_VERSION)
|
179
|
-
)
|
180
|
-
end
|
181
|
-
|
182
|
-
def start_health_server!
|
183
|
-
@health_server = AnyCable::HealthServer.new(
|
184
|
-
server,
|
185
|
-
**config.to_http_health_params
|
186
|
-
)
|
187
|
-
health_server.start
|
188
|
-
|
189
|
-
at_stop { health_server.stop }
|
190
|
-
end
|
191
|
-
|
192
|
-
def start_pubsub!
|
193
|
-
AnyCable.broadcast_adapter.announce!
|
194
|
-
end
|
195
|
-
|
196
|
-
# rubocop: disable Metrics/MethodLength, Metrics/AbcSize
|
197
|
-
def run_custom_server_command!
|
198
|
-
pid = nil
|
199
|
-
stopped = false
|
200
|
-
command_thread = Thread.new do
|
201
|
-
pid = Process.spawn(server_command)
|
202
|
-
logger.info "Started command: #{server_command} (pid: #{pid})"
|
203
|
-
|
204
|
-
Process.wait pid
|
205
|
-
pid = nil
|
206
|
-
raise Interrupt, "Server command exit unexpectedly" unless stopped
|
207
|
-
end
|
208
|
-
|
209
|
-
command_thread.abort_on_exception = true
|
210
|
-
|
211
|
-
at_stop do
|
212
|
-
stopped = true
|
213
|
-
next if pid.nil?
|
214
|
-
|
215
|
-
Process.kill("SIGTERM", pid)
|
216
|
-
|
217
|
-
logger.info "Wait till process #{pid} stop..."
|
218
|
-
|
219
|
-
tick = 0
|
220
|
-
|
221
|
-
loop do
|
222
|
-
tick += 0.2
|
223
|
-
break if tick > WAIT_PROCESS
|
224
|
-
|
225
|
-
if pid.nil?
|
226
|
-
logger.info "Process #{pid} stopped."
|
227
|
-
break
|
228
|
-
end
|
229
|
-
end
|
230
|
-
end
|
231
|
-
end
|
232
|
-
# rubocop: enable Metrics/MethodLength, Metrics/AbcSize
|
233
|
-
|
234
|
-
def log_grpc!
|
235
|
-
::GRPC.define_singleton_method(:logger) { AnyCable.logger }
|
236
|
-
end
|
237
|
-
|
238
|
-
# Add default exceptions handler: print error message to log
|
239
|
-
def log_errors!
|
240
|
-
if AnyCable.config.debug?
|
241
|
-
# Print error with backtrace in debug mode
|
242
|
-
AnyCable.capture_exception do |e|
|
243
|
-
AnyCable.logger.error("#{e.message}:\n#{e.backtrace.take(20).join("\n")}")
|
244
|
-
end
|
245
|
-
else
|
246
|
-
AnyCable.capture_exception { |e| AnyCable.logger.error(e.message) }
|
247
|
-
end
|
248
|
-
end
|
249
|
-
|
250
|
-
def verify_connection_factory!
|
251
|
-
return if AnyCable.connection_factory
|
252
|
-
|
253
|
-
logger.error "AnyCable connection factory must be configured. " \
|
254
|
-
"Make sure you've required a gem (e.g. `anycable-rails`) or " \
|
255
|
-
"configured `AnyCable.connection_factory` yourself"
|
256
|
-
exit(1)
|
257
|
-
end
|
258
|
-
|
259
|
-
def parse_gem_options!(args)
|
260
|
-
config.parse_options!(args)
|
261
|
-
rescue OptionParser::InvalidOption => e
|
262
|
-
$stdout.puts e.message
|
263
|
-
$stdout.puts "Run anycable -h to see available options"
|
264
|
-
exit(1)
|
265
|
-
end
|
266
|
-
|
267
|
-
# rubocop:disable Metrics/MethodLength
|
268
|
-
def parse_cli_options!(args)
|
269
|
-
unknown_opts = []
|
270
|
-
|
271
|
-
parser = build_cli_parser
|
272
|
-
|
273
|
-
begin
|
274
|
-
parser.parse!(args)
|
275
|
-
rescue OptionParser::InvalidOption => e
|
276
|
-
unknown_opts << e.args[0]
|
277
|
-
unless args.size.zero?
|
278
|
-
unknown_opts << args.shift unless args.first.start_with?("-")
|
279
|
-
retry
|
280
|
-
end
|
281
|
-
end
|
282
|
-
|
283
|
-
unknown_opts
|
284
|
-
end
|
285
|
-
|
286
|
-
def build_cli_parser
|
287
|
-
OptionParser.new do |o|
|
288
|
-
o.on "-v", "--version", "Print version and exit" do |_arg|
|
289
|
-
$stdout.puts "AnyCable v#{AnyCable::VERSION}"
|
290
|
-
exit(0)
|
291
|
-
end
|
292
|
-
|
293
|
-
o.on "-r", "--require [PATH|DIR]", "Location of application file to require" do |arg|
|
294
|
-
@boot_file = arg
|
295
|
-
end
|
296
|
-
|
297
|
-
o.on "--server-command VALUE", "Command to run WebSocket server" do |arg|
|
298
|
-
@server_command = arg
|
299
|
-
end
|
300
|
-
|
301
|
-
o.on_tail "-h", "--help", "Show help" do
|
302
|
-
$stdout.puts usage
|
303
|
-
exit(0)
|
304
|
-
end
|
305
|
-
end
|
306
|
-
end
|
307
|
-
# rubocop:enable Metrics/MethodLength
|
308
|
-
|
309
|
-
def usage
|
310
|
-
<<~HELP
|
311
|
-
anycable: run AnyCable gRPC server (https://anycable.io)
|
312
|
-
|
313
|
-
VERSION
|
314
|
-
anycable/#{AnyCable::VERSION}
|
315
|
-
|
316
|
-
USAGE
|
317
|
-
$ anycable [options]
|
318
|
-
|
319
|
-
BASIC OPTIONS
|
320
|
-
-r, --require=path Location of application file to require, default: "config/environment.rb"
|
321
|
-
--server-command=command Command to run WebSocket server
|
322
|
-
--rpc-host=host Local address to run gRPC server on, default: "[::]:50051"
|
323
|
-
--broadcast-adapter=type Pub/sub adapter type for broadcasts, default: redis
|
324
|
-
--log-level=level Logging level, default: "info"
|
325
|
-
--log-file=path Path to log file, default: <none> (log to STDOUT)
|
326
|
-
--log-grpc Enable gRPC logging (disabled by default)
|
327
|
-
--debug Turn on verbose logging ("debug" level and gRPC logging on)
|
328
|
-
-v, --version Print version and exit
|
329
|
-
-h, --help Show this help
|
330
|
-
|
331
|
-
REDIS PUB/SUB OPTIONS
|
332
|
-
--redis-url=url Redis URL for pub/sub, default: REDIS_URL or "redis://localhost:6379/5"
|
333
|
-
--redis-channel=name Redis channel for broadcasting, default: "__anycable__"
|
334
|
-
--redis-sentinels=<...hosts> Redis Sentinel followers addresses (as a comma-separated list), default: nil
|
335
|
-
|
336
|
-
HTTP PUB/SUB OPTIONS
|
337
|
-
--http-broadcast-url HTTP pub/sub endpoint URL, default: "http://localhost:8090/_broadcast"
|
338
|
-
--http-broadcast-secret HTTP pub/sub authorization secret, default: <none> (disabled)
|
339
|
-
|
340
|
-
HTTP HEALTH CHECKER OPTIONS
|
341
|
-
--http-health-port=port Port to run HTTP health server on, default: <none> (disabled)
|
342
|
-
--http-health-path=path Endpoint to server health cheks, default: "/health"
|
343
|
-
|
344
|
-
GRPC OPTIONS
|
345
|
-
--rpc-pool-size=size gRPC workers pool size, default: 30
|
346
|
-
--rpc-max-waiting-requests=num Max waiting requests queue size, default: 20
|
347
|
-
--rpc-poll-period=seconds Poll period (sec), default: 1
|
348
|
-
--rpc-pool-keep-alive=seconds Keep-alive polling interval (sec), default: 1
|
349
|
-
HELP
|
350
|
-
end
|
351
|
-
end
|
352
|
-
# rubocop:enable Metrics/ClassLength
|
353
|
-
end
|