grpc_reflection 0.4.0 → 0.5.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3b17804fde58e327e1e11735e929252ea6b0d39b27f0c6422ee5641c37f251fb
4
- data.tar.gz: 845fc82d9ed3149fb45c31ef8307a5da43240e14b7615e43d00748f5ba1ac008
3
+ metadata.gz: '083f05c2730db17b2d790b16084a54c3b3e165607265747e564adc26b72d71b3'
4
+ data.tar.gz: 4d9033ce323235fc76ffbd6bb0bc43ba218fb166479e0a4347b12eec2604ccba
5
5
  SHA512:
6
- metadata.gz: e91d01d52dad1cfccbcdf331ea1996d90ee546e3f92ad1dd44863c89c4aca742565d6d67b5ff7a71d93d9d48cc5346cdf258c841b49e8f54feb8e13092b262bd
7
- data.tar.gz: 96d03f3dec08b28b217111bb6f1017f7423d69eb9fc9785551ee16f953cfa8c589df797b3fbcf7f7aa276b63917c5ea5a537943b4de780d7ce6e8b0bfcd815f2
6
+ metadata.gz: 957c82b81d874bed400ccd707580b41c266d80f9a240fe7f81d21067e285ed5d508c24a362f274697168c0002aaa302669ea1c3341465018bb163980fd164f51
7
+ data.tar.gz: 5a6a5a469ea8829baf149b97888a8eb68e58bc1e229553a186cd6308256e54cf2db3511934114a02fbee92e91e5ef342c721c71360236046f8f65270debb9e2c
data/CHANGELOG.md CHANGED
@@ -1,3 +1,12 @@
1
+ ## 0.5.0
2
+
3
+ * Support multiple requests #24
4
+ * Find the RpcServer actually hosting the reflection service- #23
5
+ * Return error_response for not-found and invalid reflection requests #21
6
+ * Fix file_containing_extension to look up by extendee type, not extension name #20
7
+ * Fix symbol resolution for services/methods defined without a package #19
8
+ * Fix symbol lookup cache for non-dataset symbols #18
9
+
1
10
  ## 0.4.0
2
11
 
3
12
  * Support `file_containing_extension` request #14
@@ -6,7 +6,7 @@ require "google/protobuf/descriptor_pb"
6
6
 
7
7
  module GrpcReflection
8
8
  class FileDescriptorDecorator
9
- attr_reader :dataset, :serialized_file, :filename, :dependency
9
+ attr_reader :dataset, :serialized_file, :filename, :dependency, :file_descriptor_proto
10
10
 
11
11
  def initialize(file_descriptor_proto)
12
12
  @file_descriptor_proto = file_descriptor_proto
@@ -24,17 +24,23 @@ module GrpcReflection
24
24
  def set_dataset
25
25
  @file_descriptor_proto.service.each do |s|
26
26
  converted_service = JSON.parse(s.to_json)
27
- @dataset.add(@file_descriptor_proto.package + "." + converted_service["name"])
27
+ @dataset.add(qualified_name(converted_service["name"]))
28
28
  converted_service["method"].each do |m|
29
- @dataset.add(@file_descriptor_proto.package + "." + converted_service["name"] + "." + m["name"])
29
+ @dataset.add(qualified_name(converted_service["name"] + "." + m["name"]))
30
30
  @dataset.add(m["inputType"][1..])
31
31
  @dataset.add(m["outputType"][1..])
32
32
  end
33
33
  end
34
34
 
35
35
  @file_descriptor_proto.extension.each do |s|
36
- @dataset.add(@file_descriptor_proto.package + "." + s.name)
36
+ @dataset.add(qualified_name(s.name))
37
37
  end
38
38
  end
39
+
40
+ def qualified_name(name)
41
+ return name if @file_descriptor_proto.package.empty?
42
+
43
+ @file_descriptor_proto.package + "." + name
44
+ end
39
45
  end
40
46
  end
@@ -2,25 +2,37 @@
2
2
 
3
3
  module GrpcReflection
4
4
  module FileDescriptorManager
5
- @@file_descriptor_decorators = []
5
+ @@file_descriptor_decorators = {}
6
6
 
7
7
  class << self
8
8
  def add(file_descriptor_proto)
9
- decorator = GrpcReflection::FileDescriptorDecorator.new(file_descriptor_proto)
10
- @@file_descriptor_decorators << decorator
11
- decorator
9
+ filename = file_descriptor_proto.name
10
+ @@file_descriptor_decorators[filename] ||= GrpcReflection::FileDescriptorDecorator.new(file_descriptor_proto)
12
11
  end
13
12
 
14
13
  def find(name)
15
14
  file_descriptor = find_file_descriptor(name)
16
15
  return [] if file_descriptor.nil?
17
16
 
17
+ collect_with_dependencies(file_descriptor)
18
+ end
19
+
20
+ def find_extension(containing_type, extension_number, service_names = [])
21
+ file_descriptor = find_extension_file_descriptor(containing_type, extension_number, service_names)
22
+ return [] if file_descriptor.nil?
23
+
24
+ collect_with_dependencies(file_descriptor)
25
+ end
26
+
27
+ private
28
+
29
+ def collect_with_dependencies(file_descriptor)
18
30
  result = {}
