anycable 0.4.6 → 0.5.0.rc1
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/.rubocop.yml +8 -1
- data/CHANGELOG.md +32 -1
- data/Makefile +2 -1
- data/README.md +29 -2
- data/Rakefile +3 -1
- data/anycable.gemspec +6 -4
- data/benchmarks/.gitignore +1 -0
- data/benchmarks/HowTo.md +23 -0
- data/benchmarks/ansible.cfg +9 -0
- data/benchmarks/benchmark.yml +40 -0
- data/benchmarks/hosts +5 -0
- data/benchmarks/servers.yml +29 -0
- data/lib/anycable.rb +19 -3
- data/lib/anycable/config.rb +18 -6
- data/lib/anycable/handler/exceptions_handling.rb +24 -10
- data/lib/anycable/pubsub.rb +6 -1
- data/lib/anycable/rpc/{rpc.rb → rpc_pb.rb} +4 -0
- data/lib/anycable/rpc/{rpc_services.rb → rpc_services_pb.rb} +0 -2
- data/lib/anycable/rpc_handler.rb +19 -11
- data/lib/anycable/server.rb +24 -11
- data/lib/anycable/socket.rb +1 -0
- data/lib/anycable/version.rb +2 -1
- data/protos/rpc.proto +4 -0
- metadata +35 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2c34f2dcdd663a7a4197be6ae56359d8e1f15fd7
|
4
|
+
data.tar.gz: 43eebb1490b11a6fdbf3d7aa65658f8cc25cd48f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2a684670f4fe590b9cc9da89c92c94bb42e3168cb531e75ff4a21cda4c4fb39683041bd40da4bbaaaaf8b331910c00453971c8571e302521b016116d1747d868
|
7
|
+
data.tar.gz: e0f67df078fa371f6d989ec03d8deced4908e61a1f37c206b1a77ecbff92e675c80f604dc7fa22dc45fbfb9fe3d4227fe505f55bc787c8d37279942325cf96d2
|
data/.rubocop.yml
CHANGED
@@ -9,14 +9,21 @@ AllCops:
|
|
9
9
|
- 'spec/dummy/**/*'
|
10
10
|
- 'tmp/**/*'
|
11
11
|
- 'bench/**/*'
|
12
|
+
- 'vendor/**/*'
|
12
13
|
- 'lib/anycable/rpc/**/*'
|
14
|
+
- 'Gemfile'
|
15
|
+
- 'Rakefile'
|
16
|
+
- '*.gemspec'
|
13
17
|
DisplayCopNames: true
|
14
18
|
StyleGuideCopsOnly: false
|
15
|
-
TargetRubyVersion: 2.
|
19
|
+
TargetRubyVersion: 2.4
|
16
20
|
|
17
21
|
Style/AccessorMethodName:
|
18
22
|
Enabled: false
|
19
23
|
|
24
|
+
Style/PercentLiteralDelimiters:
|
25
|
+
Enabled: false
|
26
|
+
|
20
27
|
Style/TrivialAccessors:
|
21
28
|
Enabled: false
|
22
29
|
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,36 @@
|
|
1
1
|
# Change log
|
2
2
|
|
3
|
+
## 0.5.0 (master)
|
4
|
+
|
5
|
+
- [#2](https://github.com/anycable/anycable/issues/2) Add support for [Redis Sentinel](https://redis.io/topics/sentinel). ([@accessd](https://github.com/accessd))
|
6
|
+
|
7
|
+
- [#28](https://github.com/anycable/anycable/issues/28) Support arbitrary headers. ([@palkan][])
|
8
|
+
|
9
|
+
Previously we hardcoded only "Cookie" header. Now we add all passed headers by WebSocket server to request env.
|
10
|
+
|
11
|
+
- [#27](https://github.com/anycable/anycable/issues/27) Add `error_msg` to RPC responses. ([@palkan][])
|
12
|
+
|
13
|
+
Now RPC responses has 3 statuses:
|
14
|
+
|
15
|
+
- `SUCCESS` – successful request, operation succeed
|
16
|
+
- `FAILURE` – successful request, operation failed (e.g. authentication failed)
|
17
|
+
- `ERROR` – request failed (exception raised).
|
18
|
+
|
19
|
+
We provide `error_msg` only when request status is `ERROR`.
|
20
|
+
|
21
|
+
- [#25](https://github.com/anycable/anycable/issues/25) Improve logging and exceptions handling. ([@palkan][])
|
22
|
+
|
23
|
+
Default logger logs to STDOUT with `info` level by default but can be configured to log to file with
|
24
|
+
any severity.
|
25
|
+
|
26
|
+
GRPC logging is turned off by default (can be turned on through `log_grpc` configuration parameter).
|
27
|
+
|
28
|
+
`ANYCABLE_DEBUG=1` acts as a shortcut to set `debug` level and turn on GRPC logging.
|
29
|
+
|
30
|
+
Now it's possible to add custom exception handlers (e.g. to notify external exception tracking services).
|
31
|
+
|
32
|
+
More on [Wiki](https://github.com/anycable/anycable/wiki/Logging-&-Exceptions-Handling).
|
33
|
+
|
3
34
|
## 0.4.6 (2017-05-20)
|
4
35
|
|
5
36
|
- Add `Anycable::Server#stop` method. ([@sadovnik][])
|
@@ -53,4 +84,4 @@ All Rails specifics now live here https://github.com/anycable/anycable-rails.
|
|
53
84
|
Implement `Disconnect` handler, which invokes `Connection#disconnect` (along with `Channel#unsubscribed` for each subscription).
|
54
85
|
|
55
86
|
[@palkan]: https://github.com/palkan
|
56
|
-
[@sadovnik]: https://github.com/sadovnik
|
87
|
+
[@sadovnik]: https://github.com/sadovnik
|
data/Makefile
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
all: build
|
2
2
|
|
3
3
|
build:
|
4
|
-
|
4
|
+
grpc_tools_ruby_protoc -I ./protos --ruby_out=./lib/anycable/rpc --grpc_out=./lib/anycable/rpc ./protos/rpc.proto
|
5
|
+
sed -i '' '/'rpc_pb'/d' ./lib/anycable/rpc/rpc_services_pb.rb
|
data/README.md
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
[](https://gitpitch.com/anycable/anycable/master?grs=github) [](https://rubygems.org/gems/anycable) [](https://travis-ci.org/anycable/anycable) [](https://circleci.com/gh/anycable/anycable/tree/master)
|
2
|
+
[](https://dependencyci.com/github/anycable/anycable)
|
2
3
|
[](https://gitter.im/anycable/Lobby)
|
3
4
|
|
4
5
|
# Anycable
|
@@ -7,7 +8,7 @@ AnyCable allows you to use any WebSocket server (written in any language) as a r
|
|
7
8
|
|
8
9
|
AnyCable uses ActionCable protocol, so you can use ActionCable [JavaScript client](https://www.npmjs.com/package/actioncable) without any monkey-patching.
|
9
10
|
|
10
|
-
**NOTE**: Since version 0.4.0 this repository contains only core functionality and
|
11
|
+
**NOTE**: Since version 0.4.0 this repository contains only core functionality and cannot be used separately as is.
|
11
12
|
Rails plug-n-play integration has been extracted to [anycable-rails](https://github.com/anycable/anycable-rails) gem.
|
12
13
|
|
13
14
|
<a href="https://evilmartians.com/">
|
@@ -40,11 +41,22 @@ Read our [Wiki](https://github.com/anycable/anycable/wiki) for more.
|
|
40
41
|
|
41
42
|
Anycable uses [anyway_config](https://github.com/palkan/anyway_config), thus it is also possible to set configuration variables through `secrets.yml` or environment vars.
|
42
43
|
|
44
|
+
### Example with redis sentinel
|
45
|
+
|
46
|
+
```yaml
|
47
|
+
rpc_host: "localhost:50123"
|
48
|
+
redis_url: "redis://redis-1-1:6379/2"
|
49
|
+
redis_sentinels:
|
50
|
+
- { host: 'redis-1-1', port: 26379 }
|
51
|
+
- { host: 'redis-1-2', port: 26379 }
|
52
|
+
- { host: 'redis-1-3', port: 26379 }
|
53
|
+
```
|
54
|
+
|
43
55
|
## ActionCable Compatibility
|
44
56
|
|
45
57
|
This is the compatibility list for the AnyCable gem, not for AnyCable servers (which may not support some of the features yet).
|
46
58
|
|
47
|
-
Feature | Status
|
59
|
+
Feature | Status
|
48
60
|
-------------------------|--------
|
49
61
|
Connection Identifiers | +
|
50
62
|
Connection Request (cookies, params) | +
|
@@ -58,6 +70,21 @@ Streaming | +
|
|
58
70
|
[Custom stream callbacks](http://edgeapi.rubyonrails.org/classes/ActionCable/Channel/Streams.html) | -
|
59
71
|
Broadcasting | +
|
60
72
|
|
73
|
+
## Build
|
74
|
+
|
75
|
+
- Install required GRPC gems:
|
76
|
+
|
77
|
+
```
|
78
|
+
gem install grpc
|
79
|
+
gem install grpc-tools
|
80
|
+
```
|
81
|
+
|
82
|
+
- Re-generate GRPC files (if necessary):
|
83
|
+
|
84
|
+
```
|
85
|
+
make
|
86
|
+
```
|
87
|
+
|
61
88
|
## Contributing
|
62
89
|
|
63
90
|
Bug reports and pull requests are welcome on GitHub at https://github.com/anycable/anycable.
|
data/Rakefile
CHANGED
data/anycable.gemspec
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
#
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
2
3
|
lib = File.expand_path('../lib', __FILE__)
|
3
4
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
5
|
require 'anycable/version'
|
@@ -17,14 +18,15 @@ Gem::Specification.new do |spec|
|
|
17
18
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
19
|
spec.require_paths = ["lib"]
|
19
20
|
|
20
|
-
spec.add_dependency "anyway_config", "~>
|
21
|
-
spec.add_dependency "grpc", "~> 1.
|
22
|
-
spec.add_dependency "redis", "
|
21
|
+
spec.add_dependency "anyway_config", "~> 1.1"
|
22
|
+
spec.add_dependency "grpc", "~> 1.6"
|
23
|
+
spec.add_dependency "redis", ">= 3.2"
|
23
24
|
|
24
25
|
spec.add_development_dependency "bundler", "~> 1"
|
25
26
|
spec.add_development_dependency "rake", ">= 10.0"
|
26
27
|
spec.add_development_dependency "rack", "~> 2.0"
|
27
28
|
spec.add_development_dependency "rspec", ">= 3.5"
|
29
|
+
spec.add_development_dependency "rubocop", ">= 0.50"
|
28
30
|
spec.add_development_dependency "simplecov", ">= 0.3.8"
|
29
31
|
spec.add_development_dependency "pry-byebug"
|
30
32
|
end
|
@@ -0,0 +1 @@
|
|
1
|
+
*.retry
|
data/benchmarks/HowTo.md
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
## Hot to run benchmarks
|
2
|
+
|
3
|
+
### Installation
|
4
|
+
|
5
|
+
- Install [Ansible](http://ansible.com) (`brew install ansible`)
|
6
|
+
|
7
|
+
- Launch two EC2 instances from `anycable-benchmark-xxx` AMI
|
8
|
+
|
9
|
+
- Attach more local network interfaces to the _client_ instance
|
10
|
+
|
11
|
+
- Update `hosts` file and playbooks with required information (IPs, etc)
|
12
|
+
|
13
|
+
- Prepare the _client_ instance: `ansible-playbook --extra-vars="prepare=True" benchmark.yml`
|
14
|
+
|
15
|
+
### Running benchmarks
|
16
|
+
|
17
|
+
To run a server, e.g. Action Cable: `ansible-playbook --tags action_cable servers.yml`
|
18
|
+
|
19
|
+
To run a benchmark against it: `ansible-playbook --tags action_cable benchmark.yml`
|
20
|
+
|
21
|
+
You can also specify benchmark parameters: `ansible-playbook --extra-vars "step_size=1000 steps=10 sample_size=10" benchmark.yml`.
|
22
|
+
|
23
|
+
**NOTE**: Ansible doesn't support command output streaming, so we can only see the results at the end of the run.
|
@@ -0,0 +1,40 @@
|
|
1
|
+
---
|
2
|
+
- name: Benchmark Client
|
3
|
+
hosts: benchmark
|
4
|
+
sudo: yes
|
5
|
+
remote_user: ubuntu
|
6
|
+
gather_facts: False
|
7
|
+
vars:
|
8
|
+
server_host: '172.31.22.14'
|
9
|
+
hostname: ws-bench-client
|
10
|
+
local_ips: ['172.31.21.241', '172.31.21.242', '172.31.21.243', '172.31.21.244']
|
11
|
+
local_ips_str: '-l 172.31.21.241 -l 172.31.21.242 -l 172.31.21.243 -l 172.31.21.244'
|
12
|
+
steps: 10
|
13
|
+
step_size: 1000
|
14
|
+
sample_size: 40
|
15
|
+
prepare: False
|
16
|
+
tasks:
|
17
|
+
- name: Prepare the machine
|
18
|
+
when: prepare
|
19
|
+
block:
|
20
|
+
- hostname:
|
21
|
+
name: "{{ hostname }}"
|
22
|
+
- lineinfile:
|
23
|
+
path: /etc/hosts
|
24
|
+
line: '127.0.0.1 {{ hostname }}'
|
25
|
+
state: present
|
26
|
+
- shell: ip addr add {{ item }}/20 dev eth0
|
27
|
+
with_items: "{{ local_ips }}"
|
28
|
+
- name: Action Cable benchmark
|
29
|
+
become_user: deplo
|
30
|
+
shell: bin/websocket-bench broadcast {{ local_ips_str }} --concurrent 4 --sample-size {{ sample_size }} --step-size {{ step_size }} --payload-padding 200 --total-steps {{ steps }} --origin http://0.0.0.0 ws://{{ server_host }}:3334/cable --server-type=actioncable
|
31
|
+
register: bench
|
32
|
+
tags: action_cable
|
33
|
+
args:
|
34
|
+
chdir: /webapps/anycable_bench
|
35
|
+
ignore_errors: yes
|
36
|
+
|
37
|
+
- name: Benchmark results
|
38
|
+
debug: var=bench.stdout_lines
|
39
|
+
tags:
|
40
|
+
- action_cable
|
data/benchmarks/hosts
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
---
|
2
|
+
- name: Benchmark Servers
|
3
|
+
hosts: servers
|
4
|
+
sudo: yes
|
5
|
+
remote_user: ubuntu
|
6
|
+
gather_facts: False
|
7
|
+
vars:
|
8
|
+
rails_webc: 8
|
9
|
+
tasks:
|
10
|
+
- name: Kill servers
|
11
|
+
shell: pid=$(lsof -i:{{item}} -t); kill -TERM $pid || kill -KILL $pid
|
12
|
+
tags:
|
13
|
+
- action_cable
|
14
|
+
- anycable
|
15
|
+
with_items:
|
16
|
+
- "3334"
|
17
|
+
ignore_errors: true
|
18
|
+
- name: Run Action Cable
|
19
|
+
become_user: deplo
|
20
|
+
tags: action_cable
|
21
|
+
shell: WEB_CONCURRENCY={{ rails_webc }} bundle exec rails s -p 3334 -e production
|
22
|
+
args:
|
23
|
+
chdir: /webapps/anycable_bench/ruby/action-cable-server
|
24
|
+
- name: Run Anycable Go
|
25
|
+
become_user: deplo
|
26
|
+
tags: anycable
|
27
|
+
shell: bundle exec anycable
|
28
|
+
args:
|
29
|
+
chdir: /webapps/anycable_bench/ruby/action-cable-server/bin
|
data/lib/anycable.rb
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require "anycable/version"
|
3
4
|
require "anycable/config"
|
4
|
-
require "anycable/server"
|
5
|
-
require "anycable/pubsub"
|
6
5
|
require "logger"
|
7
6
|
|
8
7
|
# Anycable allows to use any websocket service (written in any language) as a replacement
|
@@ -14,12 +13,21 @@ require "logger"
|
|
14
13
|
# Broadcasting messages to WS is done through Redis Pub/Sub.
|
15
14
|
module Anycable
|
16
15
|
class << self
|
16
|
+
# Provide connection factory which
|
17
|
+
# is a callable object with build
|
18
|
+
# a Connection object
|
19
|
+
attr_accessor :connection_factory
|
20
|
+
|
17
21
|
def logger=(logger)
|
18
22
|
@logger = logger
|
19
23
|
end
|
20
24
|
|
21
25
|
def logger
|
22
|
-
@logger
|
26
|
+
return @logger if instance_variable_defined?(:@logger)
|
27
|
+
log_output = Anycable.config.log_file || STDOUT
|
28
|
+
@logger = Logger.new(log_output).tap do |logger|
|
29
|
+
logger.level = Anycable.config.log_level
|
30
|
+
end
|
23
31
|
end
|
24
32
|
|
25
33
|
def config
|
@@ -30,6 +38,11 @@ module Anycable
|
|
30
38
|
yield(config) if block_given?
|
31
39
|
end
|
32
40
|
|
41
|
+
def error_handlers
|
42
|
+
return @error_handlers if instance_variable_defined?(:@error_handlers)
|
43
|
+
@error_handlers = []
|
44
|
+
end
|
45
|
+
|
33
46
|
def pubsub
|
34
47
|
@pubsub ||= PubSub.new
|
35
48
|
end
|
@@ -40,3 +53,6 @@ module Anycable
|
|
40
53
|
end
|
41
54
|
end
|
42
55
|
end
|
56
|
+
|
57
|
+
require "anycable/server"
|
58
|
+
require "anycable/pubsub"
|
data/lib/anycable/config.rb
CHANGED
@@ -1,15 +1,27 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
|
2
|
+
|
3
|
+
require "anyway_config"
|
3
4
|
|
4
5
|
module Anycable
|
5
|
-
# Anycable configuration
|
6
|
+
# Anycable configuration.
|
6
7
|
class Config < Anyway::Config
|
7
8
|
config_name :anycable
|
8
9
|
|
9
|
-
attr_config :
|
10
|
-
rpc_host: "localhost:50051",
|
10
|
+
attr_config rpc_host: "localhost:50051",
|
11
11
|
redis_url: "redis://localhost:6379/5",
|
12
|
-
|
13
|
-
|
12
|
+
redis_sentinels: [],
|
13
|
+
redis_channel: "__anycable__",
|
14
|
+
log_file: nil,
|
15
|
+
log_level: :info,
|
16
|
+
log_grpc: false,
|
17
|
+
debug: false # Shortcut to enable GRPC logging and debug level
|
18
|
+
|
19
|
+
def initialize(*)
|
20
|
+
super
|
21
|
+
# Set log params if debug is true
|
22
|
+
return unless debug
|
23
|
+
self.log_level = :debug
|
24
|
+
self.log_grpc = true
|
25
|
+
end
|
14
26
|
end
|
15
27
|
end
|
@@ -1,29 +1,43 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Anycable
|
4
|
-
module Handler
|
4
|
+
module Handler # :nodoc:
|
5
5
|
# Handle app-level errors
|
6
6
|
module ExceptionsHandling
|
7
7
|
def connect(*)
|
8
8
|
super
|
9
|
-
rescue StandardError =>
|
10
|
-
|
11
|
-
Anycable::ConnectionResponse.new(status: Anycable::Status::ERROR)
|
9
|
+
rescue StandardError => ex
|
10
|
+
handle_exception(ex)
|
11
|
+
Anycable::ConnectionResponse.new(status: Anycable::Status::ERROR, error_msg: ex.message)
|
12
12
|
end
|
13
13
|
|
14
14
|
def disconnect(*)
|
15
15
|
super
|
16
|
-
rescue StandardError =>
|
17
|
-
|
18
|
-
Anycable::DisconnectResponse.new(status: Anycable::Status::ERROR)
|
16
|
+
rescue StandardError => ex
|
17
|
+
handle_exception(ex)
|
18
|
+
Anycable::DisconnectResponse.new(status: Anycable::Status::ERROR, error_msg: ex.message)
|
19
19
|
end
|
20
20
|
|
21
21
|
def command(*)
|
22
22
|
super
|
23
|
-
rescue StandardError =>
|
24
|
-
|
25
|
-
Anycable::CommandResponse.new(status: Anycable::Status::ERROR)
|
23
|
+
rescue StandardError => ex
|
24
|
+
handle_exception(ex)
|
25
|
+
Anycable::CommandResponse.new(status: Anycable::Status::ERROR, error_msg: ex.message)
|
26
|
+
end
|
27
|
+
|
28
|
+
def handle_exception(ex)
|
29
|
+
Anycable.error_handlers.each do |handler|
|
30
|
+
begin
|
31
|
+
handler.call(ex)
|
32
|
+
rescue StandardError => ex
|
33
|
+
Anycable.logger.error "!!! ERROR HANDLER THREW AN ERROR !!!"
|
34
|
+
Anycable.logger.error ex
|
35
|
+
Anycable.logger.error ex.backtrace.join("\n") unless ex.backtrace.nil?
|
36
|
+
end
|
37
|
+
end
|
26
38
|
end
|
27
39
|
end
|
40
|
+
|
41
|
+
Anycable.error_handlers << proc { |e| Anycable.logger.error(e.message) }
|
28
42
|
end
|
29
43
|
end
|
data/lib/anycable/pubsub.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require "redis"
|
3
4
|
require "json"
|
4
5
|
|
@@ -8,7 +9,11 @@ module Anycable
|
|
8
9
|
attr_reader :redis_conn
|
9
10
|
|
10
11
|
def initialize
|
11
|
-
|
12
|
+
redis_config = { url: Anycable.config.redis_url }
|
13
|
+
unless Anycable.config.redis_sentinels.empty?
|
14
|
+
redis_config[:sentinels] = Anycable.config.redis_sentinels
|
15
|
+
end
|
16
|
+
@redis_conn = Redis.new(redis_config)
|
12
17
|
end
|
13
18
|
|
14
19
|
def broadcast(channel, payload)
|
@@ -12,6 +12,7 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
|
|
12
12
|
optional :status, :enum, 1, "anycable.Status"
|
13
13
|
optional :identifiers, :string, 2
|
14
14
|
repeated :transmissions, :string, 3
|
15
|
+
optional :error_msg, :string, 4
|
15
16
|
end
|
16
17
|
add_message "anycable.CommandMessage" do
|
17
18
|
optional :command, :string, 1
|
@@ -25,6 +26,7 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
|
|
25
26
|
optional :stop_streams, :bool, 3
|
26
27
|
repeated :streams, :string, 4
|
27
28
|
repeated :transmissions, :string, 5
|
29
|
+
optional :error_msg, :string, 6
|
28
30
|
end
|
29
31
|
add_message "anycable.DisconnectRequest" do
|
30
32
|
optional :identifiers, :string, 1
|
@@ -34,10 +36,12 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
|
|
34
36
|
end
|
35
37
|
add_message "anycable.DisconnectResponse" do
|
36
38
|
optional :status, :enum, 1, "anycable.Status"
|
39
|
+
optional :error_msg, :string, 2
|
37
40
|
end
|
38
41
|
add_enum "anycable.Status" do
|
39
42
|
value :ERROR, 0
|
40
43
|
value :SUCCESS, 1
|
44
|
+
value :FAILURE, 2
|
41
45
|
end
|
42
46
|
end
|
43
47
|
|
data/lib/anycable/rpc_handler.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'anycable/socket'
|
3
|
-
require 'anycable/rpc/
|
4
|
-
require 'anycable/rpc/
|
4
|
+
require 'anycable/rpc/rpc_pb'
|
5
|
+
require 'anycable/rpc/rpc_services_pb'
|
5
6
|
|
6
7
|
require 'anycable/handler/exceptions_handling'
|
7
8
|
|
@@ -18,12 +19,12 @@ module Anycable
|
|
18
19
|
|
19
20
|
socket = build_socket(env: rack_env(request))
|
20
21
|
|
21
|
-
connection = factory.
|
22
|
+
connection = factory.call(socket)
|
22
23
|
|
23
24
|
connection.handle_open
|
24
25
|
|
25
26
|
if socket.closed?
|
26
|
-
Anycable::ConnectionResponse.new(status: Anycable::Status::
|
27
|
+
Anycable::ConnectionResponse.new(status: Anycable::Status::FAILURE)
|
27
28
|
else
|
28
29
|
Anycable::ConnectionResponse.new(
|
29
30
|
status: Anycable::Status::SUCCESS,
|
@@ -38,7 +39,7 @@ module Anycable
|
|
38
39
|
|
39
40
|
socket = build_socket(env: rack_env(request))
|
40
41
|
|
41
|
-
connection = factory.
|
42
|
+
connection = factory.call(
|
42
43
|
socket,
|
43
44
|
identifiers: request.identifiers,
|
44
45
|
subscriptions: request.subscriptions
|
@@ -47,7 +48,7 @@ module Anycable
|
|
47
48
|
if connection.handle_close
|
48
49
|
Anycable::DisconnectResponse.new(status: Anycable::Status::SUCCESS)
|
49
50
|
else
|
50
|
-
Anycable::DisconnectResponse.new(status: Anycable::Status::
|
51
|
+
Anycable::DisconnectResponse.new(status: Anycable::Status::FAILURE)
|
51
52
|
end
|
52
53
|
end
|
53
54
|
|
@@ -56,7 +57,7 @@ module Anycable
|
|
56
57
|
|
57
58
|
socket = build_socket
|
58
59
|
|
59
|
-
connection = factory.
|
60
|
+
connection = factory.call(
|
60
61
|
socket,
|
61
62
|
identifiers: message.connection_identifiers
|
62
63
|
)
|
@@ -68,7 +69,7 @@ module Anycable
|
|
68
69
|
)
|
69
70
|
|
70
71
|
Anycable::CommandResponse.new(
|
71
|
-
status: result ? Anycable::Status::SUCCESS : Anycable::Status::
|
72
|
+
status: result ? Anycable::Status::SUCCESS : Anycable::Status::FAILURE,
|
72
73
|
disconnect: socket.closed?,
|
73
74
|
stop_streams: socket.stop_streams?,
|
74
75
|
streams: socket.streams,
|
@@ -87,24 +88,31 @@ module Anycable
|
|
87
88
|
'PATH_INFO' => uri.path,
|
88
89
|
'SERVER_PORT' => uri.port.to_s,
|
89
90
|
'HTTP_HOST' => uri.host,
|
90
|
-
'HTTP_COOKIE' => request.headers['Cookie'],
|
91
91
|
# Hack to avoid Missing rack.input error
|
92
92
|
'rack.request.form_input' => '',
|
93
93
|
'rack.input' => '',
|
94
94
|
'rack.request.form_hash' => {}
|
95
|
-
}
|
95
|
+
}.merge(build_headers(request.headers))
|
96
96
|
end
|
97
97
|
|
98
98
|
def build_socket(**options)
|
99
99
|
Anycable::Socket.new(**options)
|
100
100
|
end
|
101
101
|
|
102
|
+
def build_headers(headers)
|
103
|
+
headers.each_with_object({}) do |(k, v), obj|
|
104
|
+
k = k.upcase
|
105
|
+
k.tr!('-', '_')
|
106
|
+
obj["HTTP_#{k}"] = v
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
102
110
|
def logger
|
103
111
|
Anycable.logger
|
104
112
|
end
|
105
113
|
|
106
114
|
def factory
|
107
|
-
Anycable.
|
115
|
+
Anycable.connection_factory
|
108
116
|
end
|
109
117
|
end
|
110
118
|
end
|
data/lib/anycable/server.rb
CHANGED
@@ -1,31 +1,44 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'grpc'
|
3
4
|
require 'anycable/rpc_handler'
|
4
5
|
|
5
|
-
# Set GRPC logger
|
6
|
-
module GRPC
|
7
|
-
def self.logger
|
8
|
-
Anycable.logger
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
6
|
module Anycable
|
13
7
|
# Wrapper over GRPC server
|
14
8
|
module Server
|
15
9
|
class << self
|
16
|
-
|
10
|
+
attr_reader :grpc_server
|
17
11
|
|
18
12
|
def start
|
19
|
-
|
20
|
-
grpc_server
|
21
|
-
|
13
|
+
log_grpc! if Anycable.config.log_grpc
|
14
|
+
@grpc_server ||= build_server
|
15
|
+
|
22
16
|
Anycable.logger.info "RPC server is listening on #{Anycable.config.rpc_host}"
|
23
17
|
grpc_server.run_till_terminated
|
24
18
|
end
|
25
19
|
|
26
20
|
def stop
|
21
|
+
return unless running?
|
27
22
|
@grpc_server.stop
|
28
23
|
end
|
24
|
+
|
25
|
+
def running?
|
26
|
+
grpc_server&.running_state == :running
|
27
|
+
end
|
28
|
+
|
29
|
+
# Enable GRPC logging
|
30
|
+
def log_grpc!
|
31
|
+
GRPC.define_singleton_method(:logger) { Anycable.logger }
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def build_server
|
37
|
+
GRPC::RpcServer.new.tap do |server|
|
38
|
+
server.add_http2_port(Anycable.config.rpc_host, :this_port_is_insecure)
|
39
|
+
server.handle(Anycable::RPCHandler)
|
40
|
+
end
|
41
|
+
end
|
29
42
|
end
|
30
43
|
end
|
31
44
|
end
|
data/lib/anycable/socket.rb
CHANGED
data/lib/anycable/version.rb
CHANGED
data/protos/rpc.proto
CHANGED
@@ -11,6 +11,7 @@ service RPC {
|
|
11
11
|
enum Status {
|
12
12
|
ERROR = 0;
|
13
13
|
SUCCESS = 1;
|
14
|
+
FAILURE = 2;
|
14
15
|
}
|
15
16
|
|
16
17
|
message ConnectionRequest {
|
@@ -22,6 +23,7 @@ message ConnectionResponse {
|
|
22
23
|
Status status = 1;
|
23
24
|
string identifiers = 2;
|
24
25
|
repeated string transmissions = 3;
|
26
|
+
string error_msg = 4;
|
25
27
|
}
|
26
28
|
|
27
29
|
message CommandMessage {
|
@@ -37,6 +39,7 @@ message CommandResponse {
|
|
37
39
|
bool stop_streams = 3;
|
38
40
|
repeated string streams = 4;
|
39
41
|
repeated string transmissions = 5;
|
42
|
+
string error_msg = 6;
|
40
43
|
}
|
41
44
|
|
42
45
|
message DisconnectRequest {
|
@@ -48,4 +51,5 @@ message DisconnectRequest {
|
|
48
51
|
|
49
52
|
message DisconnectResponse {
|
50
53
|
Status status = 1;
|
54
|
+
string error_msg = 2;
|
51
55
|
}
|
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: 0.5.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- palkan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-10-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: anyway_config
|
@@ -16,42 +16,42 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: '1.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.1'
|
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.6'
|
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.6'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: redis
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '3.
|
47
|
+
version: '3.2'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '3.
|
54
|
+
version: '3.2'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: bundler
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,6 +108,20 @@ dependencies:
|
|
108
108
|
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '3.5'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: rubocop
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0.50'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0.50'
|
111
125
|
- !ruby/object:Gem::Dependency
|
112
126
|
name: simplecov
|
113
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -165,7 +179,13 @@ files:
|
|
165
179
|
- assets/cpu_chart.gif
|
166
180
|
- assets/cpu_chart2.gif
|
167
181
|
- assets/evlms.png
|
182
|
+
- benchmarks/.gitignore
|
168
183
|
- benchmarks/2017-02-12.md
|
184
|
+
- benchmarks/HowTo.md
|
185
|
+
- benchmarks/ansible.cfg
|
186
|
+
- benchmarks/benchmark.yml
|
187
|
+
- benchmarks/hosts
|
188
|
+
- benchmarks/servers.yml
|
169
189
|
- bin/console
|
170
190
|
- bin/setup
|
171
191
|
- circle.yml
|
@@ -173,8 +193,8 @@ files:
|
|
173
193
|
- lib/anycable/config.rb
|
174
194
|
- lib/anycable/handler/exceptions_handling.rb
|
175
195
|
- lib/anycable/pubsub.rb
|
176
|
-
- lib/anycable/rpc/
|
177
|
-
- lib/anycable/rpc/
|
196
|
+
- lib/anycable/rpc/rpc_pb.rb
|
197
|
+
- lib/anycable/rpc/rpc_services_pb.rb
|
178
198
|
- lib/anycable/rpc_handler.rb
|
179
199
|
- lib/anycable/server.rb
|
180
200
|
- lib/anycable/socket.rb
|
@@ -195,12 +215,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
195
215
|
version: '0'
|
196
216
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
197
217
|
requirements:
|
198
|
-
- - "
|
218
|
+
- - ">"
|
199
219
|
- !ruby/object:Gem::Version
|
200
|
-
version:
|
220
|
+
version: 1.3.1
|
201
221
|
requirements: []
|
202
222
|
rubyforge_project:
|
203
|
-
rubygems_version: 2.6.
|
223
|
+
rubygems_version: 2.6.13
|
204
224
|
signing_key:
|
205
225
|
specification_version: 4
|
206
226
|
summary: Polyglot replacement for ActionCable server
|