protobuffy 3.6.0 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (209) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +67 -0
  4. data/.rubocop_todo.yml +145 -0
  5. data/.travis.yml +25 -5
  6. data/CHANGES.md +55 -0
  7. data/CONTRIBUTING.md +1 -1
  8. data/LICENSE.txt +17 -9
  9. data/README.md +13 -12
  10. data/Rakefile +15 -11
  11. data/bin/protoc-gen-ruby +8 -3
  12. data/bin/rpc_server +1 -0
  13. data/examples/lib/example/reverse-client.rb +2 -2
  14. data/install-protobuf.sh +28 -0
  15. data/lib/protobuf.rb +57 -53
  16. data/lib/protobuf/cli.rb +94 -74
  17. data/lib/protobuf/code_generator.rb +60 -9
  18. data/lib/protobuf/decoder.rb +19 -65
  19. data/lib/protobuf/deprecation.rb +117 -0
  20. data/lib/protobuf/descriptors/google/protobuf/compiler/plugin.pb.rb +11 -1
  21. data/lib/protobuf/descriptors/google/protobuf/descriptor.pb.rb +55 -3
  22. data/lib/protobuf/encoder.rb +13 -53
  23. data/lib/protobuf/enum.rb +58 -63
  24. data/lib/protobuf/field.rb +4 -4
  25. data/lib/protobuf/field/base_field.rb +101 -173
  26. data/lib/protobuf/field/bool_field.rb +17 -11
  27. data/lib/protobuf/field/bytes_field.rb +21 -35
  28. data/lib/protobuf/field/double_field.rb +0 -1
  29. data/lib/protobuf/field/enum_field.rb +23 -22
  30. data/lib/protobuf/field/field_array.rb +5 -4
  31. data/lib/protobuf/field/fixed32_field.rb +1 -1
  32. data/lib/protobuf/field/fixed64_field.rb +0 -1
  33. data/lib/protobuf/field/float_field.rb +4 -1
  34. data/lib/protobuf/field/int32_field.rb +0 -1
  35. data/lib/protobuf/field/int64_field.rb +0 -1
  36. data/lib/protobuf/field/integer_field.rb +0 -1
  37. data/lib/protobuf/field/message_field.rb +13 -28
  38. data/lib/protobuf/field/sfixed32_field.rb +0 -1
  39. data/lib/protobuf/field/sfixed64_field.rb +0 -1
  40. data/lib/protobuf/field/signed_integer_field.rb +0 -1
  41. data/lib/protobuf/field/sint32_field.rb +0 -1
  42. data/lib/protobuf/field/sint64_field.rb +0 -1
  43. data/lib/protobuf/field/string_field.rb +2 -4
  44. data/lib/protobuf/field/uint32_field.rb +0 -1
  45. data/lib/protobuf/field/uint64_field.rb +0 -1
  46. data/lib/protobuf/field/varint_field.rb +30 -13
  47. data/lib/protobuf/generators/base.rb +30 -16
  48. data/lib/protobuf/generators/enum_generator.rb +6 -9
  49. data/lib/protobuf/generators/extension_generator.rb +1 -2
  50. data/lib/protobuf/generators/field_generator.rb +25 -13
  51. data/lib/protobuf/generators/file_generator.rb +157 -35
  52. data/lib/protobuf/generators/group_generator.rb +22 -17
  53. data/lib/protobuf/generators/message_generator.rb +13 -14
  54. data/lib/protobuf/generators/option_generator.rb +17 -0
  55. data/lib/protobuf/generators/printable.rb +12 -13
  56. data/lib/protobuf/generators/service_generator.rb +2 -3
  57. data/lib/protobuf/http.rb +2 -2
  58. data/lib/protobuf/lifecycle.rb +20 -33
  59. data/lib/protobuf/logging.rb +39 -0
  60. data/lib/protobuf/message.rb +114 -47
  61. data/lib/protobuf/message/fields.rb +170 -88
  62. data/lib/protobuf/message/serialization.rb +19 -18
  63. data/lib/protobuf/optionable.rb +53 -6
  64. data/lib/protobuf/rpc/buffer.rb +18 -19
  65. data/lib/protobuf/rpc/client.rb +22 -50
  66. data/lib/protobuf/rpc/connectors/base.rb +177 -12
  67. data/lib/protobuf/rpc/connectors/http.rb +14 -9
  68. data/lib/protobuf/rpc/connectors/ping.rb +89 -0
  69. data/lib/protobuf/rpc/connectors/socket.rb +13 -8
  70. data/lib/protobuf/rpc/connectors/zmq.rb +178 -73
  71. data/lib/protobuf/rpc/dynamic_discovery.pb.rb +4 -1
  72. data/lib/protobuf/rpc/env.rb +12 -12
  73. data/lib/protobuf/rpc/error.rb +3 -3
  74. data/lib/protobuf/rpc/error/client_error.rb +4 -4
  75. data/lib/protobuf/rpc/error/server_error.rb +9 -9
  76. data/lib/protobuf/rpc/middleware/exception_handler.rb +6 -2
  77. data/lib/protobuf/rpc/middleware/logger.rb +8 -4
  78. data/lib/protobuf/rpc/middleware/request_decoder.rb +17 -21
  79. data/lib/protobuf/rpc/middleware/response_encoder.rb +22 -27
  80. data/lib/protobuf/rpc/middleware/statsd.rb +3 -3
  81. data/lib/protobuf/rpc/rpc.pb.rb +4 -1
  82. data/lib/protobuf/rpc/server.rb +1 -1
  83. data/lib/protobuf/rpc/servers/http/server.rb +19 -17
  84. data/lib/protobuf/rpc/servers/socket/server.rb +78 -70
  85. data/lib/protobuf/rpc/servers/socket/worker.rb +4 -4
  86. data/lib/protobuf/rpc/servers/socket_runner.rb +27 -15
  87. data/lib/protobuf/rpc/servers/zmq/broker.rb +70 -31
  88. data/lib/protobuf/rpc/servers/zmq/server.rb +55 -47
  89. data/lib/protobuf/rpc/servers/zmq/util.rb +14 -13
  90. data/lib/protobuf/rpc/servers/zmq/worker.rb +16 -16
  91. data/lib/protobuf/rpc/servers/zmq_runner.rb +26 -7
  92. data/lib/protobuf/rpc/service.rb +21 -27
  93. data/lib/protobuf/rpc/service_directory.rb +43 -27
  94. data/lib/protobuf/rpc/service_dispatcher.rb +9 -10
  95. data/lib/protobuf/rpc/service_filters.rb +32 -55
  96. data/lib/protobuf/rpc/stat.rb +4 -8
  97. data/lib/protobuf/socket.rb +1 -2
  98. data/lib/protobuf/tasks/compile.rake +3 -4
  99. data/lib/protobuf/varint.rb +9 -0
  100. data/lib/protobuf/varint_pure.rb +13 -0
  101. data/lib/protobuf/version.rb +1 -1
  102. data/lib/protobuf/zmq.rb +2 -2
  103. data/proto/google/protobuf/descriptor.proto +190 -31
  104. data/protobuffy.gemspec +30 -17
  105. data/spec/benchmark/tasks.rb +27 -19
  106. data/spec/bin/protoc-gen-ruby_spec.rb +11 -6
  107. data/spec/encoding/all_types_spec.rb +96 -84
  108. data/spec/encoding/extreme_values_spec.rb +0 -0
  109. data/spec/functional/class_inheritance_spec.rb +52 -0
  110. data/spec/functional/code_generator_spec.rb +38 -0
  111. data/spec/functional/socket_server_spec.rb +15 -15
  112. data/spec/functional/zmq_server_spec.rb +29 -27
  113. data/spec/lib/protobuf/cli_spec.rb +82 -67
  114. data/spec/lib/protobuf/code_generator_spec.rb +37 -10
  115. data/spec/lib/protobuf/enum_spec.rb +77 -46
  116. data/spec/lib/protobuf/field/bool_field_spec.rb +91 -0
  117. data/spec/lib/protobuf/field/double_field_spec.rb +9 -0
  118. data/spec/lib/protobuf/field/enum_field_spec.rb +26 -0
  119. data/spec/lib/protobuf/field/field_array_spec.rb +69 -0
  120. data/spec/lib/protobuf/field/fixed32_field_spec.rb +7 -0
  121. data/spec/lib/protobuf/field/fixed64_field_spec.rb +7 -0
  122. data/spec/lib/protobuf/field/float_field_spec.rb +90 -0
  123. data/spec/lib/protobuf/field/int32_field_spec.rb +114 -1
  124. data/spec/lib/protobuf/field/int64_field_spec.rb +7 -0
  125. data/spec/lib/protobuf/field/message_field_spec.rb +132 -0
  126. data/spec/lib/protobuf/field/sfixed32_field_spec.rb +9 -0
  127. data/spec/lib/protobuf/field/sfixed64_field_spec.rb +9 -0
  128. data/spec/lib/protobuf/field/sint32_field_spec.rb +9 -0
  129. data/spec/lib/protobuf/field/sint64_field_spec.rb +9 -0
  130. data/spec/lib/protobuf/field/string_field_spec.rb +44 -11
  131. data/spec/lib/protobuf/field/uint32_field_spec.rb +7 -0
  132. data/spec/lib/protobuf/field/uint64_field_spec.rb +7 -0
  133. data/spec/lib/protobuf/field_spec.rb +4 -6
  134. data/spec/lib/protobuf/generators/base_spec.rb +80 -13
  135. data/spec/lib/protobuf/generators/enum_generator_spec.rb +35 -21
  136. data/spec/lib/protobuf/generators/extension_generator_spec.rb +12 -13
  137. data/spec/lib/protobuf/generators/field_generator_spec.rb +73 -21
  138. data/spec/lib/protobuf/generators/file_generator_spec.rb +89 -6
  139. data/spec/lib/protobuf/generators/service_generator_spec.rb +25 -13
  140. data/spec/lib/protobuf/lifecycle_spec.rb +25 -20
  141. data/spec/lib/protobuf/message_spec.rb +578 -79
  142. data/spec/lib/protobuf/optionable_spec.rb +202 -26
  143. data/spec/lib/protobuf/rpc/client_spec.rb +16 -16
  144. data/spec/lib/protobuf/rpc/connectors/base_spec.rb +167 -13
  145. data/spec/lib/protobuf/rpc/connectors/connector_spec.rb +4 -5
  146. data/spec/lib/protobuf/rpc/connectors/http_spec.rb +13 -11
  147. data/spec/lib/protobuf/rpc/connectors/ping_spec.rb +69 -0
  148. data/spec/lib/protobuf/rpc/connectors/socket_spec.rb +6 -7
  149. data/spec/lib/protobuf/rpc/connectors/zmq_spec.rb +35 -52
  150. data/spec/lib/protobuf/rpc/middleware/exception_handler_spec.rb +10 -10
  151. data/spec/lib/protobuf/rpc/middleware/logger_spec.rb +11 -11
  152. data/spec/lib/protobuf/rpc/middleware/request_decoder_spec.rb +23 -23
  153. data/spec/lib/protobuf/rpc/middleware/response_encoder_spec.rb +11 -11
  154. data/spec/lib/protobuf/rpc/middleware/statsd_spec.rb +6 -6
  155. data/spec/lib/protobuf/rpc/servers/http/server_spec.rb +47 -44
  156. data/spec/lib/protobuf/rpc/servers/socket_server_spec.rb +6 -6
  157. data/spec/lib/protobuf/rpc/servers/zmq/server_spec.rb +12 -10
  158. data/spec/lib/protobuf/rpc/servers/zmq/util_spec.rb +11 -11
  159. data/spec/lib/protobuf/rpc/servers/zmq/worker_spec.rb +7 -7
  160. data/spec/lib/protobuf/rpc/service_directory_spec.rb +47 -49
  161. data/spec/lib/protobuf/rpc/service_dispatcher_spec.rb +8 -25
  162. data/spec/lib/protobuf/rpc/service_filters_spec.rb +102 -69
  163. data/spec/lib/protobuf/rpc/service_spec.rb +37 -36
  164. data/spec/lib/protobuf/rpc/stat_spec.rb +7 -9
  165. data/spec/lib/protobuf/varint_spec.rb +29 -0
  166. data/spec/lib/protobuf_spec.rb +55 -28
  167. data/spec/spec_helper.rb +12 -27
  168. data/spec/support/all.rb +0 -1
  169. data/spec/support/packed_field.rb +4 -3
  170. data/spec/support/{test → protos}/all_types.data.bin +0 -0
  171. data/spec/support/{test → protos}/all_types.data.txt +0 -0
  172. data/spec/support/{test → protos}/enum.pb.rb +8 -4
  173. data/spec/support/{test → protos}/enum.proto +4 -1
  174. data/spec/support/{test → protos}/extreme_values.data.bin +0 -0
  175. data/spec/support/protos/google_unittest.bin +0 -0
  176. data/spec/support/protos/google_unittest.pb.rb +798 -0
  177. data/spec/support/{test → protos}/google_unittest.proto +237 -66
  178. data/spec/support/protos/google_unittest_custom_options.bin +0 -0
  179. data/spec/support/protos/google_unittest_custom_options.pb.rb +268 -0
  180. data/spec/support/protos/google_unittest_custom_options.proto +424 -0
  181. data/spec/support/protos/google_unittest_import.pb.rb +55 -0
  182. data/spec/support/{test → protos}/google_unittest_import.proto +19 -10
  183. data/spec/support/protos/google_unittest_import_public.pb.rb +31 -0
  184. data/spec/support/{test → protos}/google_unittest_import_public.proto +8 -5
  185. data/spec/support/{test → protos}/multi_field_extensions.pb.rb +5 -2
  186. data/spec/support/{test → protos}/multi_field_extensions.proto +2 -0
  187. data/spec/support/{test → protos}/resource.pb.rb +47 -11
  188. data/spec/support/{test → protos}/resource.proto +24 -1
  189. data/spec/support/resource_service.rb +23 -0
  190. data/spec/support/server.rb +32 -61
  191. metadata +119 -59
  192. data/lib/protobuf/deprecator.rb +0 -42
  193. data/lib/protobuf/logger.rb +0 -93
  194. data/lib/protobuf/rpc/connector.rb +0 -21
  195. data/lib/protobuf/rpc/connectors/common.rb +0 -172
  196. data/spec/data/data.bin +0 -3
  197. data/spec/data/types.bin +0 -0
  198. data/spec/lib/protobuf/logger_spec.rb +0 -145
  199. data/spec/lib/protobuf/rpc/connector_spec.rb +0 -26
  200. data/spec/lib/protobuf/rpc/connectors/common_spec.rb +0 -170
  201. data/spec/support/test/defaults.pb.rb +0 -25
  202. data/spec/support/test/defaults.proto +0 -9
  203. data/spec/support/test/extended.pb.rb +0 -22
  204. data/spec/support/test/extended.proto +0 -10
  205. data/spec/support/test/google_unittest.pb.rb +0 -543
  206. data/spec/support/test/google_unittest_import.pb.rb +0 -37
  207. data/spec/support/test/google_unittest_import_public.pb.rb +0 -8
  208. data/spec/support/test/resource_service.rb +0 -26
  209. data/spec/support/tolerance_matcher.rb +0 -40