19
31
  result[file_descriptor.filename] = file_descriptor.serialized_file
20
32
  dependencies = file_descriptor.dependency.dup
21
33
  until dependencies.empty?
22
34
  dependency = dependencies.shift
23
- decorated_file_descriptor = @@file_descriptor_decorators.detect { |f| f.filename == dependency }
35
+ decorated_file_descriptor = @@file_descriptor_decorators[dependency]
24
36
  if decorated_file_descriptor.nil? && proto = Google::Protobuf::DescriptorPool.generated_pool.lookup(dependency)&.to_proto
25
37
  decorated_file_descriptor = add(proto)
26
38
  end
@@ -34,26 +46,82 @@ module GrpcReflection
34
46
  result.values
35
47
  end
36
48
 
37
- private
49
+ def find_extension_file_descriptor(containing_type, extension_number, service_names)
50
+ candidate_file_descriptor_protos(service_names).each_value do |file_descriptor_proto|
51
+ next unless extension_field_matches?(file_descriptor_proto, containing_type, extension_number)
52
+
53
+ return add(file_descriptor_proto)
54
+ end
55
+
56
+ nil
57
+ end
58
+
59
+ def candidate_file_descriptor_protos(service_names)
60
+ candidates = {}
61
+
62
+ @@file_descriptor_decorators.each_value do |decorated_file_descriptor|
63
+ candidates[decorated_file_descriptor.filename] = decorated_file_descriptor.file_descriptor_proto
64
+ end
65
+
66
+ pending = service_names.filter_map do |service_name|
67
+ descriptor = Google::Protobuf::DescriptorPool.generated_pool.lookup(service_name)
68
+ descriptor&.file_descriptor&.to_proto if descriptor.respond_to?(:file_descriptor)
69
+ end
70
+
71
+ until pending.empty?
72
+ file_descriptor_proto = pending.shift
73
+ next if file_descriptor_proto.nil? || candidates.key?(file_descriptor_proto.name)
74
+
75
+ candidates[file_descriptor_proto.name] = file_descriptor_proto
76
+ file_descriptor_proto.dependency.each do |dependency|
77
+ next if candidates.key?(dependency)
78
+
79
+ dependency_proto = Google::Protobuf::DescriptorPool.generated_pool.lookup(dependency)&.to_proto
80
+ pending << dependency_proto unless dependency_proto.nil?
81
+ end
82
+ end
83
+
84
+ candidates
85
+ end
86
+
87
+ def extension_field_matches?(file_descriptor_proto, containing_type, extension_number)
88
+ each_extension_field(file_descriptor_proto).any? do |field|
89
+ field.extendee == ".#{containing_type}" && field.number == extension_number
90
+ end
91
+ end
92
+
93
+ def each_extension_field(file_descriptor_proto, &block)
94
+ return enum_for(:each_extension_field, file_descriptor_proto) unless block_given?
95
+
96
+ file_descriptor_proto.extension.each(&block)
97
+ file_descriptor_proto.message_type.each { |message_type| each_message_extension_field(message_type, &block) }
98
+ end
99
+
100
+ def each_message_extension_field(message_type, &block)
101
+ message_type.extension.each(&block)
102
+ message_type.nested_type.each { |nested_type| each_message_extension_field(nested_type, &block) }
103
+ end
38
104
 
39
105
  def find_file_descriptor(name)
40
- file_descriptor = @@file_descriptor_decorators.detect { |f| f.dataset.include?(name) }
106
+ file_descriptor = @@file_descriptor_decorators.values.detect { |f| f.dataset.include?(name) }
41
107
  return file_descriptor if file_descriptor
42
108
 
43
109
  search_name = name
44
110
  file_descriptor_proto = nil
45
- while pos = search_name.rindex(".")
111
+ loop do
46
112
  descriptor = Google::Protobuf::DescriptorPool.generated_pool.lookup(search_name)
47
- search_name = search_name.slice(0..(pos - 1))
48
- next if descriptor.nil? || !descriptor.respond_to?(:file_descriptor)
49
- file_descriptor_proto = descriptor.file_descriptor&.to_proto
50
- break unless file_descriptor_proto.nil?
113
+ pos = search_name.rindex(".")
114
+ search_name = pos ? search_name.slice(0..(pos - 1)) : nil
115
+ unless descriptor.nil? || !descriptor.respond_to?(:file_descriptor)
116
+ file_descriptor_proto = descriptor.file_descriptor&.to_proto
117
+ break unless file_descriptor_proto.nil?
118
+ end
119
+ break if search_name.nil?
51
120
  end
52
121
 
53
122
  return nil if file_descriptor_proto.nil?
54
123
 
55
124
  add(file_descriptor_proto)
56
- @@file_descriptor_decorators.detect { |f| f.dataset.include?(name) }
57
125
  end
58
126
  end
59
127
  end
@@ -1,39 +1,57 @@
1
1
  module GrpcReflection
