protobuf 2.2.5-java
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.
- data/.gitignore +17 -0
- data/.travis.yml +9 -0
- data/.yardopts +5 -0
- data/Gemfile +3 -0
- data/README.md +316 -0
- data/Rakefile +29 -0
- data/UPGRADING.md +60 -0
- data/bin/rpc_server +5 -0
- data/bin/rprotoc +62 -0
- data/examples/addressbook.pb.rb +55 -0
- data/examples/addressbook.proto +24 -0
- data/examples/reading_a_message.rb +32 -0
- data/examples/writing_a_message.rb +46 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/code_generator.h +142 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/command_line_interface.h +318 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/cpp/cpp_enum.h +99 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/cpp/cpp_enum_field.h +103 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/cpp/cpp_extension.h +85 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/cpp/cpp_field.h +167 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/cpp/cpp_file.h +98 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/cpp/cpp_generator.h +72 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/cpp/cpp_helpers.h +159 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/cpp/cpp_message.h +170 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/cpp/cpp_message_field.h +102 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/cpp/cpp_primitive_field.h +103 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/cpp/cpp_service.h +118 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/cpp/cpp_string_field.h +104 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.h +2721 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/importer.h +303 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/java/java_enum.h +84 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/java/java_enum_field.h +121 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/java/java_extension.h +77 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/java/java_field.h +108 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/java/java_file.h +101 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/java/java_generator.h +72 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/java/java_helpers.h +213 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/java/java_message.h +109 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/java/java_message_field.h +134 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/java/java_primitive_field.h +121 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/java/java_service.h +113 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/java/java_string_field.h +120 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/mock_code_generator.h +113 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/package_info.h +64 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/parser.h +434 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/plugin.h +73 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/plugin.pb.h +790 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/python/python_generator.h +156 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/subprocess.h +108 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/compiler/zip_writer.h +93 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/descriptor.h +1367 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/descriptor.pb.h +5223 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/descriptor_database.h +366 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/dynamic_message.h +136 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/extension_set.h +904 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/generated_message_reflection.h +424 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/generated_message_util.h +82 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/io/coded_stream.h +1102 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/io/coded_stream_inl.h +64 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/io/gzip_stream.h +207 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/io/package_info.h +54 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/io/printer.h +136 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/io/tokenizer.h +313 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/io/zero_copy_stream.h +238 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/io/zero_copy_stream_impl.h +357 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/io/zero_copy_stream_impl_lite.h +340 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/message.h +692 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/message_lite.h +239 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/package_info.h +64 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/reflection_ops.h +80 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/repeated_field.h +1295 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/service.h +291 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/stubs/common.h +1211 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/stubs/hash.h +220 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/stubs/map-util.h +119 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/stubs/once.h +123 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/stubs/stl_util-inl.h +121 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/stubs/strutil.h +457 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/stubs/substitute.h +170 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/test_util.h +174 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/test_util_lite.h +101 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/testing/file.h +83 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/testing/googletest.h +98 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/text_format.h +285 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/unittest.pb.h +11915 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/unittest_custom_options.pb.h +2895 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/unittest_embed_optimize_for.pb.h +211 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/unittest_empty.pb.h +56 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/unittest_import.pb.h +188 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/unittest_import_lite.pb.h +151 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/unittest_lite.pb.h +4752 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/unittest_lite_imports_nonlite.pb.h +150 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/unittest_mset.pb.h +816 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/unittest_no_generic_services.pb.h +197 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/unittest_optimize_for.pb.h +403 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/unknown_field_set.h +268 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/wire_format.h +304 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/wire_format_lite.h +620 -0
- data/ext/protobuf-2.4.1/src/google/protobuf/wire_format_lite_inl.h +774 -0
- data/ext/ruby_generator/Makefile +10 -0
- data/ext/ruby_generator/RubyGenerator.cpp +450 -0
- data/ext/ruby_generator/RubyGenerator.h +199 -0
- data/ext/ruby_generator/extconf.rb +36 -0
- data/ext/ruby_generator/protoc-ruby +0 -0
- data/lib/protobuf/cli.rb +188 -0
- data/lib/protobuf/enum.rb +58 -0
- data/lib/protobuf/enum_value.rb +59 -0
- data/lib/protobuf/evented.rb +22 -0
- data/lib/protobuf/exceptions.rb +11 -0
- data/lib/protobuf/ext/eventmachine.rb +14 -0
- data/lib/protobuf/field/base_field.rb +240 -0
- data/lib/protobuf/field/bool_field.rb +36 -0
- data/lib/protobuf/field/bytes_field.rb +38 -0
- data/lib/protobuf/field/double_field.rb +19 -0
- data/lib/protobuf/field/enum_field.rb +50 -0
- data/lib/protobuf/field/extension_fields.rb +32 -0
- data/lib/protobuf/field/field_array.rb +65 -0
- data/lib/protobuf/field/fixed32_field.rb +19 -0
- data/lib/protobuf/field/fixed64_field.rb +22 -0
- data/lib/protobuf/field/float_field.rb +31 -0
- data/lib/protobuf/field/int32_field.rb +12 -0
- data/lib/protobuf/field/int64_field.rb +12 -0
- data/lib/protobuf/field/integer_field.rb +19 -0
- data/lib/protobuf/field/message_field.rb +53 -0
- data/lib/protobuf/field/sfixed32_field.rb +21 -0
- data/lib/protobuf/field/sfixed64_field.rb +24 -0
- data/lib/protobuf/field/signed_integer_field.rb +23 -0
- data/lib/protobuf/field/sint32_field.rb +12 -0
- data/lib/protobuf/field/sint64_field.rb +12 -0
- data/lib/protobuf/field/string_field.rb +14 -0
- data/lib/protobuf/field/uint32_field.rb +12 -0
- data/lib/protobuf/field/uint64_field.rb +12 -0
- data/lib/protobuf/field/varint_field.rb +61 -0
- data/lib/protobuf/field.rb +57 -0
- data/lib/protobuf/logger.rb +86 -0
- data/lib/protobuf/message/decoder.rb +83 -0
- data/lib/protobuf/message/encoder.rb +48 -0
- data/lib/protobuf/message/extend.rb +8 -0
- data/lib/protobuf/message/message.rb +1 -0
- data/lib/protobuf/message.rb +320 -0
- data/lib/protobuf/rpc/buffer.rb +79 -0
- data/lib/protobuf/rpc/client.rb +166 -0
- data/lib/protobuf/rpc/connector.rb +19 -0
- data/lib/protobuf/rpc/connectors/base.rb +38 -0
- data/lib/protobuf/rpc/connectors/common.rb +156 -0
- data/lib/protobuf/rpc/connectors/em_client.rb +84 -0
- data/lib/protobuf/rpc/connectors/eventmachine.rb +87 -0
- data/lib/protobuf/rpc/connectors/socket.rb +73 -0
- data/lib/protobuf/rpc/connectors/zmq.rb +69 -0
- data/lib/protobuf/rpc/error/client_error.rb +31 -0
- data/lib/protobuf/rpc/error/server_error.rb +43 -0
- data/lib/protobuf/rpc/error.rb +25 -0
- data/lib/protobuf/rpc/rpc.pb.rb +118 -0
- data/lib/protobuf/rpc/server.rb +89 -0
- data/lib/protobuf/rpc/servers/evented/server.rb +41 -0
- data/lib/protobuf/rpc/servers/evented_runner.rb +21 -0
- data/lib/protobuf/rpc/servers/socket/server.rb +111 -0
- data/lib/protobuf/rpc/servers/socket/worker.rb +66 -0
- data/lib/protobuf/rpc/servers/socket_runner.rb +27 -0
- data/lib/protobuf/rpc/servers/zmq/broker.rb +87 -0
- data/lib/protobuf/rpc/servers/zmq/server.rb +50 -0
- data/lib/protobuf/rpc/servers/zmq/util.rb +27 -0
- data/lib/protobuf/rpc/servers/zmq/worker.rb +60 -0
- data/lib/protobuf/rpc/servers/zmq_runner.rb +25 -0
- data/lib/protobuf/rpc/service.rb +173 -0
- data/lib/protobuf/rpc/service_dispatcher.rb +130 -0
- data/lib/protobuf/rpc/service_filters.rb +267 -0
- data/lib/protobuf/rpc/stat.rb +83 -0
- data/lib/protobuf/socket.rb +22 -0
- data/lib/protobuf/version.rb +4 -0
- data/lib/protobuf/wire_type.rb +10 -0
- data/lib/protobuf/zmq.rb +21 -0
- data/lib/protobuf.rb +86 -0
- data/proto/rpc.pb.rb +48 -0
- data/proto/rpc.proto +73 -0
- data/protobuf.gemspec +44 -0
- data/spec/benchmark/tasks.rb +179 -0
- data/spec/functional/embedded_service_spec.rb +7 -0
- data/spec/functional/evented_server_spec.rb +64 -0
- data/spec/functional/socket_server_spec.rb +58 -0
- data/spec/functional/zmq_server_spec.rb +58 -0
- data/spec/lib/protobuf/cli_spec.rb +212 -0
- data/spec/lib/protobuf/enum_spec.rb +98 -0
- data/spec/lib/protobuf/enum_value_spec.rb +15 -0
- data/spec/lib/protobuf/logger_spec.rb +131 -0
- data/spec/lib/protobuf/message/encoder_spec.rb +19 -0
- data/spec/lib/protobuf/message_spec.rb +209 -0
- data/spec/lib/protobuf/rpc/client_spec.rb +158 -0
- data/spec/lib/protobuf/rpc/connector_spec.rb +32 -0
- data/spec/lib/protobuf/rpc/connectors/base_spec.rb +50 -0
- data/spec/lib/protobuf/rpc/connectors/common_spec.rb +128 -0
- data/spec/lib/protobuf/rpc/connectors/socket_spec.rb +36 -0
- data/spec/lib/protobuf/rpc/connectors/zmq_spec.rb +22 -0
- data/spec/lib/protobuf/rpc/servers/evented_server_spec.rb +18 -0
- data/spec/lib/protobuf/rpc/servers/socket_server_spec.rb +43 -0
- data/spec/lib/protobuf/rpc/servers/zmq/broker_spec.rb +35 -0
- data/spec/lib/protobuf/rpc/servers/zmq/server_spec.rb +41 -0
- data/spec/lib/protobuf/rpc/servers/zmq/util_spec.rb +45 -0
- data/spec/lib/protobuf/rpc/servers/zmq/worker_spec.rb +44 -0
- data/spec/lib/protobuf/rpc/service_dispatcher_spec.rb +116 -0
- data/spec/lib/protobuf/rpc/service_filters_spec.rb +451 -0
- data/spec/lib/protobuf/rpc/service_spec.rb +165 -0
- data/spec/lib/protobuf_spec.rb +62 -0
- data/spec/spec_helper.rb +51 -0
- data/spec/support/all.rb +6 -0
- data/spec/support/server.rb +101 -0
- data/spec/support/test/enum.pb.rb +34 -0
- data/spec/support/test/enum.proto +12 -0
- data/spec/support/test/resource.pb.rb +58 -0
- data/spec/support/test/resource.proto +31 -0
- data/spec/support/test/resource_service.rb +14 -0
- data/spec/support/test_app_file.rb +2 -0
- data/spec/support/tolerance_matcher.rb +40 -0
- data/test/data/data.bin +3 -0
- data/test/data/data_source.py +14 -0
- data/test/data/types.bin +0 -0
- data/test/data/types_source.py +22 -0
- data/test/data/unk.png +0 -0
- data/test/proto/addressbook.pb.rb +66 -0
- data/test/proto/addressbook.proto +33 -0
- data/test/proto/addressbook_base.pb.rb +58 -0
- data/test/proto/addressbook_base.proto +26 -0
- data/test/proto/addressbook_ext.pb.rb +20 -0
- data/test/proto/addressbook_ext.proto +6 -0
- data/test/proto/collision.pb.rb +17 -0
- data/test/proto/collision.proto +5 -0
- data/test/proto/ext_collision.pb.rb +24 -0
- data/test/proto/ext_collision.proto +8 -0
- data/test/proto/ext_range.pb.rb +22 -0
- data/test/proto/ext_range.proto +7 -0
- data/test/proto/float_default.proto +10 -0
- data/test/proto/lowercase.pb.rb +30 -0
- data/test/proto/lowercase.proto +9 -0
- data/test/proto/merge.pb.rb +39 -0
- data/test/proto/merge.proto +15 -0
- data/test/proto/nested.pb.rb +30 -0
- data/test/proto/nested.proto +9 -0
- data/test/proto/optional_field.pb.rb +35 -0
- data/test/proto/optional_field.proto +12 -0
- data/test/proto/packed.pb.rb +22 -0
- data/test/proto/packed.proto +6 -0
- data/test/proto/rpc.proto +6 -0
- data/test/proto/types.pb.rb +84 -0
- data/test/proto/types.proto +37 -0
- data/test/test_addressbook.rb +56 -0
- data/test/test_enum_value.rb +41 -0
- data/test/test_extension.rb +36 -0
- data/test/test_lowercase.rb +11 -0
- data/test/test_message.rb +128 -0
- data/test/test_optional_field.rb +103 -0
- data/test/test_packed_field.rb +40 -0
- data/test/test_parse.rb +15 -0
- data/test/test_repeated_types.rb +132 -0
- data/test/test_serialize.rb +61 -0
- data/test/test_standard_message.rb +96 -0
- data/test/test_types.rb +226 -0
- metadata +461 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
module Protobuf
|
|
2
|
+
module Rpc
|
|
3
|
+
class Connector
|
|
4
|
+
|
|
5
|
+
# Returns a connector class for the pre-defined connector_type.
|
|
6
|
+
def self.connector_for_client
|
|
7
|
+
case ::Protobuf.connector_type
|
|
8
|
+
when :evented then
|
|
9
|
+
::Protobuf::Rpc::Connectors::EventMachine
|
|
10
|
+
when :zmq then
|
|
11
|
+
::Protobuf::Rpc::Connectors::Zmq
|
|
12
|
+
else
|
|
13
|
+
::Protobuf::Rpc::Connectors::Socket
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
require 'protobuf/logger'
|
|
2
|
+
require 'protobuf/rpc/rpc.pb'
|
|
3
|
+
require 'protobuf/rpc/buffer'
|
|
4
|
+
require 'protobuf/rpc/error'
|
|
5
|
+
require 'protobuf/rpc/stat'
|
|
6
|
+
require 'protobuf/rpc/connectors/common'
|
|
7
|
+
|
|
8
|
+
module Protobuf
|
|
9
|
+
module Rpc
|
|
10
|
+
module Connectors
|
|
11
|
+
DEFAULT_OPTIONS = {
|
|
12
|
+
:service => nil, # Service to invoke
|
|
13
|
+
:method => nil, # Service method to call
|
|
14
|
+
:host => '127.0.0.1', # A default host (usually overridden)
|
|
15
|
+
:port => '9399', # A default port (usually overridden)
|
|
16
|
+
:request => nil, # The request object sent by the client
|
|
17
|
+
:request_type => nil, # The request type expected by the client
|
|
18
|
+
:response_type => nil, # The response type expected by the client
|
|
19
|
+
:timeout => 30 # The default timeout for the request, also handled by client.rb
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
class Base
|
|
23
|
+
include Protobuf::Logger::LogMethods
|
|
24
|
+
|
|
25
|
+
attr_reader :options
|
|
26
|
+
attr_accessor :success_cb, :failure_cb, :complete_cb
|
|
27
|
+
|
|
28
|
+
def initialize(options)
|
|
29
|
+
@options = DEFAULT_OPTIONS.merge(options)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def send_request
|
|
33
|
+
raise 'If you inherit a Connector from Base you must implement send_request'
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
module Protobuf
|
|
2
|
+
module Rpc
|
|
3
|
+
module Connectors
|
|
4
|
+
module Common
|
|
5
|
+
|
|
6
|
+
attr_reader :error
|
|
7
|
+
|
|
8
|
+
def any_callbacks?
|
|
9
|
+
return [@complete_cb, @failure_cb, @success_cb].inject(false) do |reduction, cb|
|
|
10
|
+
reduction = (reduction || !cb.nil?)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def complete
|
|
15
|
+
@stats.stop
|
|
16
|
+
log_info { @stats.to_s }
|
|
17
|
+
log_debug { sign_message('Response proceessing complete') }
|
|
18
|
+
@complete_cb.call(self) unless @complete_cb.nil?
|
|
19
|
+
rescue => e
|
|
20
|
+
log_error { sign_message('Complete callback error encountered') }
|
|
21
|
+
log_exception(e)
|
|
22
|
+
raise
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def data_callback(data)
|
|
26
|
+
log_debug { sign_message('Using data_callback') }
|
|
27
|
+
@used_data_callback = true
|
|
28
|
+
@data = data
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# All failures should be routed through this method.
|
|
32
|
+
#
|
|
33
|
+
# @param [Symbol] code The code we're using (see ::Protobuf::Socketrpc::ErrorReason)
|
|
34
|
+
# @param [String] message The error message
|
|
35
|
+
def fail(code, message)
|
|
36
|
+
@error = ClientError.new
|
|
37
|
+
@error.code = code.is_a?(Symbol) ? Protobuf::Socketrpc::ErrorReason.values[code] : code
|
|
38
|
+
@error.message = message
|
|
39
|
+
log_debug { sign_message("Server failed request (invoking on_failure): #{@error.inspect}") }
|
|
40
|
+
|
|
41
|
+
@failure_cb.call(@error) unless @failure_cb.nil?
|
|
42
|
+
rescue => e
|
|
43
|
+
log_error { sign_message("Failure callback error encountered") }
|
|
44
|
+
log_exception(e)
|
|
45
|
+
raise
|
|
46
|
+
ensure
|
|
47
|
+
complete
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def initialize_stats
|
|
51
|
+
@stats = Protobuf::Rpc::Stat.new(:CLIENT)
|
|
52
|
+
@stats.server = [@options[:port], @options[:host]]
|
|
53
|
+
@stats.service = @options[:service].name
|
|
54
|
+
@stats.method_name = @options[:method].to_s
|
|
55
|
+
rescue => ex
|
|
56
|
+
log_exception(ex)
|
|
57
|
+
fail(:RPC_ERROR, "Invalid stats configuration. #{ex.message}")
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def log_signature
|
|
61
|
+
@_log_signature ||= "client-#{self.class}"
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def parse_response
|
|
65
|
+
# Close up the connection as we no longer need it
|
|
66
|
+
close_connection
|
|
67
|
+
|
|
68
|
+
log_debug { sign_message("Parsing response from server (connection closed)") }
|
|
69
|
+
|
|
70
|
+
# Parse out the raw response
|
|
71
|
+
response_wrapper = Protobuf::Socketrpc::Response.new
|
|
72
|
+
response_wrapper.parse_from_string(@response_data)
|
|
73
|
+
|
|
74
|
+
# Determine success or failure based on parsed data
|
|
75
|
+
if response_wrapper.has_field?(:error_reason)
|
|
76
|
+
log_debug { sign_message("Error response parsed") }
|
|
77
|
+
|
|
78
|
+
# fail the call if we already know the client is failed
|
|
79
|
+
# (don't try to parse out the response payload)
|
|
80
|
+
fail(response_wrapper.error_reason, response_wrapper.error)
|
|
81
|
+
else
|
|
82
|
+
log_debug { sign_message("Successful response parsed") }
|
|
83
|
+
|
|
84
|
+
# Ensure client_response is an instance
|
|
85
|
+
response_type = @options[:response_type].new
|
|
86
|
+
parsed = response_type.parse_from_string(response_wrapper.response_proto.to_s)
|
|
87
|
+
|
|
88
|
+
if parsed.nil? and not response_wrapper.has_field?(:error_reason)
|
|
89
|
+
fail(:BAD_RESPONSE_PROTO, 'Unable to parse response from server')
|
|
90
|
+
else
|
|
91
|
+
verify_callbacks
|
|
92
|
+
succeed(parsed)
|
|
93
|
+
return @data if @used_data_callback
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def post_init
|
|
99
|
+
send_data unless error?
|
|
100
|
+
rescue => e
|
|
101
|
+
fail(:RPC_ERROR, "Connection error: #{e.message}")
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def rpc_request_data
|
|
105
|
+
validate_request_type
|
|
106
|
+
|
|
107
|
+
return Protobuf::Socketrpc::Request.new(
|
|
108
|
+
:service_name => @options[:service].name,
|
|
109
|
+
:method_name => @options[:method].to_s,
|
|
110
|
+
:request_proto => @options[:request].serialize_to_string
|
|
111
|
+
).serialize_to_string
|
|
112
|
+
rescue => e
|
|
113
|
+
fail(:INVALID_REQUEST_PROTO, "Could not set request proto: #{e.message}")
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def setup_connection
|
|
117
|
+
initialize_stats
|
|
118
|
+
@request_data = rpc_request_data
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def succeed(response)
|
|
122
|
+
log_debug { sign_message("Server succeeded request (invoking on_success)") }
|
|
123
|
+
@success_cb.call(response) unless @success_cb.nil?
|
|
124
|
+
rescue => e
|
|
125
|
+
log_error { sign_message("Success callback error encountered") }
|
|
126
|
+
log_exception(e)
|
|
127
|
+
fail(:RPC_ERROR, "An exception occurred while calling on_success: #{e.message}")
|
|
128
|
+
ensure
|
|
129
|
+
complete
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def validate_request_type
|
|
133
|
+
unless @options[:request].class == @options[:request_type]
|
|
134
|
+
expected = @options[:request_type].name
|
|
135
|
+
actual = @options[:request].class.name
|
|
136
|
+
fail(:INVALID_REQUEST_PROTO, "Expected request type to be type of #{expected}, got #{actual} instead")
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def verify_callbacks
|
|
141
|
+
if !any_callbacks?
|
|
142
|
+
log_debug { sign_message("No callbacks set, using data_callback") }
|
|
143
|
+
@success_cb = @failure_cb = self.method(:data_callback)
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def verify_options
|
|
148
|
+
# Verify the options that are necessary and merge them in
|
|
149
|
+
[:service, :method, :host, :port].each do |opt|
|
|
150
|
+
fail(:RPC_ERROR, "Invalid client connection configuration. #{opt} must be a defined option.") if @options[opt].nil?
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Handles client connections to the server
|
|
2
|
+
module Protobuf
|
|
3
|
+
module Rpc
|
|
4
|
+
module Connectors
|
|
5
|
+
|
|
6
|
+
class EMClient < EM::Connection
|
|
7
|
+
include Protobuf::Logger::LogMethods
|
|
8
|
+
include Protobuf::Rpc::Connectors::Common
|
|
9
|
+
|
|
10
|
+
attr_reader :options, :request, :response
|
|
11
|
+
attr_reader :error, :error_reason, :error_message
|
|
12
|
+
|
|
13
|
+
##
|
|
14
|
+
# Constructor
|
|
15
|
+
#
|
|
16
|
+
def initialize(options = {}, &failure_cb)
|
|
17
|
+
@failure_cb = failure_cb
|
|
18
|
+
@options = DEFAULT_OPTIONS.merge(options)
|
|
19
|
+
@response_buffer = ::Protobuf::Rpc::Buffer.new(:read)
|
|
20
|
+
verify_options
|
|
21
|
+
|
|
22
|
+
log_debug { sign_message("Client Initialized: #{options.inspect}") }
|
|
23
|
+
rescue => e
|
|
24
|
+
fail(:RPC_ERROR, "Failed to initialize connection: #{e.message}")
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
##
|
|
28
|
+
# Class Methods
|
|
29
|
+
#
|
|
30
|
+
def self.connect(options = {})
|
|
31
|
+
options = DEFAULT_OPTIONS.merge(options)
|
|
32
|
+
log_debug { sign_message("Connecting to server: #{options.inspect}") }
|
|
33
|
+
EM.connect(options[:host], options[:port], self, options)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# turn post_init back into a no-op for event machine
|
|
37
|
+
def post_init
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
##
|
|
41
|
+
# Instance Methods
|
|
42
|
+
#
|
|
43
|
+
# Completion callback registration
|
|
44
|
+
def on_complete(&complete_cb)
|
|
45
|
+
@complete_cb = complete_cb
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Failure callback registration
|
|
49
|
+
def on_failure(&failure_cb)
|
|
50
|
+
@failure_cb = failure_cb
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Success callback registration
|
|
54
|
+
def on_success(&success_cb)
|
|
55
|
+
@success_cb = success_cb
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def receive_data(data)
|
|
59
|
+
log_debug { sign_message("receive_data: #{data}") }
|
|
60
|
+
@response_buffer << data
|
|
61
|
+
@response_data = @response_buffer.data
|
|
62
|
+
parse_response if !@response_data.nil? && @response_buffer.flushed?
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def send_data
|
|
66
|
+
request_buffer = ::Protobuf::Rpc::Buffer.new(:write)
|
|
67
|
+
request_buffer.set_data(@request_data)
|
|
68
|
+
log_debug { sign_message("sending data: #{request_buffer.inspect}") }
|
|
69
|
+
super(request_buffer.write)
|
|
70
|
+
rescue => e
|
|
71
|
+
fail(:RPC_ERROR, "Connection error: #{e.message}")
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# overwriting this method for java because it's broken in eventmachine. See https://github.com/eventmachine/eventmachine/issues/14
|
|
75
|
+
if RUBY_PLATFORM =~ /java/
|
|
76
|
+
def error?
|
|
77
|
+
!!@error
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
require 'protobuf/rpc/connectors/base'
|
|
2
|
+
require 'protobuf/rpc/connectors/em_client'
|
|
3
|
+
|
|
4
|
+
module Protobuf
|
|
5
|
+
module Rpc
|
|
6
|
+
module Connectors
|
|
7
|
+
class EventMachine < Base
|
|
8
|
+
|
|
9
|
+
def send_request
|
|
10
|
+
ensure_em_running do
|
|
11
|
+
f = Fiber.current
|
|
12
|
+
|
|
13
|
+
::EM.next_tick do
|
|
14
|
+
log_debug { sign_message('Scheduling EventMachine client request to be created on next tick') }
|
|
15
|
+
cnxn = EMClient.connect(options, &ensure_cb)
|
|
16
|
+
cnxn.on_success(&success_cb) if success_cb
|
|
17
|
+
cnxn.on_failure(&ensure_cb)
|
|
18
|
+
cnxn.on_complete { resume_fiber(f) }
|
|
19
|
+
cnxn.setup_connection
|
|
20
|
+
cnxn.send_data
|
|
21
|
+
log_debug { sign_message('Connection scheduled') }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
set_timeout_and_validate_fiber
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Returns a callable that ensures any errors will be returned to the client
|
|
29
|
+
#
|
|
30
|
+
# If a failure callback was set, just use that as a direct assignment
|
|
31
|
+
# otherwise implement one here that simply throws an exception, since we
|
|
32
|
+
# don't want to swallow the black holes.
|
|
33
|
+
#
|
|
34
|
+
def ensure_cb
|
|
35
|
+
@ensure_cb ||= (@failure_cb || lambda { |error| raise "#{error.code.name}: #{error.message}" })
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def log_signature
|
|
39
|
+
@_log_signature ||= "client-#{self.class}"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def ensure_em_running(&blk)
|
|
45
|
+
if ::EM.reactor_running?
|
|
46
|
+
@using_global_reactor = true
|
|
47
|
+
yield
|
|
48
|
+
else
|
|
49
|
+
@using_global_reactor = false
|
|
50
|
+
::EM.fiber_run do
|
|
51
|
+
blk.call
|
|
52
|
+
::EM.stop
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def resume_fiber(fib)
|
|
58
|
+
::EM::cancel_timer(@timeout_timer)
|
|
59
|
+
fib.resume(true)
|
|
60
|
+
rescue => ex
|
|
61
|
+
log_exception(ex)
|
|
62
|
+
message = "Synchronous client failed: #{ex.message}"
|
|
63
|
+
error_stop_reactor(message)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def set_timeout_and_validate_fiber
|
|
67
|
+
@timeout_timer = ::EM::add_timer(@options[:timeout]) do
|
|
68
|
+
message = "Client timeout of #{@options[:timeout]} seconds expired"
|
|
69
|
+
error_stop_reactor(message)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
Fiber.yield
|
|
73
|
+
rescue FiberError => ex
|
|
74
|
+
log_exception(ex)
|
|
75
|
+
message = "Synchronous calls must be in 'EM.fiber_run' block"
|
|
76
|
+
error_stop_reactor(message)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def error_stop_reactor(message)
|
|
80
|
+
err = Protobuf::Rpc::ClientError.new(Protobuf::Socketrpc::ErrorReason::RPC_ERROR, message)
|
|
81
|
+
ensure_cb.call(err)
|
|
82
|
+
::EM.stop unless @using_global_reactor
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
require 'protobuf/rpc/connectors/base'
|
|
2
|
+
|
|
3
|
+
module Protobuf
|
|
4
|
+
module Rpc
|
|
5
|
+
module Connectors
|
|
6
|
+
class Socket < Base
|
|
7
|
+
include Protobuf::Rpc::Connectors::Common
|
|
8
|
+
include Protobuf::Logger::LogMethods
|
|
9
|
+
|
|
10
|
+
def send_request
|
|
11
|
+
setup_connection
|
|
12
|
+
connect_to_rpc_server
|
|
13
|
+
post_init
|
|
14
|
+
read_response
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def log_signature
|
|
18
|
+
@_log_signature ||= "[client-#{self.class}]"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
|
|
23
|
+
def close_connection
|
|
24
|
+
@socket.close
|
|
25
|
+
log_debug { sign_message('Connector closed') }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def connect_to_rpc_server
|
|
29
|
+
@socket = TCPSocket.new(options[:host], options[:port])
|
|
30
|
+
log_debug { sign_message("Connection established #{options[:host]}:#{options[:port]}") }
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Method to determine error state, must be used with Connector api
|
|
34
|
+
def error?
|
|
35
|
+
return true if @error
|
|
36
|
+
log_debug { sign_message("Error state : #{@socket.closed?}") }
|
|
37
|
+
@socket.closed?
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def read_data
|
|
41
|
+
size_io = StringIO.new
|
|
42
|
+
|
|
43
|
+
until (size_reader = @socket.getc) == "-"
|
|
44
|
+
size_io << size_reader
|
|
45
|
+
end
|
|
46
|
+
str_size_io = size_io.string
|
|
47
|
+
|
|
48
|
+
"#{str_size_io}-#{@socket.read(str_size_io.to_i)}"
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def read_response
|
|
52
|
+
log_debug { sign_message("error? is #{error?}") }
|
|
53
|
+
return if error?
|
|
54
|
+
response_buffer = ::Protobuf::Rpc::Buffer.new(:read)
|
|
55
|
+
response_buffer << read_data
|
|
56
|
+
@stats.response_size = response_buffer.size
|
|
57
|
+
@response_data = response_buffer.data
|
|
58
|
+
parse_response if response_buffer.flushed?
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def send_data
|
|
62
|
+
return if error?
|
|
63
|
+
request_buffer = ::Protobuf::Rpc::Buffer.new(:write)
|
|
64
|
+
request_buffer.set_data(@request_data)
|
|
65
|
+
@socket.write(request_buffer.write)
|
|
66
|
+
@socket.flush
|
|
67
|
+
log_debug { sign_message("write closed") }
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
require 'protobuf/rpc/connectors/base'
|
|
2
|
+
|
|
3
|
+
module Protobuf
|
|
4
|
+
module Rpc
|
|
5
|
+
module Connectors
|
|
6
|
+
class Zmq < Base
|
|
7
|
+
include Protobuf::Rpc::Connectors::Common
|
|
8
|
+
include Protobuf::Logger::LogMethods
|
|
9
|
+
|
|
10
|
+
def send_request
|
|
11
|
+
setup_connection
|
|
12
|
+
connect_to_rpc_server
|
|
13
|
+
post_init
|
|
14
|
+
read_response
|
|
15
|
+
ensure
|
|
16
|
+
@socket.close if @socket
|
|
17
|
+
@zmq_context.terminate if @zmq_context
|
|
18
|
+
@zmq_context = nil
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def log_signature
|
|
22
|
+
@_log_signature ||= "[client-#{self.class}]"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private
|
|
26
|
+
|
|
27
|
+
def close_connection
|
|
28
|
+
return if @error
|
|
29
|
+
zmq_error_check(@socket.close)
|
|
30
|
+
zmq_error_check(@zmq_context.terminate)
|
|
31
|
+
log_debug { sign_message("Connector closed") }
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def connect_to_rpc_server
|
|
35
|
+
return if @error
|
|
36
|
+
log_debug { sign_message("Establishing connection: #{options[:host]}:#{options[:port]}") }
|
|
37
|
+
@zmq_context = ::ZMQ::Context.new
|
|
38
|
+
@socket = @zmq_context.socket(::ZMQ::REQ)
|
|
39
|
+
zmq_error_check(@socket.connect("tcp://#{options[:host]}:#{options[:port]}"))
|
|
40
|
+
log_debug { sign_message("Connection established #{options[:host]}:#{options[:port]}") }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Method to determine error state, must be used with Connector api
|
|
44
|
+
def error?
|
|
45
|
+
!!@error
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def read_response
|
|
49
|
+
return if @error
|
|
50
|
+
@response_data = ''
|
|
51
|
+
zmq_error_check(@socket.recv_string(@response_data))
|
|
52
|
+
parse_response
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def send_data
|
|
56
|
+
return if @error
|
|
57
|
+
log_debug { sign_message("Sending Request: #{@request_data}") }
|
|
58
|
+
@stats.request_size = @request_data.size
|
|
59
|
+
zmq_error_check(@socket.send_string(@request_data))
|
|
60
|
+
log_debug { sign_message("write closed") }
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def zmq_error_check(return_code)
|
|
64
|
+
raise "Last API call failed at #{caller(1)}" unless return_code >= 0
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
require 'protobuf/rpc/error'
|
|
2
|
+
|
|
3
|
+
module Protobuf
|
|
4
|
+
module Rpc
|
|
5
|
+
|
|
6
|
+
class InvalidRequestProto < PbError
|
|
7
|
+
def initialize(message='Invalid request type given')
|
|
8
|
+
super message, 'INVALID_REQUEST_PROTO'
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class BadResponseProto < PbError
|
|
13
|
+
def initialize(message='Bad response type from server')
|
|
14
|
+
super message, 'BAD_RESPONSE_PROTO'
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class UnkownHost < PbError
|
|
19
|
+
def initialize(message='Unknown host or port')
|
|
20
|
+
super message, 'UNKNOWN_HOST'
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class IOError < PbError
|
|
25
|
+
def initialize(message='IO Error occurred')
|
|
26
|
+
super message, 'IO_ERROR'
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
require 'protobuf/rpc/rpc.pb'
|
|
2
|
+
|
|
3
|
+
module Protobuf
|
|
4
|
+
module Rpc
|
|
5
|
+
|
|
6
|
+
class BadRequestData < PbError
|
|
7
|
+
def initialize message='Unable to parse request'
|
|
8
|
+
super message, 'BAD_REQUEST_DATA'
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
class BadRequestProto < PbError
|
|
13
|
+
def initialize message='Request is of wrong type'
|
|
14
|
+
super message, 'BAD_REQUEST_PROTO'
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class ServiceNotFound < PbError
|
|
19
|
+
def initialize message='Service class not found'
|
|
20
|
+
super message, 'SERVICE_NOT_FOUND'
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
class MethodNotFound < PbError
|
|
25
|
+
def initialize message='Service method not found'
|
|
26
|
+
super message, 'METHOD_NOT_FOUND'
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
class RpcError < PbError
|
|
31
|
+
def initialize message='RPC exception occurred'
|
|
32
|
+
super message, 'RPC_ERROR'
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
class RpcFailed < PbError
|
|
37
|
+
def initialize message='RPC failed'
|
|
38
|
+
super message, 'RPC_FAILED'
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
end
|
|
43
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
require 'protobuf/rpc/rpc.pb'
|
|
2
|
+
|
|
3
|
+
module Protobuf
|
|
4
|
+
module Rpc
|
|
5
|
+
ClientError = Struct.new("ClientError", :code, :message)
|
|
6
|
+
|
|
7
|
+
# Base PbError class for client and server errors
|
|
8
|
+
class PbError < StandardError
|
|
9
|
+
attr_reader :error_type
|
|
10
|
+
|
|
11
|
+
def initialize message='An unknown RpcError occurred', error_type='RPC_ERROR'
|
|
12
|
+
@error_type = error_type.is_a?(String) ? ::Protobuf::Socketrpc::ErrorReason.const_get(error_type) : error_type
|
|
13
|
+
super message
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def to_response response
|
|
17
|
+
response.error = message
|
|
18
|
+
response.error_reason = @error_type
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
require 'protobuf/rpc/error/server_error'
|
|
25
|
+
require 'protobuf/rpc/error/client_error'
|