prepor-protobuf 3.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.rubocop.yml +51 -0
  4. data/.rubocop_todo.yml +89 -0
  5. data/.travis.yml +25 -0
  6. data/.yardopts +5 -0
  7. data/CHANGES.md +256 -0
  8. data/CONTRIBUTING.md +16 -0
  9. data/Gemfile +3 -0
  10. data/LICENSE.txt +22 -0
  11. data/README.md +33 -0
  12. data/Rakefile +64 -0
  13. data/bin/protoc-gen-ruby +16 -0
  14. data/bin/rpc_server +5 -0
  15. data/install-protobuf.sh +28 -0
  16. data/lib/protobuf.rb +100 -0
  17. data/lib/protobuf/cli.rb +242 -0
  18. data/lib/protobuf/code_generator.rb +44 -0
  19. data/lib/protobuf/decoder.rb +73 -0
  20. data/lib/protobuf/deprecation.rb +112 -0
  21. data/lib/protobuf/descriptors.rb +3 -0
  22. data/lib/protobuf/descriptors/google/protobuf/compiler/plugin.pb.rb +48 -0
  23. data/lib/protobuf/descriptors/google/protobuf/descriptor.pb.rb +251 -0
  24. data/lib/protobuf/encoder.rb +67 -0
  25. data/lib/protobuf/enum.rb +303 -0
  26. data/lib/protobuf/exceptions.rb +9 -0
  27. data/lib/protobuf/field.rb +74 -0
  28. data/lib/protobuf/field/base_field.rb +267 -0
  29. data/lib/protobuf/field/bool_field.rb +59 -0
  30. data/lib/protobuf/field/bytes_field.rb +82 -0
  31. data/lib/protobuf/field/double_field.rb +25 -0
  32. data/lib/protobuf/field/enum_field.rb +68 -0
  33. data/lib/protobuf/field/field_array.rb +87 -0
  34. data/lib/protobuf/field/fixed32_field.rb +25 -0
  35. data/lib/protobuf/field/fixed64_field.rb +28 -0
  36. data/lib/protobuf/field/float_field.rb +41 -0
  37. data/lib/protobuf/field/int32_field.rb +21 -0
  38. data/lib/protobuf/field/int64_field.rb +21 -0
  39. data/lib/protobuf/field/integer_field.rb +23 -0
  40. data/lib/protobuf/field/message_field.rb +65 -0
  41. data/lib/protobuf/field/sfixed32_field.rb +27 -0
  42. data/lib/protobuf/field/sfixed64_field.rb +28 -0
  43. data/lib/protobuf/field/signed_integer_field.rb +29 -0
  44. data/lib/protobuf/field/sint32_field.rb +21 -0
  45. data/lib/protobuf/field/sint64_field.rb +21 -0
  46. data/lib/protobuf/field/string_field.rb +34 -0
  47. data/lib/protobuf/field/uint32_field.rb +21 -0
  48. data/lib/protobuf/field/uint64_field.rb +21 -0
  49. data/lib/protobuf/field/varint_field.rb +73 -0
  50. data/lib/protobuf/generators/base.rb +70 -0
  51. data/lib/protobuf/generators/enum_generator.rb +41 -0
  52. data/lib/protobuf/generators/extension_generator.rb +27 -0
  53. data/lib/protobuf/generators/field_generator.rb +131 -0
  54. data/lib/protobuf/generators/file_generator.rb +135 -0
  55. data/lib/protobuf/generators/group_generator.rb +112 -0
  56. data/lib/protobuf/generators/message_generator.rb +98 -0
  57. data/lib/protobuf/generators/printable.rb +160 -0
  58. data/lib/protobuf/generators/service_generator.rb +26 -0
  59. data/lib/protobuf/lifecycle.rb +33 -0
  60. data/lib/protobuf/logging.rb +39 -0
  61. data/lib/protobuf/message.rb +193 -0
  62. data/lib/protobuf/message/fields.rb +133 -0
  63. data/lib/protobuf/message/serialization.rb +89 -0
  64. data/lib/protobuf/optionable.rb +23 -0
  65. data/lib/protobuf/rpc/buffer.rb +77 -0
  66. data/lib/protobuf/rpc/client.rb +168 -0
  67. data/lib/protobuf/rpc/connector.rb +19 -0
  68. data/lib/protobuf/rpc/connectors/base.rb +55 -0
  69. data/lib/protobuf/rpc/connectors/common.rb +176 -0
  70. data/lib/protobuf/rpc/connectors/socket.rb +73 -0
  71. data/lib/protobuf/rpc/connectors/zmq.rb +322 -0
  72. data/lib/protobuf/rpc/dynamic_discovery.pb.rb +49 -0
  73. data/lib/protobuf/rpc/env.rb +58 -0
  74. data/lib/protobuf/rpc/error.rb +28 -0
  75. data/lib/protobuf/rpc/error/client_error.rb +31 -0
  76. data/lib/protobuf/rpc/error/server_error.rb +43 -0
  77. data/lib/protobuf/rpc/middleware.rb +25 -0
  78. data/lib/protobuf/rpc/middleware/exception_handler.rb +36 -0
  79. data/lib/protobuf/rpc/middleware/logger.rb +91 -0
  80. data/lib/protobuf/rpc/middleware/request_decoder.rb +83 -0
  81. data/lib/protobuf/rpc/middleware/response_encoder.rb +88 -0
  82. data/lib/protobuf/rpc/middleware/runner.rb +18 -0
  83. data/lib/protobuf/rpc/rpc.pb.rb +55 -0
  84. data/lib/protobuf/rpc/server.rb +39 -0
  85. data/lib/protobuf/rpc/servers/socket/server.rb +123 -0
  86. data/lib/protobuf/rpc/servers/socket/worker.rb +56 -0
  87. data/lib/protobuf/rpc/servers/socket_runner.rb +40 -0
  88. data/lib/protobuf/rpc/servers/zmq/broker.rb +193 -0
  89. data/lib/protobuf/rpc/servers/zmq/server.rb +320 -0
  90. data/lib/protobuf/rpc/servers/zmq/util.rb +48 -0
  91. data/lib/protobuf/rpc/servers/zmq/worker.rb +104 -0
  92. data/lib/protobuf/rpc/servers/zmq_runner.rb +62 -0
  93. data/lib/protobuf/rpc/service.rb +179 -0
  94. data/lib/protobuf/rpc/service_directory.rb +253 -0
  95. data/lib/protobuf/rpc/service_dispatcher.rb +46 -0
  96. data/lib/protobuf/rpc/service_filters.rb +272 -0
  97. data/lib/protobuf/rpc/stat.rb +97 -0
  98. data/lib/protobuf/socket.rb +21 -0
  99. data/lib/protobuf/tasks.rb +1 -0
  100. data/lib/protobuf/tasks/compile.rake +61 -0
  101. data/lib/protobuf/version.rb +3 -0
  102. data/lib/protobuf/wire_type.rb +10 -0
  103. data/lib/protobuf/zmq.rb +21 -0
  104. data/proto/dynamic_discovery.proto +44 -0
  105. data/proto/google/protobuf/compiler/plugin.proto +147 -0
  106. data/proto/google/protobuf/descriptor.proto +620 -0
  107. data/proto/rpc.proto +62 -0
  108. data/protobuf.gemspec +51 -0
  109. data/spec/benchmark/tasks.rb +139 -0
  110. data/spec/bin/protoc-gen-ruby_spec.rb +23 -0
  111. data/spec/data/data.bin +3 -0
  112. data/spec/data/types.bin +0 -0
  113. data/spec/encoding/all_types_spec.rb +105 -0
  114. data/spec/encoding/extreme_values_spec.rb +0 -0
  115. data/spec/functional/class_inheritance_spec.rb +52 -0
  116. data/spec/functional/socket_server_spec.rb +59 -0
  117. data/spec/functional/zmq_server_spec.rb +105 -0
  118. data/spec/lib/protobuf/cli_spec.rb +273 -0
  119. data/spec/lib/protobuf/code_generator_spec.rb +60 -0
  120. data/spec/lib/protobuf/enum_spec.rb +265 -0
  121. data/spec/lib/protobuf/field/bool_field_spec.rb +51 -0
  122. data/spec/lib/protobuf/field/field_array_spec.rb +69 -0
  123. data/spec/lib/protobuf/field/float_field_spec.rb +55 -0
  124. data/spec/lib/protobuf/field/int32_field_spec.rb +89 -0
  125. data/spec/lib/protobuf/field/string_field_spec.rb +45 -0
  126. data/spec/lib/protobuf/field_spec.rb +191 -0
  127. data/spec/lib/protobuf/generators/base_spec.rb +84 -0
  128. data/spec/lib/protobuf/generators/enum_generator_spec.rb +73 -0
  129. data/spec/lib/protobuf/generators/extension_generator_spec.rb +42 -0
  130. data/spec/lib/protobuf/generators/field_generator_spec.rb +102 -0
  131. data/spec/lib/protobuf/generators/file_generator_spec.rb +32 -0
  132. data/spec/lib/protobuf/generators/message_generator_spec.rb +0 -0
  133. data/spec/lib/protobuf/generators/service_generator_spec.rb +46 -0
  134. data/spec/lib/protobuf/lifecycle_spec.rb +94 -0
  135. data/spec/lib/protobuf/message_spec.rb +526 -0
  136. data/spec/lib/protobuf/optionable_spec.rb +46 -0
  137. data/spec/lib/protobuf/rpc/client_spec.rb +66 -0
  138. data/spec/lib/protobuf/rpc/connector_spec.rb +26 -0
  139. data/spec/lib/protobuf/rpc/connectors/base_spec.rb +50 -0
  140. data/spec/lib/protobuf/rpc/connectors/common_spec.rb +170 -0
  141. data/spec/lib/protobuf/rpc/connectors/socket_spec.rb +36 -0
  142. data/spec/lib/protobuf/rpc/connectors/zmq_spec.rb +117 -0
  143. data/spec/lib/protobuf/rpc/middleware/exception_handler_spec.rb +62 -0
  144. data/spec/lib/protobuf/rpc/middleware/logger_spec.rb +49 -0
  145. data/spec/lib/protobuf/rpc/middleware/request_decoder_spec.rb +115 -0
  146. data/spec/lib/protobuf/rpc/middleware/response_encoder_spec.rb +75 -0
  147. data/spec/lib/protobuf/rpc/servers/socket_server_spec.rb +38 -0
  148. data/spec/lib/protobuf/rpc/servers/zmq/server_spec.rb +43 -0
  149. data/spec/lib/protobuf/rpc/servers/zmq/util_spec.rb +55 -0
  150. data/spec/lib/protobuf/rpc/servers/zmq/worker_spec.rb +35 -0
  151. data/spec/lib/protobuf/rpc/service_directory_spec.rb +293 -0
  152. data/spec/lib/protobuf/rpc/service_dispatcher_spec.rb +52 -0
  153. data/spec/lib/protobuf/rpc/service_filters_spec.rb +517 -0
  154. data/spec/lib/protobuf/rpc/service_spec.rb +162 -0
  155. data/spec/lib/protobuf/rpc/stat_spec.rb +68 -0
  156. data/spec/lib/protobuf_spec.rb +98 -0
  157. data/spec/spec_helper.rb +44 -0
  158. data/spec/support/all.rb +6 -0
  159. data/spec/support/packed_field.rb +22 -0
  160. data/spec/support/server.rb +64 -0
  161. data/spec/support/test/all_types.data.bin +0 -0
  162. data/spec/support/test/all_types.data.txt +119 -0
  163. data/spec/support/test/defaults.pb.rb +27 -0
  164. data/spec/support/test/defaults.proto +9 -0
  165. data/spec/support/test/enum.pb.rb +55 -0
  166. data/spec/support/test/enum.proto +34 -0
  167. data/spec/support/test/extended.pb.rb +18 -0
  168. data/spec/support/test/extended.proto +10 -0
  169. data/spec/support/test/extreme_values.data.bin +0 -0
  170. data/spec/support/test/google_unittest.pb.rb +537 -0
  171. data/spec/support/test/google_unittest.proto +713 -0
  172. data/spec/support/test/google_unittest_import.pb.rb +39 -0
  173. data/spec/support/test/google_unittest_import.proto +64 -0
  174. data/spec/support/test/google_unittest_import_public.pb.rb +10 -0
  175. data/spec/support/test/google_unittest_import_public.proto +38 -0
  176. data/spec/support/test/multi_field_extensions.pb.rb +58 -0
  177. data/spec/support/test/multi_field_extensions.proto +33 -0
  178. data/spec/support/test/resource.pb.rb +119 -0
  179. data/spec/support/test/resource.proto +94 -0
  180. data/spec/support/test/resource_service.rb +23 -0
  181. data/spec/support/test_app_file.rb +2 -0
  182. metadata +502 -0