2
2
  module ServerShared
3
3
  def server_reflection_info_response(req, proto_module)
4
- # TODO: support streaming call
5
- request = req.first
4
+ req.lazy.map { |request| build_response(request, proto_module) }
5
+ end
6
+
7
+ private
6
8
 
7
- res = proto_module::ServerReflectionResponse.new
8
- if request.list_services.size != 0
9
+ def build_response(request, proto_module)
10
+ res = proto_module::ServerReflectionResponse.new(original_request: request, valid_host: request.host)
11
+ case request.message_request
12
+ when :list_services
9
13
  res.list_services_response = proto_module::ListServiceResponse.new(service: list_services_response(proto_module))
10
- elsif !request.file_containing_symbol.empty?
14
+ when :file_containing_symbol
11
15
  result = GrpcReflection::FileDescriptorManager.find(request.file_containing_symbol)
12
- res.file_descriptor_response = proto_module::FileDescriptorResponse.new(file_descriptor_proto: result)
13
- elsif !request.file_by_filename.empty?
14
- proto = Google::Protobuf::DescriptorPool.generated_pool.lookup(request.file_by_filename)&.to_proto
15
- res.file_descriptor_response = proto_module::FileDescriptorResponse.new(file_descriptor_proto: [Google::Protobuf::FileDescriptorProto.encode(proto)])
16
- elsif !request.file_containing_extension.nil? && !request.file_containing_extension.containing_type.empty?
17
- descriptor = Google::Protobuf::DescriptorPool.generated_pool.lookup(request.file_containing_extension.containing_type)
18
- if descriptor.is_a?(Google::Protobuf::FieldDescriptor) && descriptor.number == request.file_containing_extension.extension_number
19
- result = GrpcReflection::FileDescriptorManager.find(request.file_containing_extension.containing_type)
16
+ if result.empty?
17
+ res.error_response = error_response(proto_module, GRPC::Core::StatusCodes::NOT_FOUND, "symbol not found: #{request.file_containing_symbol}")
18
+ else
20
19
  res.file_descriptor_response = proto_module::FileDescriptorResponse.new(file_descriptor_proto: result)
20
+ end
21
+ when :file_by_filename
22
+ descriptor = Google::Protobuf::DescriptorPool.generated_pool.lookup(request.file_by_filename)
23
+ if !descriptor.is_a?(Google::Protobuf::FileDescriptor)
24
+ res.error_response = error_response(proto_module, GRPC::Core::StatusCodes::NOT_FOUND, "file not found: #{request.file_by_filename}")
21
25
  else
22
- res.file_descriptor_response = proto_module::FileDescriptorResponse.new(file_descriptor_proto: [])
26
+ res.file_descriptor_response = proto_module::FileDescriptorResponse.new(file_descriptor_proto: [Google::Protobuf::FileDescriptorProto.encode(descriptor.to_proto)])
23
27
  end
24
- elsif !request.all_extension_numbers_of_type.empty?
25
- res.error_response = proto_module::ErrorResponse.new(
26
- error_code: GRPC::Core::StatusCodes::UNIMPLEMENTED,
27
- error_message: "all_extension_numbers_of_type is not implemented"
28
+ when :file_containing_extension
29
+ result = GrpcReflection::FileDescriptorManager.find_extension(
30
+ request.file_containing_extension.containing_type,
31
+ request.file_containing_extension.extension_number,
32
+ service_names
28
33
  )
34
+ if result.empty?
35
+ res.error_response = error_response(proto_module, GRPC::Core::StatusCodes::NOT_FOUND, "extension not found: #{request.file_containing_extension.containing_type} #{request.file_containing_extension.extension_number}")
36
+ else
37
+ res.file_descriptor_response = proto_module::FileDescriptorResponse.new(file_descriptor_proto: result)
38
+ end
39
+ when :all_extension_numbers_of_type
40
+ res.error_response = error_response(proto_module, GRPC::Core::StatusCodes::UNIMPLEMENTED, "all_extension_numbers_of_type is not implemented")
41
+ else
42
+ res.error_response = error_response(proto_module, GRPC::Core::StatusCodes::INVALID_ARGUMENT, "invalid MessageRequest")
29
43
  end
30
- [res].enum_for(:each)
44
+ res
31
45
  end
32
46
 
33
- private
47
+ def error_response(proto_module, error_code, error_message)
48
+ proto_module::ErrorResponse.new(error_code: error_code, error_message: error_message)
49
+ end
34
50
 
35
51
  def main_server
36
- @main_server ||= ObjectSpace.each_object(GRPC::RpcServer).to_a[0]
52
+ @main_server ||= ObjectSpace.each_object(GRPC::RpcServer).find do |server|
53
+ server.send(:rpc_handlers).values.any? { |handler| handler.receiver.equal?(self) }
54
+ end
37
55
  end
38
56
 
39
57
  def service_names
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module GrpcReflection
4
- VERSION = "0.4.0"
4
+ VERSION = "0.5.0"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: grpc_reflection
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.0
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yuji Yaginuma