anycable-core 1.4.0 → 1.4.1
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 +4 -0
- data/lib/anycable/config.rb +1 -1
- data/lib/anycable/grpc/config.rb +16 -0
- data/lib/anycable/grpc/server.rb +8 -1
- data/lib/anycable/grpc_kit/server.rb +29 -3
- data/lib/anycable/version.rb +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: fead71a088b7431fb65a3cfdd16ebee3760700496e9cc0d440f40b118952ac6a
|
4
|
+
data.tar.gz: 26c7f7d1fd4fa3aefbf8e43358b8eb959e3aa707ec36d2d7775f657748e1afc5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 887068bded37ce33ebdb0a5ae2ffce3afbb545053a544db83ad581008ac0ec603a45019df8a87281030b790db90f2aae3c812b3434b3c782ac69f29d04c535bd
|
7
|
+
data.tar.gz: c2e49c2fc7becb3c9b9076fd57f988abec053bd419e56dd0769d4e086704a66fd80dab0ffa485a9221053b9742a55de38c90b1463d1d5264b385c7b2f132d33d
|
data/CHANGELOG.md
CHANGED
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
|
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
|
@@ -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
@@ -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.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- palkan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-07-
|
11
|
+
date: 2023-07-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: anyway_config
|