anycable-core 1.1.0.pre1 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0f3906d5bd75c90a70af60b0ce10ab49c5940bc7818aa90f4e2af61831b9d5f2
4
- data.tar.gz: 3a5b9eea11ea0769d5dcfebd8721c3cf0d6925b470d636f895c37e8da82818a4
3
+ metadata.gz: 113cfc3490f5829915e8e46026b1c7de0672bb8dc5b388a91a1d0c773688aea5
4
+ data.tar.gz: 877b8c1672dd37169787dd04bdec610810eab8b27084d8bebf16e3a1b3de98f7
5
5
  SHA512:
6
- metadata.gz: 116b8c9a943c5785773f4286115cb01955e188bcc45e9583986db08cbbc7c945817280217df07956d2ca3bc739ad95a1120b7f1bf7a19655b19c1cccd49d290a
7
- data.tar.gz: aacd6b3e0dda79471150f6305dde49ec1efafdc05fae3c4e9da7ccaf1fa9dfb9c1d7554ac3154e74104b99807f2400f0da465f53da2dcd283870715609384e3f
6
+ metadata.gz: c6f636686bba507d3b88c83541ba2189637ddb6ef2074d635715d4a533fca4480c37b1131db83a9c6e32ad5e2e166316e7c2747b4aca23a9b2620910bedc0774
7
+ data.tar.gz: 5d32ecbb7ed802e7d153f4aef170b7df5eca8bc8b4d609a725e9853dc7a4d6eb183abeb9a0ffe1615c33d5272c7cb415b86bd621aaccd5a4ea22c892df3a12c6
data/CHANGELOG.md CHANGED
@@ -2,7 +2,23 @@
2
2
 
3
3
  ## master
4
4
 
5
- ## 1.1.0-dev
5
+ ## 1.1.2 (2021-09-10) 🤵👰
6
+
7
+ - Improved gRPC server args support. ([@palkan][])
8
+
9
+ Add ability to declare gRPC server args without namespacing (i.e., `"max_connection_age_ms"` instead of `"grpc.max_connection_age_ms"`). That makes it possible to use ENV vars to provide the gRPC configuration.
10
+
11
+ ## 1.1.1 (2021-06-05)
12
+
13
+ - Fixed error message when RPC implementation is missing. ([@palkan][])
14
+
15
+ We haven't extracted `anycable-grpc` yet.
16
+
17
+ ## 1.1.0 🚸 (2021-06-01)
18
+
19
+ - No changes since 1.1.0.rc1.
20
+
21
+ ## 1.1.0.rc1 (2021-05-12)
6
22
 
7
23
  - **BREAKING** Move middlewares from gRPC interceptors to custom implementation. ([@palkan][])
8
24
 
