protobuffy 3.6.0 → 4.0.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 +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +67 -0
- data/.rubocop_todo.yml +145 -0
- data/.travis.yml +25 -5
- data/CHANGES.md +55 -0
- data/CONTRIBUTING.md +1 -1
- data/LICENSE.txt +17 -9
- data/README.md +13 -12
- data/Rakefile +15 -11
- data/bin/protoc-gen-ruby +8 -3
- data/bin/rpc_server +1 -0
- data/examples/lib/example/reverse-client.rb +2 -2
- data/install-protobuf.sh +28 -0
- data/lib/protobuf.rb +57 -53
- data/lib/protobuf/cli.rb +94 -74
- data/lib/protobuf/code_generator.rb +60 -9
- data/lib/protobuf/decoder.rb +19 -65
- data/lib/protobuf/deprecation.rb +117 -0
- data/lib/protobuf/descriptors/google/protobuf/compiler/plugin.pb.rb +11 -1
- data/lib/protobuf/descriptors/google/protobuf/descriptor.pb.rb +55 -3
- data/lib/protobuf/encoder.rb +13 -53
- data/lib/protobuf/enum.rb +58 -63
- data/lib/protobuf/field.rb +4 -4
- data/lib/protobuf/field/base_field.rb +101 -173
- data/lib/protobuf/field/bool_field.rb +17 -11
- data/lib/protobuf/field/bytes_field.rb +21 -35
- data/lib/protobuf/field/double_field.rb +0 -1
- data/lib/protobuf/field/enum_field.rb +23 -22
- data/lib/protobuf/field/field_array.rb +5 -4
- data/lib/protobuf/field/fixed32_field.rb +1 -1
- data/lib/protobuf/field/fixed64_field.rb +0 -1
- data/lib/protobuf/field/float_field.rb +4 -1
- data/lib/protobuf/field/int32_field.rb +0 -1
- data/lib/protobuf/field/int64_field.rb +0 -1
- data/lib/protobuf/field/integer_field.rb +0 -1
- data/lib/protobuf/field/message_field.rb +13 -28
- data/lib/protobuf/field/sfixed32_field.rb +0 -1
- data/lib/protobuf/field/sfixed64_field.rb +0 -1
- data/lib/protobuf/field/signed_integer_field.rb +0 -1
- data/lib/protobuf/field/sint32_field.rb +0 -1
- data/lib/protobuf/field/sint64_field.rb +0 -1
- data/lib/protobuf/field/string_field.rb +2 -4
- data/lib/protobuf/field/uint32_field.rb +0 -1
- data/lib/protobuf/field/uint64_field.rb +0 -1
- data/lib/protobuf/field/varint_field.rb +30 -13
- data/lib/protobuf/generators/base.rb +30 -16
- data/lib/protobuf/generators/enum_generator.rb +6 -9
- data/lib/protobuf/generators/extension_generator.rb +1 -2
- data/lib/protobuf/generators/field_generator.rb +25 -13
- data/lib/protobuf/generators/file_generator.rb +157 -35
- data/lib/protobuf/generators/group_generator.rb +22 -17
- data/lib/protobuf/generators/message_generator.rb +13 -14
- data/lib/protobuf/generators/option_generator.rb +17 -0
- data/lib/protobuf/generators/printable.rb +12 -13
- data/lib/protobuf/generators/service_generator.rb +2 -3
- data/lib/protobuf/http.rb +2 -2
- data/lib/protobuf/lifecycle.rb +20 -33
- data/lib/protobuf/logging.rb +39 -0
- data/lib/protobuf/message.rb +114 -47
- data/lib/protobuf/message/fields.rb +170 -88
- data/lib/protobuf/message/serialization.rb +19 -18
- data/lib/protobuf/optionable.rb +53 -6
- data/lib/protobuf/rpc/buffer.rb +18 -19
- data/lib/protobuf/rpc/client.rb +22 -50
- data/lib/protobuf/rpc/connectors/base.rb +177 -12
- data/lib/protobuf/rpc/connectors/http.rb +14 -9
- data/lib/protobuf/rpc/connectors/ping.rb +89 -0
- data/lib/protobuf/rpc/connectors/socket.rb +13 -8
- data/lib/protobuf/rpc/connectors/zmq.rb +178 -73
- data/lib/protobuf/rpc/dynamic_discovery.pb.rb +4 -1
- data/lib/protobuf/rpc/env.rb +12 -12
- data/lib/protobuf/rpc/error.rb +3 -3
- data/lib/protobuf/rpc/error/client_error.rb +4 -4
- data/lib/protobuf/rpc/error/server_error.rb +9 -9
- data/lib/protobuf/rpc/middleware/exception_handler.rb +6 -2
- data/lib/protobuf/rpc/middleware/logger.rb +8 -4
- data/lib/protobuf/rpc/middleware/request_decoder.rb +17 -21
- data/lib/protobuf/rpc/middleware/response_encoder.rb +22 -27
- data/lib/protobuf/rpc/middleware/statsd.rb +3 -3
- data/lib/protobuf/rpc/rpc.pb.rb +4 -1
- data/lib/protobuf/rpc/server.rb +1 -1
- data/lib/protobuf/rpc/servers/http/server.rb +19 -17
- data/lib/protobuf/rpc/servers/socket/server.rb +78 -70
- data/lib/protobuf/rpc/servers/socket/worker.rb +4 -4
- data/lib/protobuf/rpc/servers/socket_runner.rb +27 -15
- data/lib/protobuf/rpc/servers/zmq/broker.rb +70 -31
- data/lib/protobuf/rpc/servers/zmq/server.rb +55 -47
- data/lib/protobuf/rpc/servers/zmq/util.rb +14 -13
- data/lib/protobuf/rpc/servers/zmq/worker.rb +16 -16
- data/lib/protobuf/rpc/servers/zmq_runner.rb +26 -7
- data/lib/protobuf/rpc/service.rb +21 -27
- data/lib/protobuf/rpc/service_directory.rb +43 -27
- data/lib/protobuf/rpc/service_dispatcher.rb +9 -10
- data/lib/protobuf/rpc/service_filters.rb +32 -55
- data/lib/protobuf/rpc/stat.rb +4 -8
- data/lib/protobuf/socket.rb +1 -2
- data/lib/protobuf/tasks/compile.rake +3 -4
- data/lib/protobuf/varint.rb +9 -0
- data/lib/protobuf/varint_pure.rb +13 -0
- data/lib/protobuf/version.rb +1 -1
- data/lib/protobuf/zmq.rb +2 -2
- data/proto/google/protobuf/descriptor.proto +190 -31
- data/protobuffy.gemspec +30 -17
- data/spec/benchmark/tasks.rb +27 -19
- data/spec/bin/protoc-gen-ruby_spec.rb +11 -6
- data/spec/encoding/all_types_spec.rb +96 -84
- data/spec/encoding/extreme_values_spec.rb +0 -0
- data/spec/functional/class_inheritance_spec.rb +52 -0
- data/spec/functional/code_generator_spec.rb +38 -0
- data/spec/functional/socket_server_spec.rb +15 -15
- data/spec/functional/zmq_server_spec.rb +29 -27
- data/spec/lib/protobuf/cli_spec.rb +82 -67
- data/spec/lib/protobuf/code_generator_spec.rb +37 -10
- data/spec/lib/protobuf/enum_spec.rb +77 -46
- data/spec/lib/protobuf/field/bool_field_spec.rb +91 -0
- data/spec/lib/protobuf/field/double_field_spec.rb +9 -0
- data/spec/lib/protobuf/field/enum_field_spec.rb +26 -0
- data/spec/lib/protobuf/field/field_array_spec.rb +69 -0
- data/spec/lib/protobuf/field/fixed32_field_spec.rb +7 -0
- data/spec/lib/protobuf/field/fixed64_field_spec.rb +7 -0
- data/spec/lib/protobuf/field/float_field_spec.rb +90 -0
- data/spec/lib/protobuf/field/int32_field_spec.rb +114 -1
- data/spec/lib/protobuf/field/int64_field_spec.rb +7 -0
- data/spec/lib/protobuf/field/message_field_spec.rb +132 -0
- data/spec/lib/protobuf/field/sfixed32_field_spec.rb +9 -0
- data/spec/lib/protobuf/field/sfixed64_field_spec.rb +9 -0
- data/spec/lib/protobuf/field/sint32_field_spec.rb +9 -0
- data/spec/lib/protobuf/field/sint64_field_spec.rb +9 -0
- data/spec/lib/protobuf/field/string_field_spec.rb +44 -11
- data/spec/lib/protobuf/field/uint32_field_spec.rb +7 -0
- data/spec/lib/protobuf/field/uint64_field_spec.rb +7 -0
- data/spec/lib/protobuf/field_spec.rb +4 -6
- data/spec/lib/protobuf/generators/base_spec.rb +80 -13
- data/spec/lib/protobuf/generators/enum_generator_spec.rb +35 -21
- data/spec/lib/protobuf/generators/extension_generator_spec.rb +12 -13
- data/spec/lib/protobuf/generators/field_generator_spec.rb +73 -21
- data/spec/lib/protobuf/generators/file_generator_spec.rb +89 -6
- data/spec/lib/protobuf/generators/service_generator_spec.rb +25 -13
- data/spec/lib/protobuf/lifecycle_spec.rb +25 -20
- data/spec/lib/protobuf/message_spec.rb +578 -79
- data/spec/lib/protobuf/optionable_spec.rb +202 -26
- data/spec/lib/protobuf/rpc/client_spec.rb +16 -16
- data/spec/lib/protobuf/rpc/connectors/base_spec.rb +167 -13
- data/spec/lib/protobuf/rpc/connectors/connector_spec.rb +4 -5
- data/spec/lib/protobuf/rpc/connectors/http_spec.rb +13 -11
- data/spec/lib/protobuf/rpc/connectors/ping_spec.rb +69 -0
- data/spec/lib/protobuf/rpc/connectors/socket_spec.rb +6 -7
- data/spec/lib/protobuf/rpc/connectors/zmq_spec.rb +35 -52
- data/spec/lib/protobuf/rpc/middleware/exception_handler_spec.rb +10 -10
- data/spec/lib/protobuf/rpc/middleware/logger_spec.rb +11 -11
- data/spec/lib/protobuf/rpc/middleware/request_decoder_spec.rb +23 -23
- data/spec/lib/protobuf/rpc/middleware/response_encoder_spec.rb +11 -11
- data/spec/lib/protobuf/rpc/middleware/statsd_spec.rb +6 -6
- data/spec/lib/protobuf/rpc/servers/http/server_spec.rb +47 -44
- data/spec/lib/protobuf/rpc/servers/socket_server_spec.rb +6 -6
- data/spec/lib/protobuf/rpc/servers/zmq/server_spec.rb +12 -10
- data/spec/lib/protobuf/rpc/servers/zmq/util_spec.rb +11 -11
- data/spec/lib/protobuf/rpc/servers/zmq/worker_spec.rb +7 -7
- data/spec/lib/protobuf/rpc/service_directory_spec.rb +47 -49
- data/spec/lib/protobuf/rpc/service_dispatcher_spec.rb +8 -25
- data/spec/lib/protobuf/rpc/service_filters_spec.rb +102 -69
- data/spec/lib/protobuf/rpc/service_spec.rb +37 -36
- data/spec/lib/protobuf/rpc/stat_spec.rb +7 -9
- data/spec/lib/protobuf/varint_spec.rb +29 -0
- data/spec/lib/protobuf_spec.rb +55 -28
- data/spec/spec_helper.rb +12 -27
- data/spec/support/all.rb +0 -1
- data/spec/support/packed_field.rb +4 -3
- data/spec/support/{test → protos}/all_types.data.bin +0 -0
- data/spec/support/{test → protos}/all_types.data.txt +0 -0
- data/spec/support/{test → protos}/enum.pb.rb +8 -4
- data/spec/support/{test → protos}/enum.proto +4 -1
- data/spec/support/{test → protos}/extreme_values.data.bin +0 -0
- data/spec/support/protos/google_unittest.bin +0 -0
- data/spec/support/protos/google_unittest.pb.rb +798 -0
- data/spec/support/{test → protos}/google_unittest.proto +237 -66
- data/spec/support/protos/google_unittest_custom_options.bin +0 -0
- data/spec/support/protos/google_unittest_custom_options.pb.rb +268 -0
- data/spec/support/protos/google_unittest_custom_options.proto +424 -0
- data/spec/support/protos/google_unittest_import.pb.rb +55 -0
- data/spec/support/{test → protos}/google_unittest_import.proto +19 -10
- data/spec/support/protos/google_unittest_import_public.pb.rb +31 -0
- data/spec/support/{test → protos}/google_unittest_import_public.proto +8 -5
- data/spec/support/{test → protos}/multi_field_extensions.pb.rb +5 -2
- data/spec/support/{test → protos}/multi_field_extensions.proto +2 -0
- data/spec/support/{test → protos}/resource.pb.rb +47 -11
- data/spec/support/{test → protos}/resource.proto +24 -1
- data/spec/support/resource_service.rb +23 -0
- data/spec/support/server.rb +32 -61
- metadata +119 -59
- data/lib/protobuf/deprecator.rb +0 -42
- data/lib/protobuf/logger.rb +0 -93
- data/lib/protobuf/rpc/connector.rb +0 -21
- data/lib/protobuf/rpc/connectors/common.rb +0 -172
- data/spec/data/data.bin +0 -3
- data/spec/data/types.bin +0 -0
- data/spec/lib/protobuf/logger_spec.rb +0 -145
- data/spec/lib/protobuf/rpc/connector_spec.rb +0 -26
- data/spec/lib/protobuf/rpc/connectors/common_spec.rb +0 -170
- data/spec/support/test/defaults.pb.rb +0 -25
- data/spec/support/test/defaults.proto +0 -9
- data/spec/support/test/extended.pb.rb +0 -22
- data/spec/support/test/extended.proto +0 -10
- data/spec/support/test/google_unittest.pb.rb +0 -543
- data/spec/support/test/google_unittest_import.pb.rb +0 -37
- data/spec/support/test/google_unittest_import_public.pb.rb +0 -8
- data/spec/support/test/resource_service.rb +0 -26
- data/spec/support/tolerance_matcher.rb +0 -40
data/lib/protobuf/rpc/client.rb
CHANGED
@@ -1,16 +1,15 @@
|
|
1
1
|
require 'forwardable'
|
2
2
|
require 'protobuf'
|
3
|
-
require 'protobuf/
|
3
|
+
require 'protobuf/logging'
|
4
4
|
require 'protobuf/rpc/error'
|
5
|
-
require 'protobuf/rpc/connector'
|
6
5
|
|
7
6
|
module Protobuf
|
8
7
|
module Rpc
|
9
8
|
class Client
|
10
9
|
extend Forwardable
|
11
|
-
include Protobuf::
|
10
|
+
include Protobuf::Logging
|
12
11
|
|
13
|
-
def_delegators :@connector, :options, :complete_cb, :success_cb, :failure_cb
|
12
|
+
def_delegators :@connector, :options, :complete_cb, :success_cb, :failure_cb, :send_request
|
14
13
|
attr_reader :connector
|
15
14
|
|
16
15
|
# Create a new client with default options (defined in ClientConnection)
|
@@ -27,9 +26,9 @@ module Protobuf
|
|
27
26
|
# })
|
28
27
|
#
|
29
28
|
def initialize(options = {})
|
30
|
-
|
31
|
-
@connector =
|
32
|
-
|
29
|
+
fail "Invalid client configuration. Service must be defined." if options[:service].nil?
|
30
|
+
@connector = ::Protobuf.connector_type_class.new(options)
|
31
|
+
logger.debug { sign_message("Initialized with options: #{options.inspect}") }
|
33
32
|
end
|
34
33
|
|
35
34
|
def log_signature
|
@@ -46,8 +45,8 @@ module Protobuf
|
|
46
45
|
end
|
47
46
|
|
48
47
|
def on_complete=(callable)
|
49
|
-
if callable
|
50
|
-
|
48
|
+
if !callable.nil? && !callable.respond_to?(:call) && callable.arity != 1
|
49
|
+
fail "callable must take a single argument and respond to :call"
|
51
50
|
end
|
52
51
|
|
53
52
|
@connector.complete_cb = callable
|
@@ -65,8 +64,8 @@ module Protobuf
|
|
65
64
|
end
|
66
65
|
|
67
66
|
def on_failure=(callable)
|
68
|
-
if callable
|
69
|
-
|
67
|
+
if !callable.nil? && !callable.respond_to?(:call) && callable.arity != 1
|
68
|
+
fail "Callable must take a single argument and respond to :call"
|
70
69
|
end
|
71
70
|
|
72
71
|
@connector.failure_cb = callable
|
@@ -84,8 +83,8 @@ module Protobuf
|
|
84
83
|
end
|
85
84
|
|
86
85
|
def on_success=(callable)
|
87
|
-
if callable
|
88
|
-
|
86
|
+
if !callable.nil? && !callable.respond_to?(:call) && callable.arity != 1
|
87
|
+
fail "Callable must take a single argument and respond to :call"
|
89
88
|
end
|
90
89
|
|
91
90
|
@connector.success_cb = callable
|
@@ -105,62 +104,35 @@ module Protobuf
|
|
105
104
|
#
|
106
105
|
def method_missing(method_name, *params)
|
107
106
|
service = options[:service]
|
108
|
-
|
109
|
-
|
110
|
-
super(method_name, *params)
|
111
|
-
else
|
112
|
-
log_debug { sign_message("#{service.name}##{method_name.to_s}") }
|
107
|
+
if service.rpc_method?(method_name)
|
108
|
+
logger.debug { sign_message("#{service.name}##{method_name}") }
|
113
109
|
rpc = service.rpcs[method_name.to_sym]
|
114
110
|
|
115
111
|
options[:request_type] = rpc.request_type
|
116
|
-
|
112
|
+
logger.debug { sign_message("Request Type: #{options[:request_type].name}") }
|
117
113
|
|
118
114
|
options[:response_type] = rpc.response_type
|
119
|
-
|
115
|
+
logger.debug { sign_message("Response Type: #{options[:response_type].name}") }
|
120
116
|
|
121
117
|
options[:method] = method_name.to_s
|
122
118
|
options[:request] = params[0].is_a?(Hash) ? options[:request_type].new(params[0]) : params[0]
|
123
|
-
|
119
|
+
logger.debug { sign_message("Request Data: #{options[:request].inspect}") }
|
124
120
|
|
125
121
|
# Call client to setup on_success and on_failure event callbacks
|
126
122
|
if block_given?
|
127
|
-
|
123
|
+
logger.debug { sign_message("client setup callback given, invoking") }
|
128
124
|
yield(self)
|
129
125
|
else
|
130
|
-
|
126
|
+
logger.debug { sign_message("no block given for callbacks") }
|
131
127
|
end
|
132
128
|
|
133
129
|
send_request
|
130
|
+
else
|
131
|
+
logger.error { sign_message("#{service.name}##{method_name} not rpc method, passing to super") }
|
132
|
+
super(method_name, *params)
|
134
133
|
end
|
135
134
|
end
|
136
135
|
|
137
|
-
# Send the request to the service.
|
138
|
-
# This method is usually never called directly
|
139
|
-
# but is invoked by method_missing (see docs above).
|
140
|
-
#
|
141
|
-
# request = WidgetFindRequest.new
|
142
|
-
# client = Client.new({
|
143
|
-
# :service => WidgetService,
|
144
|
-
# :method => "find",
|
145
|
-
# :request_type => "WidgetFindRequest",
|
146
|
-
# :response_type => "WidgetList",
|
147
|
-
# :request => request
|
148
|
-
# })
|
149
|
-
#
|
150
|
-
# client.on_success do |res|
|
151
|
-
# res.widgets.each{|w| puts w.inspect }
|
152
|
-
# end
|
153
|
-
#
|
154
|
-
# client.on_failure do |err|
|
155
|
-
# puts err.message
|
156
|
-
# end
|
157
|
-
#
|
158
|
-
# client.send_request
|
159
|
-
#
|
160
|
-
def send_request
|
161
|
-
@connector.send_request
|
162
|
-
end
|
163
|
-
|
164
136
|
end
|
165
137
|
|
166
138
|
ActiveSupport.run_load_hooks(:protobuf_rpc_client, Client)
|
@@ -1,10 +1,9 @@
|
|
1
1
|
require 'timeout'
|
2
|
-
require 'protobuf/
|
2
|
+
require 'protobuf/logging'
|
3
3
|
require 'protobuf/rpc/rpc.pb'
|
4
4
|
require 'protobuf/rpc/buffer'
|
5
5
|
require 'protobuf/rpc/error'
|
6
6
|
require 'protobuf/rpc/stat'
|
7
|
-
require 'protobuf/rpc/connectors/common'
|
8
7
|
|
9
8
|
module Protobuf
|
10
9
|
module Rpc
|
@@ -17,28 +16,117 @@ module Protobuf
|
|
17
16
|
:request => nil, # The request object sent by the client
|
18
17
|
:request_type => nil, # The request type expected by the client
|
19
18
|
:response_type => nil, # The response type expected by the client
|
20
|
-
:timeout =>
|
19
|
+
:timeout => nil, # The timeout for the request, also handled by client.rb
|
21
20
|
:client_host => nil, # The hostname or address of this client
|
22
|
-
:first_alive_load_balance => false,
|
23
|
-
}
|
21
|
+
:first_alive_load_balance => false, # Do we want to use check_avail frames before request
|
22
|
+
}.freeze
|
24
23
|
|
25
24
|
class Base
|
26
|
-
include Protobuf::
|
25
|
+
include Protobuf::Logging
|
27
26
|
|
28
|
-
attr_reader :options
|
29
|
-
attr_accessor :success_cb, :failure_cb, :complete_cb
|
27
|
+
attr_reader :options, :error
|
28
|
+
attr_accessor :success_cb, :failure_cb, :complete_cb, :stats
|
30
29
|
|
31
30
|
def initialize(options)
|
32
31
|
@options = DEFAULT_OPTIONS.merge(options)
|
32
|
+
@stats = ::Protobuf::Rpc::Stat.new(:CLIENT)
|
33
|
+
end
|
34
|
+
|
35
|
+
def any_callbacks?
|
36
|
+
[@complete_cb, @failure_cb, @success_cb].any?
|
37
|
+
end
|
38
|
+
|
39
|
+
def close_connection
|
40
|
+
fail 'If you inherit a Connector from Base you must implement close_connection'
|
41
|
+
end
|
42
|
+
|
43
|
+
def complete
|
44
|
+
@stats.stop
|
45
|
+
logger.info { @stats.to_s }
|
46
|
+
logger.debug { sign_message('Response proceessing complete') }
|
47
|
+
@complete_cb.call(self) unless @complete_cb.nil?
|
48
|
+
rescue => e
|
49
|
+
logger.error { sign_message('Complete callback error encountered') }
|
50
|
+
log_exception(e)
|
51
|
+
raise
|
52
|
+
end
|
53
|
+
|
54
|
+
def data_callback(data)
|
55
|
+
logger.debug { sign_message('Using data_callback') }
|
56
|
+
@used_data_callback = true
|
57
|
+
@data = data
|
58
|
+
end
|
59
|
+
|
60
|
+
# All failures should be routed through this method.
|
61
|
+
#
|
62
|
+
# @param [Symbol] code The code we're using (see ::Protobuf::Socketrpc::ErrorReason)
|
63
|
+
# @param [String] message The error message
|
64
|
+
def failure(code, message)
|
65
|
+
@error = ClientError.new
|
66
|
+
@error.code = ::Protobuf::Socketrpc::ErrorReason.fetch(code)
|
67
|
+
@error.message = message
|
68
|
+
logger.debug { sign_message("Server failed request (invoking on_failure): #{@error.inspect}") }
|
69
|
+
|
70
|
+
@stats.failure(code)
|
71
|
+
@failure_cb.call(@error) unless @failure_cb.nil?
|
72
|
+
rescue => e
|
73
|
+
logger.error { sign_message("Failure callback error encountered") }
|
74
|
+
log_exception(e)
|
75
|
+
raise
|
76
|
+
ensure
|
77
|
+
complete
|
33
78
|
end
|
34
79
|
|
35
80
|
def first_alive_load_balance?
|
36
|
-
ENV.
|
81
|
+
ENV.key?("PB_FIRST_ALIVE_LOAD_BALANCE") ||
|
37
82
|
options[:first_alive_load_balance]
|
38
83
|
end
|
39
84
|
|
40
|
-
def
|
41
|
-
|
85
|
+
def initialize_stats
|
86
|
+
@stats = ::Protobuf::Rpc::Stat.new(:CLIENT)
|
87
|
+
@stats.server = [@options[:port], @options[:host]]
|
88
|
+
@stats.service = @options[:service].name
|
89
|
+
@stats.method_name = @options[:method].to_s
|
90
|
+
rescue => ex
|
91
|
+
log_exception(ex)
|
92
|
+
failure(:RPC_ERROR, "Invalid stats configuration. #{ex.message}")
|
93
|
+
end
|
94
|
+
|
95
|
+
def log_signature
|
96
|
+
@_log_signature ||= "[client-#{self.class}]"
|
97
|
+
end
|
98
|
+
|
99
|
+
def parse_response
|
100
|
+
# Close up the connection as we no longer need it
|
101
|
+
close_connection
|
102
|
+
|
103
|
+
logger.debug { sign_message("Parsing response from server (connection closed)") }
|
104
|
+
|
105
|
+
# Parse out the raw response
|
106
|
+
@stats.response_size = @response_data.size unless @response_data.nil?
|
107
|
+
response_wrapper = ::Protobuf::Socketrpc::Response.decode(@response_data)
|
108
|
+
|
109
|
+
# Determine success or failure based on parsed data
|
110
|
+
if response_wrapper.field?(:error_reason)
|
111
|
+
logger.debug { sign_message("Error response parsed") }
|
112
|
+
|
113
|
+
# fail the call if we already know the client is failed
|
114
|
+
# (don't try to parse out the response payload)
|
115
|
+
failure(response_wrapper.error_reason, response_wrapper.error)
|
116
|
+
else
|
117
|
+
logger.debug { sign_message("Successful response parsed") }
|
118
|
+
|
119
|
+
# Ensure client_response is an instance
|
120
|
+
parsed = @options[:response_type].decode(response_wrapper.response_proto.to_s)
|
121
|
+
|
122
|
+
if parsed.nil? && !response_wrapper.field?(:error_reason)
|
123
|
+
failure(:BAD_RESPONSE_PROTO, 'Unable to parse response from server')
|
124
|
+
else
|
125
|
+
verify_callbacks
|
126
|
+
succeed(parsed)
|
127
|
+
return @data if @used_data_callback
|
128
|
+
end
|
129
|
+
end
|
42
130
|
end
|
43
131
|
|
44
132
|
def ping_port
|
@@ -46,8 +134,85 @@ module Protobuf
|
|
46
134
|
end
|
47
135
|
|
48
136
|
def ping_port_enabled?
|
49
|
-
ENV.
|
137
|
+
ENV.key?("PB_RPC_PING_PORT")
|
50
138
|
end
|
139
|
+
|
140
|
+
def request_bytes
|
141
|
+
validate_request_type!
|
142
|
+
fields = { :service_name => @options[:service].name,
|
143
|
+
:method_name => @options[:method].to_s,
|
144
|
+
:request_proto => @options[:request],
|
145
|
+
:caller => request_caller }
|
146
|
+
|
147
|
+
return ::Protobuf::Socketrpc::Request.encode(fields)
|
148
|
+
rescue => e
|
149
|
+
failure(:INVALID_REQUEST_PROTO, "Could not set request proto: #{e.message}")
|
150
|
+
end
|
151
|
+
|
152
|
+
def request_caller
|
153
|
+
@options[:client_host] || ::Protobuf.client_host
|
154
|
+
end
|
155
|
+
|
156
|
+
def send_request
|
157
|
+
fail 'If you inherit a Connector from Base you must implement send_request'
|
158
|
+
end
|
159
|
+
|
160
|
+
def setup_connection
|
161
|
+
initialize_stats
|
162
|
+
@request_data = request_bytes
|
163
|
+
@stats.request_size = @request_data.size
|
164
|
+
end
|
165
|
+
|
166
|
+
def succeed(response)
|
167
|
+
logger.debug { sign_message("Server succeeded request (invoking on_success)") }
|
168
|
+
@stats.success
|
169
|
+
@success_cb.call(response) unless @success_cb.nil?
|
170
|
+
rescue => e
|
171
|
+
logger.error { sign_message("Success callback error encountered") }
|
172
|
+
log_exception(e)
|
173
|
+
failure(:RPC_ERROR, "An exception occurred while calling on_success: #{e.message}")
|
174
|
+
ensure
|
175
|
+
complete
|
176
|
+
end
|
177
|
+
|
178
|
+
def timeout
|
179
|
+
if options[:timeout]
|
180
|
+
options[:timeout]
|
181
|
+
else
|
182
|
+
300 # seconds
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
# Wrap the given block in a timeout of the configured number of seconds.
|
187
|
+
#
|
188
|
+
def timeout_wrap(&block)
|
189
|
+
::Timeout.timeout(timeout, &block)
|
190
|
+
rescue ::Timeout::Error
|
191
|
+
failure(:RPC_FAILED, "The server took longer than #{timeout} seconds to respond")
|
192
|
+
end
|
193
|
+
|
194
|
+
def validate_request_type!
|
195
|
+
unless @options[:request].class == @options[:request_type]
|
196
|
+
expected = @options[:request_type].name
|
197
|
+
actual = @options[:request].class.name
|
198
|
+
failure(:INVALID_REQUEST_PROTO, "Expected request type to be type of #{expected}, got #{actual} instead")
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
def verify_callbacks
|
203
|
+
unless any_callbacks?
|
204
|
+
logger.debug { sign_message("No callbacks set, using data_callback") }
|
205
|
+
@success_cb = @failure_cb = method(:data_callback)
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def verify_options!
|
210
|
+
# Verify the options that are necessary and merge them in
|
211
|
+
[:service, :method, :host, :port].each do |opt|
|
212
|
+
failure(:RPC_ERROR, "Invalid client connection configuration. #{opt} must be a defined option.") if @options[opt].nil?
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
51
216
|
end
|
52
217
|
end
|
53
218
|
end
|
@@ -6,8 +6,7 @@ module Protobuf
|
|
6
6
|
module Rpc
|
7
7
|
module Connectors
|
8
8
|
class Http < Base
|
9
|
-
include Protobuf::
|
10
|
-
include Protobuf::Logger::LogMethods
|
9
|
+
include ::Protobuf::Logging
|
11
10
|
|
12
11
|
def send_request
|
13
12
|
timeout_wrap do
|
@@ -23,12 +22,12 @@ module Protobuf
|
|
23
22
|
# private
|
24
23
|
|
25
24
|
def close_connection
|
26
|
-
|
25
|
+
logger.debug { sign_message('Connector closed') }
|
27
26
|
end
|
28
27
|
|
29
28
|
# Method to determine error state, must be used with Connector api
|
30
29
|
def error?
|
31
|
-
|
30
|
+
logger.debug { sign_message("Error state : #{@error}") }
|
32
31
|
if @error
|
33
32
|
true
|
34
33
|
else
|
@@ -41,31 +40,37 @@ module Protobuf
|
|
41
40
|
end
|
42
41
|
|
43
42
|
def base
|
44
|
-
options[:base]
|
43
|
+
options[:base] || ''
|
45
44
|
end
|
46
45
|
|
47
46
|
def client
|
48
47
|
@_client ||= Faraday.new(:url => host)
|
49
48
|
end
|
50
49
|
|
50
|
+
def post_init
|
51
|
+
send_data unless error?
|
52
|
+
rescue => e
|
53
|
+
fail(:RPC_ERROR, "Connection error: #{e.message}")
|
54
|
+
end
|
55
|
+
|
51
56
|
def send_data
|
52
57
|
rpc_request = ::Protobuf::Socketrpc::Request.decode(@request_data)
|
53
58
|
|
54
59
|
http_response = client.post do |http_request|
|
55
60
|
path_components = [''] + rpc_request[:service_name].split('::') + [rpc_request[:method_name]]
|
56
|
-
http_request.url base + path_components.map{ |x| CGI
|
61
|
+
http_request.url base + path_components.map { |x| CGI.escape(x) }.join('/')
|
57
62
|
http_request.headers['Content-Type'] = 'application/x-protobuf'
|
58
63
|
http_request.headers['X-Protobuf-Caller'] = rpc_request[:caller] || ''
|
59
64
|
http_request.body = rpc_request[:request_proto]
|
60
65
|
end
|
61
66
|
|
62
67
|
# Server returns protobuf response with no error
|
63
|
-
if http_response.status == 200
|
68
|
+
if http_response.status == 200 && http_response.headers['x-protobuf-error'].nil?
|
64
69
|
rpc_response = Protobuf::Socketrpc::Response.new(
|
65
70
|
:response_proto => http_response.body
|
66
71
|
)
|
67
72
|
# Server returns protobuf error
|
68
|
-
elsif http_response.status != 200
|
73
|
+
elsif http_response.status != 200 && http_response.headers['x-protobuf-error']
|
69
74
|
rpc_response = Protobuf::Socketrpc::Response.new(
|
70
75
|
:response_proto => http_response.body,
|
71
76
|
:error => http_response.headers['x-protobuf-error'],
|
@@ -80,7 +85,7 @@ module Protobuf
|
|
80
85
|
)
|
81
86
|
end
|
82
87
|
|
83
|
-
@response_data = rpc_response.encode
|
88
|
+
@response_data = rpc_response.encode
|
84
89
|
|
85
90
|
parse_response
|
86
91
|
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
require "socket"
|
2
|
+
|
3
|
+
module Protobuf
|
4
|
+
module Rpc
|
5
|
+
module Connectors
|
6
|
+
class Ping
|
7
|
+
attr_reader :host, :port
|
8
|
+
|
9
|
+
def initialize(host, port)
|
10
|
+
@host = host
|
11
|
+
@port = port
|
12
|
+
end
|
13
|
+
|
14
|
+
def online?
|
15
|
+
socket = tcp_socket
|
16
|
+
socket.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_LINGER, [1, 0].pack('ii'))
|
17
|
+
|
18
|
+
true
|
19
|
+
rescue
|
20
|
+
false
|
21
|
+
ensure
|
22
|
+
begin
|
23
|
+
socket && socket.close
|
24
|
+
rescue IOError
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def timeout
|
30
|
+
@timeout ||= begin
|
31
|
+
if ::ENV.key?("PB_RPC_PING_PORT_TIMEOUT")
|
32
|
+
::ENV["PB_RPC_PING_PORT_TIMEOUT"].to_f / 1000
|
33
|
+
else
|
34
|
+
0.2 # 200 ms
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def tcp_socket
|
42
|
+
# Reference: http://stackoverflow.com/a/21014439/1457934
|
43
|
+
socket = ::Socket.new(family, ::Socket::SOCK_STREAM, 0)
|
44
|
+
socket.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, 1)
|
45
|
+
socket.connect_nonblock(sockaddr)
|
46
|
+
socket
|
47
|
+
rescue ::IO::WaitWritable
|
48
|
+
# IO.select will block until the socket is writable or the timeout
|
49
|
+
# is exceeded - whichever comes first.
|
50
|
+
if ::IO.select(nil, [socket], nil, timeout)
|
51
|
+
begin
|
52
|
+
# Verify there is now a good connection
|
53
|
+
socket.connect_nonblock(sockaddr)
|
54
|
+
socket
|
55
|
+
rescue ::Errno::EISCONN
|
56
|
+
# Socket is connected.
|
57
|
+
socket
|
58
|
+
rescue
|
59
|
+
# An unexpected exception was raised - the connection is no good.
|
60
|
+
socket.close
|
61
|
+
raise
|
62
|
+
end
|
63
|
+
else
|
64
|
+
# IO.select returns nil when the socket is not ready before timeout
|
65
|
+
# seconds have elapsed
|
66
|
+
socket.close
|
67
|
+
raise "Connection Timeout"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def family
|
72
|
+
@family ||= ::Socket.const_get(addrinfo[0][0])
|
73
|
+
end
|
74
|
+
|
75
|
+
def addrinfo
|
76
|
+
@addrinfo ||= ::Socket.getaddrinfo(host, nil)
|
77
|
+
end
|
78
|
+
|
79
|
+
def ip
|
80
|
+
@ip ||= addrinfo[0][3]
|
81
|
+
end
|
82
|
+
|
83
|
+
def sockaddr
|
84
|
+
@sockaddr ||= ::Socket.pack_sockaddr_in(port, ip)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|