anycable-core 1.4.0 → 1.4.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 +8 -0
- data/lib/anycable/config.rb +2 -2
- data/lib/anycable/grpc/config.rb +16 -0
- data/lib/anycable/grpc/server.rb +8 -1
- data/lib/anycable/grpc_kit/server.rb +32 -6
- data/lib/anycable/version.rb +1 -1
- data/sig/anycable/config.rbs +1 -1
- data/sig/anycable/grpc/config.rbs +6 -0
- data/sig/anycable/grpc/server.rbs +1 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 391832d2af2280297419d7f62853313d8ac005e7ca826654d6669135748cb8e8
|
4
|
+
data.tar.gz: 229e4b51b7eaed689f0394445e86ba96cb08889391ae343b810439a727e30c0f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c951c3a248b67b9d481865d4a7c1e3d75f76ca963a8f314c8a4889fe9ab1e28eb889ecd48094c96802a20c9196f0932051167c1bd32b54ebf7d7d95dce71620b
|
7
|
+
data.tar.gz: 630c505792b0f374dc6acf7ffa861fcde660687ed7ac8894a0275e9f8d707133dbb9c29c24ed7b0e1dd8650b428a421243d5d1179361421996c850bdc50d0128
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,14 @@
|
|
2
2
|
|
3
3
|
## master
|
4
4
|
|
5
|
+
## 1.4.2 (2023-09-05)
|
6
|
+
|
7
|
+
- Fix parsing sentinel configuration from YAML in Rails. ([@palkan][])
|
8
|
+
|
9
|
+
## 1.4.1 (2023-07-24)
|
10
|
+
|
11
|
+
- Add TLS support for gRPC server. ([@Envek][])
|
12
|
+
|
5
13
|
## 1.4.0 (2023-07-07)
|
6
14
|
|
7
15
|
- Add HTTP RPC support. ([@palkan][])
|
data/lib/anycable/config.rb
CHANGED
@@ -98,7 +98,7 @@ module AnyCable
|
|
98
98
|
--http-health-path=path Endpoint to serve health checks, default: "/health"
|
99
99
|
|
100
100
|
REDIS PUB/SUB
|
101
|
-
--redis-url=url Redis URL for pub/sub, default: REDIS_URL or "redis://localhost:6379
|
101
|
+
--redis-url=url Redis URL for pub/sub, default: REDIS_URL or "redis://localhost:6379"
|
102
102
|
--redis-channel=name Redis channel for broadcasting, default: "__anycable__"
|
103
103
|
--redis-sentinels=<...hosts> Redis Sentinel followers addresses (as a comma-separated list), default: nil
|
104
104
|
--redis-tls-verify=yes|no Whether to perform server certificate check in case of rediss:// protocol. Default: yes
|
@@ -171,7 +171,7 @@ module AnyCable
|
|
171
171
|
private
|
172
172
|
|
173
173
|
def parse_sentinel(sentinel)
|
174
|
-
return sentinel.transform_keys
|
174
|
+
return sentinel.to_hash.transform_keys(&:to_sym) if sentinel.respond_to?(:to_hash)
|
175
175
|
|
176
176
|
uri = URI.parse("redis://#{sentinel}")
|
177
177
|
|
data/lib/anycable/grpc/config.rb
CHANGED
@@ -3,6 +3,8 @@
|
|
3
3
|
AnyCable::Config.attr_config(
|
4
4
|
### gRPC options
|
5
5
|
rpc_host: "127.0.0.1:50051",
|
6
|
+
rpc_tls_cert: nil,
|
7
|
+
rpc_tls_key: nil,
|
6
8
|
rpc_pool_size: 30,
|
7
9
|
rpc_max_waiting_requests: 20,
|
8
10
|
rpc_poll_period: 1,
|
@@ -32,6 +34,7 @@ module AnyCable
|
|
32
34
|
max_waiting_requests: rpc_max_waiting_requests,
|
33
35
|
poll_period: rpc_poll_period,
|
34
36
|
pool_keep_alive: rpc_pool_keep_alive,
|
37
|
+
tls_credentials: tls_credentials,
|
35
38
|
server_args: enhance_grpc_server_args(normalized_grpc_server_args)
|
36
39
|
}
|
37
40
|
end
|
@@ -53,6 +56,17 @@ module AnyCable
|
|
53
56
|
opts["grpc.max_connection_age_ms"] = rpc_max_connection_age.to_i * 1000
|
54
57
|
opts
|
55
58
|
end
|
59
|
+
|
60
|
+
def tls_credentials
|
61
|
+
cert_path_or_content = rpc_tls_cert # Assign to local variable to make steep happy
|
62
|
+
key_path_or_content = rpc_tls_key # Assign to local variable to make steep happy
|
63
|
+
return {} if cert_path_or_content.nil? || key_path_or_content.nil?
|
64
|
+
|
65
|
+
cert = File.exist?(cert_path_or_content) ? File.read(cert_path_or_content) : cert_path_or_content
|
66
|
+
pkey = File.exist?(key_path_or_content) ? File.read(key_path_or_content) : key_path_or_content
|
67
|
+
|
68
|
+
{cert: cert, pkey: pkey}
|
69
|
+
end
|
56
70
|
end
|
57
71
|
end
|
58
72
|
end
|
@@ -62,6 +76,8 @@ AnyCable::Config.prepend AnyCable::GRPC::Config
|
|
62
76
|
AnyCable::Config.usage <<~TXT
|
63
77
|
GRPC OPTIONS
|
64
78
|
--rpc-host=host Local address to run gRPC server on, default: "127.0.0.1:50051"
|
79
|
+
--rpc-tls-cert=path TLS certificate file path or contents in PEM format, default: <none> (TLS disabled)
|
80
|
+
--rpc-tls-key=path TLS private key file path or contents in PEM format, default: <none> (TLS disabled)
|
65
81
|
--rpc-pool-size=size gRPC workers pool size, default: 30
|
66
82
|
--rpc-max-waiting-requests=num Max waiting requests queue size, default: 20
|
67
83
|
--rpc-poll-period=seconds Poll period (sec), default: 1
|
data/lib/anycable/grpc/server.rb
CHANGED
@@ -83,8 +83,9 @@ module AnyCable
|
|
83
83
|
end
|
84
84
|
|
85
85
|
def build_server(**options)
|
86
|
+
tls_credentials = options.delete(:tls_credentials)
|
86
87
|
::GRPC::RpcServer.new(**options).tap do |server|
|
87
|
-
server.add_http2_port(host,
|
88
|
+
server.add_http2_port(host, server_credentials(**tls_credentials))
|
88
89
|
server.handle(AnyCable::GRPC::Handler)
|
89
90
|
server.handle(build_health_checker)
|
90
91
|
end
|
@@ -102,6 +103,12 @@ module AnyCable
|
|
102
103
|
)
|
103
104
|
health_checker
|
104
105
|
end
|
106
|
+
|
107
|
+
def server_credentials(cert: nil, pkey: nil)
|
108
|
+
return :this_port_is_insecure if cert.nil? || pkey.nil?
|
109
|
+
|
110
|
+
::GRPC::Core::ServerCredentials.new(nil, [{private_key: pkey, cert_chain: cert}], false)
|
111
|
+
end
|
105
112
|
end
|
106
113
|
end
|
107
114
|
end
|
@@ -2,9 +2,9 @@
|
|
2
2
|
|
3
3
|
require "anycable/grpc/handler"
|
4
4
|
|
5
|
-
require_relative "
|
6
|
-
require_relative "
|
7
|
-
require_relative "
|
5
|
+
require_relative "health_pb"
|
6
|
+
require_relative "health_services_pb"
|
7
|
+
require_relative "health_checker"
|
8
8
|
|
9
9
|
module AnyCable
|
10
10
|
module GRPC
|
@@ -44,6 +44,7 @@ module AnyCable
|
|
44
44
|
@hostname = host_parts[:hostname]
|
45
45
|
@port = host_parts[:port].to_i
|
46
46
|
|
47
|
+
@tls_credentials = options.delete(:tls_credentials)
|
47
48
|
@grpc_server = build_server(**options)
|
48
49
|
end
|
49
50
|
|
@@ -56,7 +57,7 @@ module AnyCable
|
|
56
57
|
|
57
58
|
logger.info "RPC server (grpc_kit) is starting..."
|
58
59
|
|
59
|
-
@sock =
|
60
|
+
@sock = build_server_socket
|
60
61
|
|
61
62
|
server = grpc_server
|
62
63
|
|
@@ -66,6 +67,12 @@ module AnyCable
|
|
66
67
|
server.run(conn)
|
67
68
|
rescue IOError
|
68
69
|
# ignore broken connections
|
70
|
+
rescue OpenSSL::SSL::SSLError => ssl_error
|
71
|
+
if ssl_error.message.match?(/SSL_read: unexpected eof while reading/i)
|
72
|
+
# ignore broken connections
|
73
|
+
else
|
74
|
+
raise
|
75
|
+
end
|
69
76
|
end
|
70
77
|
end
|
71
78
|
|
@@ -81,13 +88,18 @@ module AnyCable
|
|
81
88
|
|
82
89
|
loop do
|
83
90
|
sock = TCPSocket.new(hostname, port, connect_timeout: 1)
|
91
|
+
if @tls_credentials&.any?
|
92
|
+
sock = OpenSSL::SSL::SSLSocket.new(sock, tls_context)
|
93
|
+
sock.sync_close = true
|
94
|
+
sock.connect
|
95
|
+
end
|
84
96
|
stub = ::Grpc::Health::V1::Health::Stub.new(sock)
|
85
97
|
stub.check(::Grpc::Health::V1::HealthCheckRequest.new)
|
86
98
|
sock.close
|
87
99
|
break
|
88
|
-
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH, SocketError
|
100
|
+
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH, SocketError, OpenSSL::SSL::SSLError => e
|
89
101
|
timeout -= 1
|
90
|
-
raise "Server is not responding" if timeout.zero?
|
102
|
+
raise "Server is not responding: #{e}" if timeout.zero?
|
91
103
|
end
|
92
104
|
end
|
93
105
|
|
@@ -125,6 +137,20 @@ module AnyCable
|
|
125
137
|
@logger ||= AnyCable.logger
|
126
138
|
end
|
127
139
|
|
140
|
+
def build_server_socket
|
141
|
+
tcp_server = TCPServer.new(hostname, port)
|
142
|
+
return tcp_server unless @tls_credentials&.any?
|
143
|
+
|
144
|
+
OpenSSL::SSL::SSLServer.new(tcp_server, tls_context)
|
145
|
+
end
|
146
|
+
|
147
|
+
def tls_context
|
148
|
+
OpenSSL::SSL::SSLContext.new.tap do |tls_context|
|
149
|
+
tls_context.cert = OpenSSL::X509::Certificate.new(@tls_credentials.fetch(:cert))
|
150
|
+
tls_context.key = OpenSSL::PKey.read(@tls_credentials.fetch(:pkey))
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
128
154
|
def build_server(**options)
|
129
155
|
pool_size = options[:pool_size]
|
130
156
|
|
data/lib/anycable/version.rb
CHANGED
data/sig/anycable/config.rbs
CHANGED
@@ -68,7 +68,7 @@ module AnyCable
|
|
68
68
|
|
69
69
|
private
|
70
70
|
|
71
|
-
def parse_sentinel: (
|
71
|
+
def parse_sentinel: (untyped sentinel) -> Hash[Symbol, untyped]
|
72
72
|
def load_presets: () -> void
|
73
73
|
def detect_presets: () -> Array[String]
|
74
74
|
def write_preset: (Symbol, untyped, preset: String) -> void
|
@@ -3,6 +3,10 @@ module AnyCable
|
|
3
3
|
interface _Config
|
4
4
|
def rpc_host: () -> String
|
5
5
|
def rpc_host=: (String) -> void
|
6
|
+
def rpc_tls_cert: () -> String?
|
7
|
+
def rpc_tls_cert=: (String?) -> void
|
8
|
+
def rpc_tls_key: () -> String?
|
9
|
+
def rpc_tls_key=: (String?) -> void
|
6
10
|
def rpc_pool_size: () -> Integer
|
7
11
|
def rpc_pool_size=: (Integer) -> void
|
8
12
|
def rpc_max_waiting_requests: () -> Integer
|
@@ -28,11 +32,13 @@ module AnyCable
|
|
28
32
|
max_waiting_requests: Integer,
|
29
33
|
poll_period: Numeric,
|
30
34
|
pool_keep_alive: Numeric,
|
35
|
+
tls_credentials: Hash[Symbol, String],
|
31
36
|
server_args: Hash[String, untyped]
|
32
37
|
}
|
33
38
|
|
34
39
|
def normalized_grpc_server_args: () -> Hash[String, untyped]
|
35
40
|
def enhance_grpc_server_args: (Hash[String, untyped]) -> Hash[String, untyped]
|
41
|
+
def tls_credentials: () -> Hash[Symbol, String]
|
36
42
|
end
|
37
43
|
end
|
38
44
|
end
|
@@ -15,6 +15,7 @@ module AnyCable
|
|
15
15
|
def logger: () -> Logger
|
16
16
|
def build_server: (**untyped options) -> untyped
|
17
17
|
def build_health_checker: () -> untyped
|
18
|
+
def server_credentials: (?cert: String?, ?pkey: String?) -> (::GRPC::Core::ServerCredentials | :this_port_is_insecure)
|
18
19
|
end
|
19
20
|
end
|
20
21
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: anycable-core
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.4.
|
4
|
+
version: 1.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- palkan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-09-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: anyway_config
|