@@ -12,7 +28,7 @@ The API changed a bit:
12
28
  ```diff
13
29
  class SomeMiddleware < AnyCable::Middleware
14
30
  - def call(request, rpc_call, rpc_handler)
15
- + def call(rpc_method_name, request)
31
+ + def call(rpc_method_name, request, metadata)
16
32
  yield
17
33
  end
18
34
  end
data/README.md CHANGED
@@ -12,6 +12,8 @@ AnyCable allows you to use any WebSocket server (written in any language) as a r
12
12
 
13
13
  AnyCable uses the same protocol as ActionCable, so you can use its [JavaScript client](https://www.npmjs.com/package/actioncable) without any monkey-patching.
14
14
 
15
+ > [AnyCable Pro](https://docs.anycable.io/pro) has been launched 🚀
16
+
15
17
  <a href="https://evilmartians.com/">
16
18
  <img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Sponsored by Evil Martians" width="236" height="54"></a>
17
19
 
data/lib/anycable/cli.rb CHANGED
@@ -19,6 +19,14 @@ module AnyCable
19
19
  # Wait for external process termination (s)
20
20
  WAIT_PROCESS = 2
21
21
 
22
+ # Run CLI inside the current process and shutdown at exit
23
+ def self.embed!(args = [])
24
+ new(embedded: true).tap do |cli|
25
+ cli.run(args)
26
+ at_exit { cli.shutdown }
27
+ end
28
+ end
29
+
22
30
  attr_reader :server, :health_server, :embedded
23
31
  alias_method :embedded?, :embedded
24
32
 
@@ -55,6 +63,8 @@ module AnyCable
55
63
 
56
64
  verify_server_builder!
57
65
 
66
+ check_version!
67
+
58
68
  @server = AnyCable.server_builder.call(config)
59
69
 
60
70
  # Make sure middlewares are not adding after server has started
@@ -242,11 +252,19 @@ module AnyCable
242
252
  return if AnyCable.server_builder
243
253
 
244
254
  logger.error "AnyCable server builder must be configured. " \
245
- "Make sure you've required a gem (e.g. `anycable-grpc`) or " \
255
+ "Make sure you've required a gem (e.g. `grpc`) or " \
246
256
  "configured `AnyCable.server_builder` yourself"
247
257
  exit(1)
248
258
  end
249
259
 
260
+ def check_version!
261
+ return unless config.version_check_enabled?
262
+
263
+ AnyCable.middleware.use(
264
+ AnyCable::Middlewares::CheckVersion.new(AnyCable::PROTO_VERSION)
265
+ )
266
+ end
267
+
250
268
  def parse_gem_options!(args)
251
269
  config.parse_options!(args)
252
270
  rescue OptionParser::InvalidOption => e
@@ -8,7 +8,7 @@ AnyCable::Config.attr_config(
8
8
  rpc_max_waiting_requests: ::GRPC::RpcServer::DEFAULT_MAX_WAITING_REQUESTS,
9
9
  rpc_poll_period: ::GRPC::RpcServer::DEFAULT_POLL_PERIOD,
10
10
  rpc_pool_keep_alive: ::GRPC::Pool::DEFAULT_KEEP_ALIVE,
11
- # See https://github.com/grpc/grpc/blob/f526602bff029b8db50a8d57134d72da33d8a752/include/grpc/impl/codegen/grpc_types.h#L292-L315
11
+ # https://github.com/grpc/grpc/blob/f526602bff029b8db50a8d57134d72da33d8a752/include/grpc/impl/codegen/grpc_types.h#L141-L351
12
12
  rpc_server_args: {},
13
13
  log_grpc: false
14
14
  )
@@ -33,9 +33,19 @@ module AnyCable
33
33
  max_waiting_requests: rpc_max_waiting_requests,
34
34
  poll_period: rpc_poll_period,
35
35
  pool_keep_alive: rpc_pool_keep_alive,
36
- server_args: rpc_server_args
36
+ server_args: normalized_grpc_server_args
37
37
  }
38
38
  end
39
+
40
+ def normalized_grpc_server_args
41
+ val = rpc_server_args
42
+ return {} unless val.is_a?(Hash)
43
+
44
+ val.transform_keys do |key|
45
+ skey = key.to_s
46
+ skey.start_with?("grpc.") ? skey : "grpc.#{skey}"
47
+ end
48
+ end
39
49
  end
40
50
  end
41
51
  end
@@ -9,16 +9,16 @@ module AnyCable
9
9
  # RPC service handler
10
10
  class Handler < AnyCable::GRPC::Service
11
11
  # Handle connection request from WebSocket server
12
- def connect(request, _unused_call)
13
- AnyCable.rpc_handler.handle(:connect, request)
12
+ def connect(request, call)
13
+ AnyCable.rpc_handler.handle(:connect, request, call.metadata)
14
14
  end
15
15
 
16
- def disconnect(request, _unused_call)
17
- AnyCable.rpc_handler.handle(:disconnect, request)
16
+ def disconnect(request, call)
17
+ AnyCable.rpc_handler.handle(:disconnect, request, call.metadata)
18
18
  end
19
19
 
20
- def command(request, _unused_call)
21
- AnyCable.rpc_handler.handle(:command, request)
20
+ def command(request, call)
21
+ AnyCable.rpc_handler.handle(:command, request, call.metadata)
22
22
  end
23
23
  end
24
24
  end
data/lib/anycable/grpc.rb CHANGED
@@ -9,22 +9,14 @@ end
9
9
 
10
10
  require "anycable/grpc/config"
11
11
  require "anycable/grpc/server"
12
- require "anycable/grpc/check_version"
13
12
 
14
13
  AnyCable.server_builder = ->(config) {
15
14
  AnyCable.logger.info "gRPC version: #{::GRPC::VERSION}"
16
15
 
17
16
  ::GRPC.define_singleton_method(:logger) { AnyCable.logger } if config.log_grpc?
18
17
 
19
- interceptors = []
20
-
21
- if config.version_check_enabled?
22
- interceptors << AnyCable::GRPC::CheckVersion.new(AnyCable::PROTO_VERSION)
23
- end
24
-
25
18
  params = config.to_grpc_params
26
19
  params[:host] = config.rpc_host
27
- params[:interceptors] = interceptors
28
20
 
29
21
  AnyCable::GRPC::Server.new(**params)
30
22
  }
@@ -3,7 +3,7 @@
3
3
  module AnyCable
4
4
  # Middleware is an analague of Rack middlewares but for AnyCable RPC calls
5
5
  class Middleware
6
- def call(_method_name, _request)
6
+ def call(_method_name, _request, _meta)
7
7
  raise NotImplementedError
8
8
  end
9
9
  end
@@ -30,19 +30,19 @@ module AnyCable
30
30
  registry
31
31
  end
32
32
 
33
- def call(method_name, request, &block)
34
- return yield(method_name, request) if registry.none?
33
+ def call(method_name, request, meta = {}, &block)
34
+ return yield(method_name, request, meta) if registry.none?
35
35
 
36
- execute_next_middleware(0, method_name, request, block)
36
+ execute_next_middleware(0, method_name, request, meta, block)
37
37
  end
38
38
 
39
39
  private
40
40
 
41
- def execute_next_middleware(ind, method_name, request, block)
42
- return block.call(method_name, request) if ind >= registry.size
41
+ def execute_next_middleware(ind, method_name, request, meta, block)
42
+ return block.call(method_name, request, meta) if ind >= registry.size
43
43
 
44
- registry[ind].call(method_name, request) do
45
- execute_next_middleware(ind + 1, method_name, request, block)
44
+ registry[ind].call(method_name, request, meta) do
45
+ execute_next_middleware(ind + 1, method_name, request, meta, block)
46
46
  end
47
47
  end
48
48
 
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module AnyCable
4
+ module Middlewares
5
+ # Checks that RPC client version is compatible with
6
+ # the current RPC proto version
7
+ class CheckVersion < AnyCable::Middleware
8
+ attr_reader :version
9
+
10
+ def initialize(version)
11
+ @version = version
12
+ end
13
+
14
+ def call(_method, _request, meta)
15
+ check_version(meta) do
16
+ yield
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def check_version(metadata)
23
+ supported_versions = metadata["protov"]&.split(",")
24
+ return yield if supported_versions&.include?(version)
25
+
26
+ raise "Incompatible AnyCable RPC client.\nCurrent server version: #{version}.\n" \
27
+ "Client supported versions: #{metadata["protov"] || "unknown"}."
28
+ end
29
+ end
30
+ end
31
+ end
@@ -3,7 +3,7 @@
3
3
  module AnyCable
4
4
  module Middlewares
5
5
  class Exceptions < AnyCable::Middleware
6
- def call(method_name, request)
6
+ def call(method_name, request, _meta)
7
7
  yield
8
8
  rescue => exp
9
9
  notify_exception(exp, method_name, request)
@@ -16,8 +16,8 @@ module AnyCable
16
16
 
17
17
  private
18
18
 
19
- def notify_exception(exp, method_name, message)
20
- AnyCable::ExceptionsHandling.notify(exp, method_name.to_s, message.to_h)
19
+ def notify_exception(exp, method_name, request)
20
+ AnyCable::ExceptionsHandling.notify(exp, method_name.to_s, request.to_h)
21
21
  end
22
22
 
23
23
  def response_class(method_name)
@@ -17,8 +17,8 @@ module AnyCable
17
17
  @commands = {}
18
18
  end
19
19
 
20
- def handle(cmd, data)
21
- middleware.call(cmd, data) do
20
+ def handle(cmd, data, meta = {})
21
+ middleware.call(cmd, data, meta) do
22
22
  send(cmd, data)
23
23
  end
24
24
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AnyCable
4
- VERSION = "1.1.0.pre1"
4
+ VERSION = "1.1.2"
5
5
  end
data/lib/anycable.rb CHANGED
@@ -9,6 +9,7 @@ require "anycable/broadcast_adapters"
9
9
 
10
10
  require "anycable/middleware_chain"
11
11
  require "anycable/middlewares/exceptions"
12
+ require "anycable/middlewares/check_version"
12
13
 
13
14
  require "anycable/socket"
14
15
  require "anycable/rpc"
data/sig/anycable/cli.rbs CHANGED
@@ -8,6 +8,7 @@ module AnyCable
8
8
 
9
9
  alias embedded? embedded
10
10
 
11
+ def self.embed!: (Array[String]?) -> void
11
12
  def initialize: (?embedded: bool embedded) -> void
12
13
  def run: (?untyped args) -> void
13
14
  def shutdown: () -> void
@@ -1,5 +1,5 @@
1
1
  module AnyCable
2
2
  class Middleware
3
- def call: (Symbol, rpcRequest) { (Symbol, rpcRequest) -> rpcResponse } -> rpcResponse
3
+ def call: (Symbol, rpcRequest, rpcMetadata) { (Symbol, rpcRequest, rpcMetadata) -> rpcResponse } -> rpcResponse
4
4
  end
5
5
  end
@@ -1,16 +1,16 @@
1
1
  module AnyCable
2
2
  class MiddlewareChain
3
- type rpcHandlerBlock = ^(Symbol, rpcRequest) -> rpcResponse
3
+ type rpcHandlerBlock = ^(Symbol, rpcRequest, rpcMetadata) -> rpcResponse
4
4
 
5
5
  def initialize: () -> void
6
6
  def use: (singleton(Middleware) | Middleware middleware) -> void
7
7
  def freeze: () -> void
8
8
  def to_a: () -> Array[Middleware]
9
- def call: (Symbol, rpcRequest) { (Symbol, rpcRequest) -> rpcResponse } -> rpcResponse
9
+ def call: (Symbol, rpcRequest, ?rpcMetadata) { (Symbol, rpcRequest, rpcMetadata) -> rpcResponse } -> rpcResponse
10
10
 
11
11
  private
12
12
 
13
- def execute_next_middleware: (Integer ind, Symbol, rpcRequest, rpcHandlerBlock block) -> rpcResponse
13
+ def execute_next_middleware: (Integer ind, Symbol, rpcRequest, rpcMetadata, rpcHandlerBlock block) -> rpcResponse
14
14
 
15
15
  attr_reader mu: untyped
16
16
  attr_reader registry: Array[Middleware]
data/sig/anycable/rpc.rbs CHANGED
@@ -4,6 +4,7 @@ module AnyCable
4
4
 
5
5
  type rpcStatus = 0 | 1 | 2
6
6
  type protoMap = Hash[String, String]
7
+ type rpcMetadata = Hash[String, String]
7
8
 
8
9
  interface _WithEnvState
9
10
  def cstate: () -> protoMap?
@@ -60,6 +61,7 @@ module AnyCable
60
61
  include _WithEnv
61
62
 
62
63
  def initialize: (?env: Env) -> void
64
+ def to_h: () -> Hash[String, untyped]
63
65
  end
64
66
 
65
67
  class ConnectionResponse
@@ -78,6 +80,8 @@ module AnyCable
78
80
  ?error_msg: String,
79
81
  ?env: EnvResponse
80
82
  ) -> void
83
+
84
+ def to_h: () -> Hash[String, untyped]
81
85
  end
82
86
 
83
87
  class CommandMessage
@@ -94,6 +98,8 @@ module AnyCable
94
98
  ?connection_identifiers: String,
95
99
  ?env: Env
96
100
  ) -> void
101
+
102
+ def to_h: () -> Hash[String, untyped]
97
103
  end
98
104
 
99
105
  class CommandResponse
@@ -118,6 +124,8 @@ module AnyCable
118
124
  ?error_msg: String,
119
125
  ?env: EnvResponse
120
126
  ) -> void
127
+
128
+ def to_h: () -> Hash[String, untyped]
121
129
  end
122
130
 
123
131
  class DisconnectRequest
@@ -127,6 +135,7 @@ module AnyCable
127
135
  attr_accessor subscriptions: Array[String]
128
136
 
129
137
  def initialize: (identifiers: String, ?subscriptions: Array[String], ?env: Env) -> void
138
+ def to_h: () -> Hash[String, untyped]
130
139
  end
131
140
 
132
141
  class DisconnectResponse
@@ -136,6 +145,7 @@ module AnyCable
136
145
  attr_accessor error_msg: String?
137
146
 
138
147
  def initialize: (status: rpcStatus, ?error_msg: String) -> void
148
+ def to_h: () -> Hash[String, untyped]
139
149
  end
140
150
 
141
151
  type rpcRequest = ConnectionRequest | DisconnectRequest | CommandMessage
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.1.0.pre1
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - palkan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-04-28 00:00:00.000000000 Z
11
+ date: 2021-09-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: anyway_config
@@ -176,7 +176,6 @@ files:
176
176
  - lib/anycable/config.rb
177
177
  - lib/anycable/exceptions_handling.rb
178
178
  - lib/anycable/grpc.rb
179
- - lib/anycable/grpc/check_version.rb
180
179
  - lib/anycable/grpc/config.rb
181
180
  - lib/anycable/grpc/handler.rb
182
181
  - lib/anycable/grpc/rpc_services_pb.rb
@@ -184,6 +183,7 @@ files:
184
183
  - lib/anycable/health_server.rb
185
184
  - lib/anycable/middleware.rb
186
185
  - lib/anycable/middleware_chain.rb
186
+ - lib/anycable/middlewares/check_version.rb
187
187
  - lib/anycable/middlewares/exceptions.rb
188
188
  - lib/anycable/protos/rpc_pb.rb
189
189
  - lib/anycable/rpc.rb
@@ -215,6 +215,7 @@ metadata:
215
215
  documentation_uri: https://docs.anycable.io/
216
216
  homepage_uri: https://anycable.io/
217
217
  source_code_uri: http://github.com/anycable/anycable
218
+ funding_uri: https://github.com/sponsors/anycable
218
219
  post_install_message:
219
220
  rdoc_options: []
220
221
  require_paths:
@@ -226,9 +227,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
226
227
  version: 2.6.0
227
228
  required_rubygems_version: !ruby/object:Gem::Requirement
228
229
  requirements:
229
- - - ">"
230
+ - - ">="
230
231
  - !ruby/object:Gem::Version
231
- version: 1.3.1
232
+ version: '0'
232
233
  requirements: []
233
234
  rubygems_version: 3.2.15
234
235
  signing_key:
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module AnyCable
4
- module GRPC
5
- # Checks that gRPC client version is compatible with
6
- # the current RPC proto version
7
- class CheckVersion < ::GRPC::ServerInterceptor
8
- attr_reader :version
9
-
10
- def initialize(version)
11
- @version = version
12
- end
13
-
14
- def request_response(request: nil, call: nil, method: nil)
15
- # Call only for AnyCable service
16
- return yield unless method.receiver.is_a?(AnyCable::GRPC::Handler)
17
-
18
- check_version(call) do
19
- yield
20
- end
21
- end
22
-
23
- def check_version(call)
24
- supported_versions = call.metadata["protov"]&.split(",")
25
- return yield if supported_versions&.include?(version)
26
-
27
- raise ::GRPC::Internal,
28
- "Incompatible AnyCable RPC client.\nCurrent server version: #{version}.\n" \
29
- "Client supported versions: #{call.metadata["protov"] || "unknown"}."
30
- end
31
- end
32
- end
33
- end