@@ -1,16 +1,15 @@
1
1
  require 'forwardable'
2
2
  require 'protobuf'
3
- require 'protobuf/logger'
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::Logger::LogMethods
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
- raise "Invalid client configuration. Service must be defined." if options[:service].nil?
31
- @connector = Connector.connector_for_client.new(options)
32
- log_debug { sign_message("Initialized with options: #{options.inspect}") }
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 != nil && !callable.respond_to?(:call) && callable.arity != 1
50
- raise "callable must take a single argument and respond to :call"
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 != nil && !callable.respond_to?(:call) && callable.arity != 1
69
- raise "Callable must take a single argument and respond to :call"
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 != nil && !callable.respond_to?(:call) && callable.arity != 1
88
- raise "Callable must take a single argument and respond to :call"
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
- unless service.rpc_method?(method_name)
109
- log_error { sign_message("#{service.name}##{method_name.to_s} not rpc method, passing to super") }
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
- log_debug { sign_message("Request Type: #{options[:request_type].name}") }
112
+ logger.debug { sign_message("Request Type: #{options[:request_type].name}") }
117
113
 
118
114
  options[:response_type] = rpc.response_type
119
- log_debug { sign_message("Response Type: #{options[:response_type].name}") }
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
- log_debug { sign_message("Request Data: #{options[:request].inspect}") }
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
- log_debug { sign_message("client setup callback given, invoking") }
123
+ logger.debug { sign_message("client setup callback given, invoking") }
128
124
  yield(self)
129
125
  else
130
- log_debug { sign_message("no block given for callbacks") }
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/logger'
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 => 300, # The default timeout for the request, also handled by client.rb
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, # Do we want to use check_avail frames before request
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::Logger::LogMethods
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.has_key?("PB_FIRST_ALIVE_LOAD_BALANCE") ||
81
+ ENV.key?("PB_FIRST_ALIVE_LOAD_BALANCE") ||
37
82
  options[:first_alive_load_balance]
38
83
  end
39
84
 
40
- def send_request
41
- raise 'If you inherit a Connector from Base you must implement send_request'
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.has_key?("PB_RPC_PING_PORT")
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::Rpc::Connectors::Common
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
- log_debug { sign_message('Connector closed') }
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
- log_debug { sign_message("Error state : #{@error}") }
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] or ''
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::escape(x) }.join('/')
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 and http_response.headers['x-protobuf-error'].nil?
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 and not http_response.headers['x-protobuf-error'].nil?
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