anycable 0.6.0.rc1 → 1.0.0.preview1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +97 -5
- data/MIT-LICENSE +1 -1
- data/README.md +13 -6
- data/bin/anycable +1 -1
- data/bin/anycabled +30 -0
- data/lib/anycable.rb +16 -11
- data/lib/anycable/broadcast_adapters.rb +3 -3
- data/lib/anycable/broadcast_adapters/redis.rb +2 -2
- data/lib/anycable/cli.rb +20 -4
- data/lib/anycable/config.rb +10 -5
- data/lib/anycable/exceptions_handling.rb +13 -9
- data/lib/anycable/health_server.rb +2 -3
- data/lib/anycable/middleware.rb +3 -0
- data/lib/anycable/middleware_chain.rb +2 -2
- data/lib/anycable/middlewares/check_version.rb +24 -0
- data/lib/anycable/rpc.rb +76 -0
- data/lib/anycable/rpc/rpc_pb.rb +54 -39
- data/lib/anycable/rpc/rpc_services_pb.rb +4 -3
- data/lib/anycable/rpc_handler.rb +77 -24
- data/lib/anycable/rspec.rb +6 -0
- data/lib/anycable/rspec/rpc_command_context.rb +20 -0
- data/lib/anycable/rspec/rpc_stub_context.rb +13 -0
- data/lib/anycable/rspec/with_grpc_server.rb +15 -0
- data/lib/anycable/server.rb +4 -46
- data/lib/anycable/socket.rb +39 -2
- data/lib/anycable/version.rb +1 -1
- metadata +32 -70
- data/.github/ISSUE_TEMPLATE.md +0 -25
- data/.github/PULL_REQUEST_TEMPLATE.md +0 -31
- data/.gitignore +0 -40
- data/.hound.yml +0 -3
- data/.rubocop.yml +0 -71
- data/.travis.yml +0 -12
- data/Gemfile +0 -8
- data/Makefile +0 -5
- data/PITCHME.md +0 -139
- data/PITCHME.yaml +0 -1
- data/Rakefile +0 -8
- data/anycable.gemspec +0 -35
- data/assets/Memory3.png +0 -0
- data/assets/Memory5.png +0 -0
- data/assets/RTT3.png +0 -0
- data/assets/RTT5.png +0 -0
- data/assets/Scheme1.png +0 -0
- data/assets/Scheme2.png +0 -0
- data/assets/cpu_chart.gif +0 -0
- data/assets/cpu_chart2.gif +0 -0
- data/assets/evlms.png +0 -0
- data/benchmarks/.gitignore +0 -2
- data/benchmarks/2017-02-12.md +0 -308
- data/benchmarks/2018-03-04.md +0 -192
- data/benchmarks/2018-05-27-rpc-bench.md +0 -57
- data/benchmarks/2018-10-27.md +0 -181
- data/benchmarks/HowTo.md +0 -23
- data/benchmarks/ansible.cfg +0 -9
- data/benchmarks/assets/2018-10-27-action-cable-rss.png +0 -0
- data/benchmarks/assets/2018-10-27-action-cable-rtt.png +0 -0
- data/benchmarks/assets/2018-10-27-anycable-rss.png +0 -0
- data/benchmarks/assets/2018-10-27-anycable-rtt.png +0 -0
- data/benchmarks/assets/2018-10-27-async-rss.png +0 -0
- data/benchmarks/assets/2018-10-27-async-rtt.png +0 -0
- data/benchmarks/assets/2018-10-27-falcon-cable-rss.png +0 -0
- data/benchmarks/assets/2018-10-27-falcon-cable-rtt.png +0 -0
- data/benchmarks/assets/2018-10-27-iodine-cable-rss.png +0 -0
- data/benchmarks/assets/2018-10-27-iodine-cable-rtt.png +0 -0
- data/benchmarks/assets/2018-10-27-plezi-rss.png +0 -0
- data/benchmarks/assets/2018-10-27-plezi-rtt.png +0 -0
- data/benchmarks/bench.png +0 -0
- data/benchmarks/benchmark.yml +0 -69
- data/benchmarks/hosts +0 -5
- data/benchmarks/rtt_plot.py +0 -74
- data/benchmarks/rtt_plot_test.py +0 -16
- data/benchmarks/servers.yml +0 -58
- data/circle.yml +0 -8
- data/etc/bug_report_template.rb +0 -76
- data/lib/anycable/handler/capture_exceptions.rb +0 -39
- data/protos/rpc.proto +0 -55
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.shared_context "anycable:rpc:command" do
|
4
|
+
include_context "anycable:rpc:stub"
|
5
|
+
|
6
|
+
let(:command) { "" }
|
7
|
+
let(:channel_id) { "" }
|
8
|
+
let(:identifiers) { {} }
|
9
|
+
let(:data) { {} }
|
10
|
+
|
11
|
+
let(:request) do
|
12
|
+
AnyCable::CommandMessage.new(
|
13
|
+
command: command,
|
14
|
+
identifier: channel_id,
|
15
|
+
connection_identifiers: identifiers.to_json,
|
16
|
+
data: data.to_json,
|
17
|
+
env: env
|
18
|
+
)
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.shared_context "anycable:rpc:stub" do
|
4
|
+
before(:all) do
|
5
|
+
@service = AnyCable::RPC::Stub.new(AnyCable.config.rpc_host, :this_channel_is_insecure)
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:service) { @service }
|
9
|
+
|
10
|
+
let(:url) { "example.com/cable" }
|
11
|
+
let(:headers) { {} }
|
12
|
+
let(:env) { AnyCable::Env.new(url: url, headers: headers) }
|
13
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.shared_context "anycable:rpc:server" do
|
4
|
+
before(:all) do
|
5
|
+
@server = AnyCable::Server.new(
|
6
|
+
host: AnyCable.config.rpc_host,
|
7
|
+
**AnyCable.config.to_grpc_params,
|
8
|
+
interceptors: AnyCable.middleware.to_a
|
9
|
+
)
|
10
|
+
|
11
|
+
@server.start
|
12
|
+
end
|
13
|
+
|
14
|
+
after(:all) { @server.stop }
|
15
|
+
end
|
data/lib/anycable/server.rb
CHANGED
@@ -12,8 +12,8 @@ module AnyCable
|
|
12
12
|
#
|
13
13
|
# Basic example:
|
14
14
|
#
|
15
|
-
# # create new server listening on
|
16
|
-
# server = AnyCable::Server.new(host: "
|
15
|
+
# # create new server listening on the loopback interface with 50051 port
|
16
|
+
# server = AnyCable::Server.new(host: "127.0.0.1:50051")
|
17
17
|
#
|
18
18
|
# # run gRPC server in bakground
|
19
19
|
# server.start
|
@@ -21,51 +21,9 @@ module AnyCable
|
|
21
21
|
# # stop server
|
22
22
|
# server.stop
|
23
23
|
class Server
|
24
|
-
class << self
|
25
|
-
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
26
|
-
def start(**options)
|
27
|
-
warn <<~DEPRECATION
|
28
|
-
Using AnyCable::Server.start is deprecated!
|
29
|
-
Please, use anycable CLI instead.
|
30
|
-
|
31
|
-
See https://docs.anycable.io/#upgrade_to_0_6_0
|
32
|
-
DEPRECATION
|
33
|
-
|
34
|
-
server = new(
|
35
|
-
host: AnyCable.config.rpc_host,
|
36
|
-
**AnyCable.config.to_grpc_params,
|
37
|
-
interceptors: AnyCable.middleware.to_a,
|
38
|
-
**options
|
39
|
-
)
|
40
|
-
|
41
|
-
AnyCable.middleware.freeze
|
42
|
-
|
43
|
-
if AnyCable.config.http_health_port_provided?
|
44
|
-
health_server = AnyCable::HealthServer.new(
|
45
|
-
server,
|
46
|
-
**AnyCable.config.to_http_health_params
|
47
|
-
)
|
48
|
-
health_server.start
|
49
|
-
end
|
50
|
-
|
51
|
-
at_exit do
|
52
|
-
server.stop
|
53
|
-
health_server&.stop
|
54
|
-
end
|
55
|
-
|
56
|
-
AnyCable.logger.info "Broadcasting Redis channel: #{AnyCable.config.redis_channel}"
|
57
|
-
|
58
|
-
server.start
|
59
|
-
server.wait_till_terminated
|
60
|
-
end
|
61
|
-
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength
|
62
|
-
end
|
63
|
-
|
64
|
-
DEFAULT_HOST = "0.0.0.0:50051"
|
65
|
-
|
66
24
|
attr_reader :grpc_server, :host
|
67
25
|
|
68
|
-
def initialize(host
|
26
|
+
def initialize(host:, logger: AnyCable.logger, **options)
|
69
27
|
@logger = logger
|
70
28
|
@host = host
|
71
29
|
@grpc_server = build_server(options)
|
@@ -115,7 +73,7 @@ module AnyCable
|
|
115
73
|
attr_reader :logger, :start_thread
|
116
74
|
|
117
75
|
def build_server(options)
|
118
|
-
GRPC::RpcServer.new(options).tap do |server|
|
76
|
+
GRPC::RpcServer.new(**options).tap do |server|
|
119
77
|
server.add_http2_port(host, :this_port_is_insecure)
|
120
78
|
server.handle(AnyCable::RPCHandler)
|
121
79
|
server.handle(build_health_checker)
|
data/lib/anycable/socket.rb
CHANGED
@@ -3,11 +3,41 @@
|
|
3
3
|
module AnyCable
|
4
4
|
# Socket mock to be used with application connection
|
5
5
|
class Socket
|
6
|
-
|
6
|
+
# Represents the per-connection store
|
7
|
+
# (for example, used to keep session beetween RPC calls)
|
8
|
+
class State
|
9
|
+
attr_reader :dirty_keys, :source
|
10
|
+
|
11
|
+
def initialize(from)
|
12
|
+
@source = from
|
13
|
+
@dirty_keys = nil
|
14
|
+
end
|
15
|
+
|
16
|
+
def read(key)
|
17
|
+
source&.[](key)
|
18
|
+
end
|
19
|
+
|
20
|
+
def write(key, val)
|
21
|
+
return if source&.[](key) == val
|
22
|
+
|
23
|
+
@source ||= {}
|
24
|
+
@dirty_keys ||= []
|
25
|
+
dirty_keys << key
|
26
|
+
source[key] = val
|
27
|
+
end
|
28
|
+
|
29
|
+
def changed_fields
|
30
|
+
return unless source && dirty_keys
|
31
|
+
source.slice(*dirty_keys)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
attr_reader :transmissions, :env, :cstate
|
7
36
|
|
8
37
|
def initialize(env: nil)
|
9
38
|
@transmissions = []
|
10
39
|
@env = env
|
40
|
+
@cstate = env["anycable.cstate"] = State.new(env["anycable.raw_cstate"])
|
11
41
|
end
|
12
42
|
|
13
43
|
def transmit(websocket_message)
|
@@ -32,7 +62,6 @@ module AnyCable
|
|
32
62
|
|
33
63
|
def close
|
34
64
|
@closed = true
|
35
|
-
@transmissions.clear
|
36
65
|
@streams&.clear
|
37
66
|
@stop_all_streams = true
|
38
67
|
end
|
@@ -44,5 +73,13 @@ module AnyCable
|
|
44
73
|
def stop_streams?
|
45
74
|
@stop_all_streams == true
|
46
75
|
end
|
76
|
+
|
77
|
+
def session
|
78
|
+
cstate.read(SESSION_KEY)
|
79
|
+
end
|
80
|
+
|
81
|
+
def session=(val)
|
82
|
+
cstate.write(SESSION_KEY, val)
|
83
|
+
end
|
47
84
|
end
|
48
85
|
end
|
data/lib/anycable/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: anycable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0.preview1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- palkan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-02-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: anyway_config
|
@@ -16,28 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 1.4.
|
19
|
+
version: 1.4.2
|
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: 1.4.
|
26
|
+
version: 1.4.2
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: grpc
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '1.
|
33
|
+
version: '1.17'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '1.
|
40
|
+
version: '1.17'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: redis
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -56,14 +56,14 @@ dependencies:
|
|
56
56
|
name: bundler
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - "
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '1'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - "
|
66
|
+
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '1'
|
69
69
|
- !ruby/object:Gem::Dependency
|
@@ -109,19 +109,19 @@ dependencies:
|
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '3.5'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
|
-
name: rubocop
|
112
|
+
name: rubocop-md
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
115
|
- - "~>"
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: 0.
|
117
|
+
version: '0.3'
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
122
|
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version: 0.
|
124
|
+
version: '0.3'
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
126
|
name: simplecov
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -137,102 +137,65 @@ dependencies:
|
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: 0.3.8
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
|
-
name:
|
140
|
+
name: standard
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
142
142
|
requirements:
|
143
|
-
- - "
|
143
|
+
- - "~>"
|
144
144
|
- !ruby/object:Gem::Version
|
145
|
-
version:
|
145
|
+
version: 0.1.7
|
146
146
|
type: :development
|
147
147
|
prerelease: false
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
149
149
|
requirements:
|
150
|
-
- - "
|
150
|
+
- - "~>"
|
151
151
|
- !ruby/object:Gem::Version
|
152
|
-
version:
|
152
|
+
version: 0.1.7
|
153
153
|
description: AnyCable is a polyglot replacement for ActionCable-compatible servers
|
154
154
|
email:
|
155
155
|
- dementiev.vm@gmail.com
|
156
156
|
executables:
|
157
157
|
- anycable
|
158
|
+
- anycabled
|
158
159
|
extensions: []
|
159
160
|
extra_rdoc_files: []
|
160
161
|
files:
|
161
|
-
- ".github/ISSUE_TEMPLATE.md"
|
162
|
-
- ".github/PULL_REQUEST_TEMPLATE.md"
|
163
|
-
- ".gitignore"
|
164
|
-
- ".hound.yml"
|
165
|
-
- ".rubocop.yml"
|
166
|
-
- ".travis.yml"
|
167
162
|
- CHANGELOG.md
|
168
|
-
- Gemfile
|
169
163
|
- MIT-LICENSE
|
170
|
-
- Makefile
|
171
|
-
- PITCHME.md
|
172
|
-
- PITCHME.yaml
|
173
164
|
- README.md
|
174
|
-
- Rakefile
|
175
|
-
- anycable.gemspec
|
176
|
-
- assets/Memory3.png
|
177
|
-
- assets/Memory5.png
|
178
|
-
- assets/RTT3.png
|
179
|
-
- assets/RTT5.png
|
180
|
-
- assets/Scheme1.png
|
181
|
-
- assets/Scheme2.png
|
182
|
-
- assets/cpu_chart.gif
|
183
|
-
- assets/cpu_chart2.gif
|
184
|
-
- assets/evlms.png
|
185
|
-
- benchmarks/.gitignore
|
186
|
-
- benchmarks/2017-02-12.md
|
187
|
-
- benchmarks/2018-03-04.md
|
188
|
-
- benchmarks/2018-05-27-rpc-bench.md
|
189
|
-
- benchmarks/2018-10-27.md
|
190
|
-
- benchmarks/HowTo.md
|
191
|
-
- benchmarks/ansible.cfg
|
192
|
-
- benchmarks/assets/2018-10-27-action-cable-rss.png
|
193
|
-
- benchmarks/assets/2018-10-27-action-cable-rtt.png
|
194
|
-
- benchmarks/assets/2018-10-27-anycable-rss.png
|
195
|
-
- benchmarks/assets/2018-10-27-anycable-rtt.png
|
196
|
-
- benchmarks/assets/2018-10-27-async-rss.png
|
197
|
-
- benchmarks/assets/2018-10-27-async-rtt.png
|
198
|
-
- benchmarks/assets/2018-10-27-falcon-cable-rss.png
|
199
|
-
- benchmarks/assets/2018-10-27-falcon-cable-rtt.png
|
200
|
-
- benchmarks/assets/2018-10-27-iodine-cable-rss.png
|
201
|
-
- benchmarks/assets/2018-10-27-iodine-cable-rtt.png
|
202
|
-
- benchmarks/assets/2018-10-27-plezi-rss.png
|
203
|
-
- benchmarks/assets/2018-10-27-plezi-rtt.png
|
204
|
-
- benchmarks/bench.png
|
205
|
-
- benchmarks/benchmark.yml
|
206
|
-
- benchmarks/hosts
|
207
|
-
- benchmarks/rtt_plot.py
|
208
|
-
- benchmarks/rtt_plot_test.py
|
209
|
-
- benchmarks/servers.yml
|
210
165
|
- bin/anycable
|
166
|
+
- bin/anycabled
|
211
167
|
- bin/console
|
212
168
|
- bin/setup
|
213
|
-
- circle.yml
|
214
|
-
- etc/bug_report_template.rb
|
215
169
|
- lib/anycable.rb
|
216
170
|
- lib/anycable/broadcast_adapters.rb
|
217
171
|
- lib/anycable/broadcast_adapters/redis.rb
|
218
172
|
- lib/anycable/cli.rb
|
219
173
|
- lib/anycable/config.rb
|
220
174
|
- lib/anycable/exceptions_handling.rb
|
221
|
-
- lib/anycable/handler/capture_exceptions.rb
|
222
175
|
- lib/anycable/health_server.rb
|
223
176
|
- lib/anycable/middleware.rb
|
224
177
|
- lib/anycable/middleware_chain.rb
|
178
|
+
- lib/anycable/middlewares/check_version.rb
|
179
|
+
- lib/anycable/rpc.rb
|
225
180
|
- lib/anycable/rpc/rpc_pb.rb
|
226
181
|
- lib/anycable/rpc/rpc_services_pb.rb
|
227
182
|
- lib/anycable/rpc_handler.rb
|
183
|
+
- lib/anycable/rspec.rb
|
184
|
+
- lib/anycable/rspec/rpc_command_context.rb
|
185
|
+
- lib/anycable/rspec/rpc_stub_context.rb
|
186
|
+
- lib/anycable/rspec/with_grpc_server.rb
|
228
187
|
- lib/anycable/server.rb
|
229
188
|
- lib/anycable/socket.rb
|
230
189
|
- lib/anycable/version.rb
|
231
|
-
- protos/rpc.proto
|
232
190
|
homepage: http://github.com/anycable/anycable
|
233
191
|
licenses:
|
234
192
|
- MIT
|
235
|
-
metadata:
|
193
|
+
metadata:
|
194
|
+
bug_tracker_uri: http://github.com/anycable/anycable/issues
|
195
|
+
changelog_uri: https://github.com/anycable/anycable/blob/master/CHANGELOG.md
|
196
|
+
documentation_uri: https://docs.anycable.io/
|
197
|
+
homepage_uri: https://anycable.io/
|
198
|
+
source_code_uri: http://github.com/anycable/anycable
|
236
199
|
post_install_message:
|
237
200
|
rdoc_options: []
|
238
201
|
require_paths:
|
@@ -241,15 +204,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
241
204
|
requirements:
|
242
205
|
- - ">="
|
243
206
|
- !ruby/object:Gem::Version
|
244
|
-
version: 2.
|
207
|
+
version: 2.5.0
|
245
208
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
246
209
|
requirements:
|
247
210
|
- - ">"
|
248
211
|
- !ruby/object:Gem::Version
|
249
212
|
version: 1.3.1
|
250
213
|
requirements: []
|
251
|
-
|
252
|
-
rubygems_version: 2.7.7
|
214
|
+
rubygems_version: 3.0.6
|
253
215
|
signing_key:
|
254
216
|
specification_version: 4
|
255
217
|
summary: AnyCable is a polyglot replacement for ActionCable-compatible servers
|
data/.github/ISSUE_TEMPLATE.md
DELETED
@@ -1,25 +0,0 @@
|
|
1
|
-
<!--
|
2
|
-
First of all, thanks for your report/suggestion/whatever!
|
3
|
-
|
4
|
-
This template is for bug reports. If you are reporting a bug, please continue on. If you are here for another reason,
|
5
|
-
feel free to skip the rest of this template.
|
6
|
-
-->
|
7
|
-
|
8
|
-
### Tell us about your environment
|
9
|
-
|
10
|
-
**Ruby version:**
|
11
|
-
|
12
|
-
**`anycable` gem version:**
|
13
|
-
|
14
|
-
**`grpc` gem version:**
|
15
|
-
|
16
|
-
### What did you do?
|
17
|
-
|
18
|
-
### What did you expect to happen?
|
19
|
-
|
20
|
-
### What actually happened?
|
21
|
-
|
22
|
-
<!--
|
23
|
-
Please, provide reproduction script (using this template (https://github.com/anycable/anycable/blob/master/etc/bug_report_template.rb)
|
24
|
-
when submitting bugs if possible.
|
25
|
-
-->
|