@@ -0,0 +1,168 @@
1
+ require 'forwardable'
2
+ require 'protobuf'
3
+ require 'protobuf/logging'
4
+ require 'protobuf/rpc/error'
5
+ require 'protobuf/rpc/connector'
6
+
7
+ module Protobuf
8
+ module Rpc
9
+ class Client
10
+ extend Forwardable
11
+ include Protobuf::Logging
12
+
13
+ def_delegators :@connector, :options, :complete_cb, :success_cb, :failure_cb
14
+ attr_reader :connector
15
+
16
+ # Create a new client with default options (defined in ClientConnection)
17
+ # See Service#client for a more convenient way to create a client, as well
18
+ # as Client#method_missing defined below.
19
+ #
20
+ # request = WidgetFindRequest.new
21
+ # client = Client.new({
22
+ # :service => WidgetService,
23
+ # :method => "find",
24
+ # :request_type => "WidgetFindRequest",
25
+ # :response_type => "WidgetList",
26
+ # :request => request
27
+ # })
28
+ #
29
+ def initialize(options = {})
30
+ fail "Invalid client configuration. Service must be defined." if options[:service].nil?
31
+ @connector = Connector.connector_for_client.new(options)
32
+ logger.debug { sign_message("Initialized with options: #{options.inspect}") }
33
+ end
34
+
35
+ def log_signature
36
+ @_log_signature ||= "[client-#{self.class}]"
37
+ end
38
+
39
+ # Set a complete callback on the client to return the object (self).
40
+ #
41
+ # client = Client.new(:service => WidgetService)
42
+ # client.on_complete {|obj| ... }
43
+ #
44
+ def on_complete(&complete_cb)
45
+ @connector.complete_cb = complete_cb
46
+ end
47
+
48
+ def on_complete=(callable)
49
+ if !callable.nil? && !callable.respond_to?(:call) && callable.arity != 1
50
+ fail "callable must take a single argument and respond to :call"
51
+ end
52
+
53
+ @connector.complete_cb = callable
54
+ end
55
+
56
+ # Set a failure callback on the client to return the
57
+ # error returned by the service, if any. If this callback
58
+ # is called, success_cb will NOT be called.
59
+ #
60
+ # client = Client.new(:service => WidgetService)
61
+ # client.on_failure {|err| ... }
62
+ #
63
+ def on_failure(&failure_cb)
64
+ @connector.failure_cb = failure_cb
65
+ end
66
+
67
+ def on_failure=(callable)
68
+ if !callable.nil? && !callable.respond_to?(:call) && callable.arity != 1
69
+ fail "Callable must take a single argument and respond to :call"
70
+ end
71
+
72
+ @connector.failure_cb = callable
73
+ end
74
+
75
+ # Set a success callback on the client to return the
76
+ # successful response from the service when it is returned.
77
+ # If this callback is called, failure_cb will NOT be called.
78
+ #
79
+ # client = Client.new(:service => WidgetService)
80
+ # client.on_success {|res| ... }
81
+ #
82
+ def on_success(&success_cb)
83
+ @connector.success_cb = success_cb
84
+ end
85
+
86
+ def on_success=(callable)
87
+ if !callable.nil? && !callable.respond_to?(:call) && callable.arity != 1
88
+ fail "Callable must take a single argument and respond to :call"
89
+ end
90
+
91
+ @connector.success_cb = callable
92
+ end
93
+
94
+ # Provides a mechanism to call the service method against the client
95
+ # which will automatically setup the service_class and method_name
96
+ # in the wrapper protobuf request.
97
+ #
98
+ # # The :find method is not defined by Client which will trigger method_missing
99
+ # Client.new(:service => WidgetService).find do |c|
100
+ # # This block will be invoked before the request is made
101
+ # # `c` in this case is the client object you created above
102
+ # c.on_success {|res| ... }
103
+ # c.on_failure {|err| ... }
104
+ # end
105
+ #
106
+ def method_missing(method_name, *params)
107
+ service = options[:service]
108
+ if service.rpc_method?(method_name)
109
+ logger.debug { sign_message("#{service.name}##{method_name}") }
110
+ rpc = service.rpcs[method_name.to_sym]
111
+
112
+ options[:request_type] = rpc.request_type
113
+ logger.debug { sign_message("Request Type: #{options[:request_type].name}") }
114
+
115
+ options[:response_type] = rpc.response_type
116
+ logger.debug { sign_message("Response Type: #{options[:response_type].name}") }
117
+
118
+ options[:method] = method_name.to_s
119
+ options[:request] = params[0].is_a?(Hash) ? options[:request_type].new(params[0]) : params[0]
120
+ logger.debug { sign_message("Request Data: #{options[:request].inspect}") }
121
+
122
+ # Call client to setup on_success and on_failure event callbacks
123
+ if block_given?
124
+ logger.debug { sign_message("client setup callback given, invoking") }
125
+ yield(self)
126
+ else
127
+ logger.debug { sign_message("no block given for callbacks") }
128
+ end
129
+
130
+ send_request
131
+ else
132
+ logger.error { sign_message("#{service.name}##{method_name} not rpc method, passing to super") }
133
+ super(method_name, *params)
134
+ end
135
+ end
136
+
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
+ end
165
+
166
+ ActiveSupport.run_load_hooks(:protobuf_rpc_client, Client)
167
+ end
168
+ end
@@ -0,0 +1,19 @@
1
+ require 'protobuf'
2
+
3
+ module Protobuf
4
+ module Rpc
5
+ class Connector
6
+
7
+ # Returns a connector class for the pre-defined connector_type.
8
+ def self.connector_for_client
9
+ case ::Protobuf.connector_type
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,55 @@
1
+ require 'timeout'
2
+ require 'protobuf/logging'
3
+ require 'protobuf/rpc/rpc.pb'
4
+ require 'protobuf/rpc/buffer'
5
+ require 'protobuf/rpc/error'
6
+ require 'protobuf/rpc/stat'
7
+ require 'protobuf/rpc/connectors/common'
8
+
9
+ module Protobuf
10
+ module Rpc
11
+ module Connectors
12
+ DEFAULT_OPTIONS = {
13
+ :service => nil, # Fully-qualified Service class
14
+ :method => nil, # Service method to invoke
15
+ :host => '127.0.0.1', # The hostname or address of the service (usually overridden)
16
+ :port => '9399', # The port of the service (usually overridden or pre-configured)
17
+ :request => nil, # The request object sent by the client
18
+ :request_type => nil, # The request type expected by the client
19
+ :response_type => nil, # The response type expected by the client
20
+ :timeout => nil, # The timeout for the request, also handled by client.rb
21
+ :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
+ }
24
+
25
+ class Base
26
+ include Protobuf::Logging
27
+
28
+ attr_reader :options
29
+ attr_accessor :success_cb, :failure_cb, :complete_cb
30
+
31
+ def initialize(options)
32
+ @options = DEFAULT_OPTIONS.merge(options)
33
+ @stats = ::Protobuf::Rpc::Stat.new(:CLIENT)
34
+ end
35
+
36
+ def first_alive_load_balance?
37
+ ENV.key?("PB_FIRST_ALIVE_LOAD_BALANCE") ||
38
+ options[:first_alive_load_balance]
39
+ end
40
+
41
+ def send_request
42
+ fail 'If you inherit a Connector from Base you must implement send_request'
43
+ end
44
+
45
+ def ping_port
46
+ @ping_port ||= ENV["PB_RPC_PING_PORT"]
47
+ end
48
+
49
+ def ping_port_enabled?
50
+ ENV.key?("PB_RPC_PING_PORT")
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,176 @@
1
+ require 'protobuf'
2
+
3
+ module Protobuf
4
+ module Rpc
5
+ module Connectors
6
+ module Common
7
+
8
+ attr_reader :error
9
+
10
+ def any_callbacks?
11
+ [@complete_cb, @failure_cb, @success_cb].any?
12
+ end
13
+
14
+ def request_caller
15
+ @options[:client_host] || ::Protobuf.client_host
16
+ end
17
+
18
+ def complete
19
+ @stats.stop
20
+ logger.info { @stats.to_s }
21
+ logger.debug { sign_message('Response proceessing complete') }
22
+ @complete_cb.call(self) unless @complete_cb.nil?
23
+ rescue => e
24
+ logger.error { sign_message('Complete callback error encountered') }
25
+ log_exception(e)
26
+ raise
27
+ end
28
+
29
+ def data_callback(data)
30
+ logger.debug { sign_message('Using data_callback') }
31
+ @used_data_callback = true
32
+ @data = data
33
+ end
34
+
35
+ # All failures should be routed through this method.
36
+ #
37
+ # @param [Symbol] code The code we're using (see ::Protobuf::Socketrpc::ErrorReason)
38
+ # @param [String] message The error message
39
+ def failure(code, message)
40
+ @error = ClientError.new
41
+ @error.code = Protobuf::Socketrpc::ErrorReason.fetch(code)
42
+ @error.message = message
43
+ logger.debug { sign_message("Server failed request (invoking on_failure): #{@error.inspect}") }
44
+
45
+ @failure_cb.call(@error) unless @failure_cb.nil?
46
+ rescue => e
47
+ logger.error { sign_message("Failure callback error encountered") }
48
+ log_exception(e)
49
+ raise
50
+ ensure
51
+ complete
52
+ end
53
+
54
+ def initialize_stats
55
+ @stats = ::Protobuf::Rpc::Stat.new(:CLIENT)
56
+ @stats.server = [@options[:port], @options[:host]]
57
+ @stats.service = @options[:service].name
58
+ @stats.method_name = @options[:method].to_s
59
+ rescue => ex
60
+ log_exception(ex)
61
+ failure(:RPC_ERROR, "Invalid stats configuration. #{ex.message}")
62
+ end
63
+
64
+ def log_signature
65
+ @_log_signature ||= "[client-#{self.class}]"
66
+ end
67
+
68
+ def parse_response
69
+ # Close up the connection as we no longer need it
70
+ close_connection
71
+
72
+ logger.debug { sign_message("Parsing response from server (connection closed)") }
73
+
74
+ # Parse out the raw response
75
+ @stats.response_size = @response_data.size unless @response_data.nil?
76
+ response_wrapper = Protobuf::Socketrpc::Response.decode(@response_data)
77
+
78
+ # Determine success or failure based on parsed data
79
+ if response_wrapper.field?(:error_reason)
80
+ logger.debug { sign_message("Error response parsed") }
81
+
82
+ # fail the call if we already know the client is failed
83
+ # (don't try to parse out the response payload)
84
+ failure(response_wrapper.error_reason, response_wrapper.error)
85
+ else
86
+ logger.debug { sign_message("Successful response parsed") }
87
+
88
+ # Ensure client_response is an instance
89
+ parsed = @options[:response_type].decode(response_wrapper.response_proto.to_s)
90
+
91
+ if parsed.nil? && !response_wrapper.field?(:error_reason)
92
+ failure(:BAD_RESPONSE_PROTO, 'Unable to parse response from server')
93
+ else
94
+ verify_callbacks
95
+ succeed(parsed)
96
+ return @data if @used_data_callback
97
+ end
98
+ end
99
+ end
100
+
101
+ def post_init
102
+ send_data unless error?
103
+ rescue => e
104
+ failure(:RPC_ERROR, "Connection error: #{e.message}")
105
+ end
106
+
107
+ def request_bytes
108
+ validate_request_type!
109
+ fields = { :service_name => @options[:service].name,
110
+ :method_name => @options[:method].to_s,
111
+ :request_proto => @options[:request],
112
+ :caller => request_caller }
113
+
114
+ return ::Protobuf::Socketrpc::Request.encode(fields)
115
+ rescue => e
116
+ failure(:INVALID_REQUEST_PROTO, "Could not set request proto: #{e.message}")
117
+ end
118
+
119
+ def setup_connection
120
+ initialize_stats
121
+ @request_data = request_bytes
122
+ @stats.request_size = request_bytes.size
123
+ end
124
+
125
+ def succeed(response)
126
+ logger.debug { sign_message("Server succeeded request (invoking on_success)") }
127
+ @success_cb.call(response) unless @success_cb.nil?
128
+ rescue => e
129
+ logger.error { sign_message("Success callback error encountered") }
130
+ log_exception(e)
131
+ failure(:RPC_ERROR, "An exception occurred while calling on_success: #{e.message}")
132
+ ensure
133
+ complete
134
+ end
135
+
136
+ def timeout
137
+ if options[:timeout]
138
+ options[:timeout]
139
+ else
140
+ 300 # seconds
141
+ end
142
+ end
143
+
144
+ # Wrap the given block in a timeout of the configured number of seconds.
145
+ #
146
+ def timeout_wrap(&block)
147
+ ::Timeout.timeout(timeout, &block)
148
+ rescue ::Timeout::Error
149
+ failure(:RPC_FAILED, "The server took longer than #{timeout} seconds to respond")
150
+ end
151
+
152
+ def validate_request_type!
153
+ unless @options[:request].class == @options[:request_type]
154
+ expected = @options[:request_type].name
155
+ actual = @options[:request].class.name
156
+ failure(:INVALID_REQUEST_PROTO, "Expected request type to be type of #{expected}, got #{actual} instead")
157
+ end
158
+ end
159
+
160
+ def verify_callbacks
161
+ unless any_callbacks?
162
+ logger.debug { sign_message("No callbacks set, using data_callback") }
163
+ @success_cb = @failure_cb = method(:data_callback)
164
+ end
165
+ end
166
+
167
+ def verify_options!
168
+ # Verify the options that are necessary and merge them in
169
+ [:service, :method, :host, :port].each do |opt|
170
+ failure(:RPC_ERROR, "Invalid client connection configuration. #{opt} must be a defined option.") if @options[opt].nil?
171
+ end
172
+ end
173
+ end
174
+ end
175
+ end
176
+ 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::Logging
9
+
10
+ def send_request
11
+ timeout_wrap do
12
+ setup_connection
13
+ connect_to_rpc_server
14
+ post_init
15
+ read_response
16
+ end
17
+ end
18
+
19
+ def log_signature
20
+ @_log_signature ||= "[client-#{self.class}]"
21
+ end
22
+
23
+ private
24
+
25
+ def close_connection
26
+ @socket.close
27
+ logger.debug { sign_message('Connector closed') }
28
+ end
29
+
30
+ def connect_to_rpc_server
31
+ @socket ||= TCPSocket.new(options[:host], options[:port])
32
+ logger.debug { sign_message("Connection established #{options[:host]}:#{options[:port]}") }
33
+ end
34
+
35
+ # Method to determine error state, must be used with Connector api
36
+ def error?
37
+ return true if @error
38
+ logger.debug { sign_message("Error state : #{@socket.closed?}") }
39
+ @socket.closed?
40
+ end
41
+
42
+ def read_data
43
+ size_io = StringIO.new
44
+
45
+ until (size_reader = @socket.getc) == "-"
46
+ size_io << size_reader
47
+ end
48
+ str_size_io = size_io.string
49
+
50
+ "#{str_size_io}-#{@socket.read(str_size_io.to_i)}"
51
+ end
52
+
53
+ def read_response
54
+ logger.debug { sign_message("error? is #{error?}") }
55
+ return if error?
56
+ response_buffer = ::Protobuf::Rpc::Buffer.new(:read)
57
+ response_buffer << read_data
58
+ @response_data = response_buffer.data
59
+ parse_response if response_buffer.flushed?
60
+ end
61
+
62
+ def send_data
63
+ return if error?
64
+ request_buffer = ::Protobuf::Rpc::Buffer.new(:write)
65
+ request_buffer.set_data(@request_data)
66
+ @socket.write(request_buffer.write)
67
+ @socket.flush
68
+ logger.debug { sign_message("write closed") }
69
+ end
70
+ end
71
+ end
72
+ end
73
+ end