protobuf 1.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.
Files changed (113) hide show
  1. data/.gitignore +5 -0
  2. data/Gemfile +3 -0
  3. data/Gemfile.lock +28 -0
  4. data/README.md +216 -0
  5. data/Rakefile +1 -0
  6. data/bin/rpc_server +117 -0
  7. data/bin/rprotoc +46 -0
  8. data/examples/addressbook.pb.rb +55 -0
  9. data/examples/addressbook.proto +24 -0
  10. data/examples/reading_a_message.rb +32 -0
  11. data/examples/writing_a_message.rb +46 -0
  12. data/lib/protobuf.rb +6 -0
  13. data/lib/protobuf/common/exceptions.rb +11 -0
  14. data/lib/protobuf/common/logger.rb +64 -0
  15. data/lib/protobuf/common/util.rb +59 -0
  16. data/lib/protobuf/common/wire_type.rb +10 -0
  17. data/lib/protobuf/compiler/compiler.rb +52 -0
  18. data/lib/protobuf/compiler/nodes.rb +323 -0
  19. data/lib/protobuf/compiler/proto.y +216 -0
  20. data/lib/protobuf/compiler/proto2.ebnf +79 -0
  21. data/lib/protobuf/compiler/proto_parser.rb +1425 -0
  22. data/lib/protobuf/compiler/template/rpc_bin.erb +4 -0
  23. data/lib/protobuf/compiler/template/rpc_client.erb +18 -0
  24. data/lib/protobuf/compiler/template/rpc_service.erb +25 -0
  25. data/lib/protobuf/compiler/template/rpc_service_implementation.erb +42 -0
  26. data/lib/protobuf/compiler/visitors.rb +302 -0
  27. data/lib/protobuf/descriptor/descriptor.proto +286 -0
  28. data/lib/protobuf/descriptor/descriptor.rb +55 -0
  29. data/lib/protobuf/descriptor/descriptor_builder.rb +143 -0
  30. data/lib/protobuf/descriptor/descriptor_proto.rb +138 -0
  31. data/lib/protobuf/descriptor/enum_descriptor.rb +33 -0
  32. data/lib/protobuf/descriptor/field_descriptor.rb +49 -0
  33. data/lib/protobuf/descriptor/file_descriptor.rb +37 -0
  34. data/lib/protobuf/message/decoder.rb +83 -0
  35. data/lib/protobuf/message/encoder.rb +46 -0
  36. data/lib/protobuf/message/enum.rb +62 -0
  37. data/lib/protobuf/message/extend.rb +8 -0
  38. data/lib/protobuf/message/field.rb +701 -0
  39. data/lib/protobuf/message/message.rb +402 -0
  40. data/lib/protobuf/message/protoable.rb +38 -0
  41. data/lib/protobuf/rpc/buffer.rb +74 -0
  42. data/lib/protobuf/rpc/client.rb +268 -0
  43. data/lib/protobuf/rpc/client_connection.rb +225 -0
  44. data/lib/protobuf/rpc/error.rb +34 -0
  45. data/lib/protobuf/rpc/error/client_error.rb +31 -0
  46. data/lib/protobuf/rpc/error/server_error.rb +43 -0
  47. data/lib/protobuf/rpc/rpc.pb.rb +107 -0
  48. data/lib/protobuf/rpc/server.rb +183 -0
  49. data/lib/protobuf/rpc/service.rb +244 -0
  50. data/lib/protobuf/rpc/stat.rb +70 -0
  51. data/lib/protobuf/version.rb +3 -0
  52. data/proto/rpc.proto +73 -0
  53. data/protobuf.gemspec +25 -0
  54. data/script/mk_parser +2 -0
  55. data/spec/functional/embedded_service_spec.rb +7 -0
  56. data/spec/proto/test.pb.rb +31 -0
  57. data/spec/proto/test.proto +31 -0
  58. data/spec/proto/test_service.rb +30 -0
  59. data/spec/proto/test_service_impl.rb +17 -0
  60. data/spec/spec_helper.rb +26 -0
  61. data/spec/unit/client_spec.rb +128 -0
  62. data/spec/unit/common/logger_spec.rb +121 -0
  63. data/spec/unit/enum_spec.rb +13 -0
  64. data/spec/unit/message_spec.rb +67 -0
  65. data/spec/unit/server_spec.rb +27 -0
  66. data/spec/unit/service_spec.rb +75 -0
  67. data/test/check_unbuild.rb +30 -0
  68. data/test/data/data.bin +3 -0
  69. data/test/data/data_source.py +14 -0
  70. data/test/data/types.bin +0 -0
  71. data/test/data/types_source.py +22 -0
  72. data/test/data/unk.png +0 -0
  73. data/test/proto/addressbook.pb.rb +66 -0
  74. data/test/proto/addressbook.proto +33 -0
  75. data/test/proto/addressbook_base.pb.rb +58 -0
  76. data/test/proto/addressbook_base.proto +26 -0
  77. data/test/proto/addressbook_ext.pb.rb +20 -0
  78. data/test/proto/addressbook_ext.proto +6 -0
  79. data/test/proto/collision.pb.rb +17 -0
  80. data/test/proto/collision.proto +5 -0
  81. data/test/proto/ext_collision.pb.rb +24 -0
  82. data/test/proto/ext_collision.proto +8 -0
  83. data/test/proto/ext_range.pb.rb +22 -0
  84. data/test/proto/ext_range.proto +7 -0
  85. data/test/proto/float_default.proto +10 -0
  86. data/test/proto/lowercase.pb.rb +30 -0
  87. data/test/proto/lowercase.proto +9 -0
  88. data/test/proto/merge.pb.rb +39 -0
  89. data/test/proto/merge.proto +15 -0
  90. data/test/proto/nested.pb.rb +30 -0
  91. data/test/proto/nested.proto +9 -0
  92. data/test/proto/optional_field.pb.rb +35 -0
  93. data/test/proto/optional_field.proto +12 -0
  94. data/test/proto/packed.pb.rb +22 -0
  95. data/test/proto/packed.proto +6 -0
  96. data/test/proto/rpc.proto +6 -0
  97. data/test/proto/types.pb.rb +84 -0
  98. data/test/proto/types.proto +37 -0
  99. data/test/test_addressbook.rb +56 -0
  100. data/test/test_compiler.rb +325 -0
  101. data/test/test_descriptor.rb +122 -0
  102. data/test/test_enum_value.rb +41 -0
  103. data/test/test_extension.rb +36 -0
  104. data/test/test_lowercase.rb +11 -0
  105. data/test/test_message.rb +128 -0
  106. data/test/test_optional_field.rb +103 -0
  107. data/test/test_packed_field.rb +40 -0
  108. data/test/test_parse.rb +15 -0
  109. data/test/test_repeated_types.rb +132 -0
  110. data/test/test_serialize.rb +61 -0
  111. data/test/test_standard_message.rb +96 -0
  112. data/test/test_types.rb +226 -0
  113. metadata +261 -0
@@ -0,0 +1,268 @@
1
+ require 'eventmachine'
2
+ require 'protobuf/common/logger'
3
+ require 'protobuf/rpc/client_connection'
4
+ require 'protobuf/rpc/buffer'
5
+ require 'protobuf/rpc/error'
6
+ require 'timeout'
7
+
8
+ module Protobuf
9
+ module Rpc
10
+ class Client
11
+ include Protobuf::Logger::LogMethods
12
+
13
+ attr_reader :error, :options, :do_block
14
+
15
+ # Create a new client with default options (defined in ClientConnection)
16
+ # See Service#client for a more convenient way to create a client, as well
17
+ # as Client#method_missing defined below.
18
+ #
19
+ # request = WidgetFindRequest.new
20
+ # client = Client.new({
21
+ # :service => WidgetService,
22
+ # :method => "find",
23
+ # :request_type => "WidgetFindRequest",
24
+ # :response_type => "WidgetList",
25
+ # :request => request
26
+ # })
27
+ #
28
+ def initialize options={}
29
+ raise "Invalid client configuration. Service must be defined." if !options[:service] || options[:service].nil?
30
+ @error = {}
31
+ @options = ClientConnection::DEFAULT_OPTIONS.merge(options)
32
+ @success_callback = nil
33
+ @failure_callback = nil
34
+ @do_block = !@options[:async]
35
+ log_debug '[client] Initialized with options: %s' % @options.inspect
36
+ end
37
+
38
+ # Set a success callback on the client to return the
39
+ # successful response from the service when it is returned.
40
+ # If this callback is called, failure_callback will NOT be called.
41
+ # Callback is called regardless of :async setting.
42
+ #
43
+ # Client(:service => WidgetService).new.find do |c|
44
+ # c.on_success {|res| ... }
45
+ # end
46
+ #
47
+ def on_success &success_callback
48
+ @success_callback = success_callback
49
+ end
50
+
51
+ # Set a failure callback on the client to return the
52
+ # error returned by the service, if any. If this callback
53
+ # is called, success_callback will NOT be called.
54
+ # Callback is called regardless of :async setting.
55
+ #
56
+ # Client(:service => WidgetService).new.find do |c|
57
+ # c.on_failure {|err| ... }
58
+ # end
59
+ #
60
+ def on_failure &failure_callback
61
+ @failure_callback = failure_callback
62
+ end
63
+
64
+ # Provides a mechanism to call the service method against the client
65
+ # and will automatically setup the service_class and method_name
66
+ # in the wrapper protobuf request.
67
+ #
68
+ # # find is not defined by Client which will trigger method_missing
69
+ # Client(:service => WidgetService).new.find
70
+ #
71
+ def method_missing method, *params, &client_callback
72
+ service = @options[:service]
73
+ unless service.rpcs[service].keys.include?(method)
74
+ log_error '[client] %s#%s not rpc method, passing to super' % [service.name, method.to_s]
75
+ super method, *params
76
+ else
77
+ log_debug '[client] %s#%s' % [service.name, method.to_s]
78
+ rpc = service.rpcs[service][method.to_sym]
79
+ @options[:request_type] = rpc.request_type
80
+ log_debug '[client] Request Type: %s' % @options[:request_type].name
81
+ @options[:response_type] = rpc.response_type
82
+ log_debug '[client] Response Type: %s' % @options[:response_type].name
83
+ @options[:method] = method.to_s
84
+ @options[:request] = params[0].is_a?(Hash) ? @options[:request_type].new(params[0]) : params[0]
85
+ log_debug '[client] Request Data: %s' % @options[:request].inspect
86
+
87
+ #### TODO remove first part here once we are able to convert everything to the new event based way of handling success/failure
88
+ unless client_callback.nil?
89
+ if client_callback.arity == 2
90
+ @options[:version] = 1.0
91
+ log_debug '[client] version = 1.0'
92
+
93
+ log_warn deprecation_warning
94
+ STDOUT.puts deprecation_warning unless Protobuf::Logger.configured?
95
+
96
+ on_success {|res| client_callback.call(self, res) }
97
+ on_failure {|err| client_callback.call(self, nil) }
98
+ else
99
+ ### TODO Replace block above with this once all client definitions use new event driven approach
100
+ # Call client to setup on_success and on_failure event callbacks
101
+ @options[:version] = 2.0
102
+ log_debug '[client] version = 2.0'
103
+ client_callback.call(self)
104
+ end
105
+ else
106
+ log_debug '[client] no callbacks given'
107
+ end
108
+
109
+ send_request
110
+ end
111
+ end
112
+
113
+ # Send the request to the service through eventmachine.
114
+ # This method is usually never called directly
115
+ # but is invoked by method_missing (see docs above).
116
+ #
117
+ # request = WidgetFindRequest.new
118
+ # client = Client.new({
119
+ # :service => WidgetService,
120
+ # :method => "find",
121
+ # :request_type => "WidgetFindRequest",
122
+ # :response_type => "WidgetList",
123
+ # :request => request
124
+ # })
125
+ #
126
+ # client.on_success do |res|
127
+ # res.widgets.each{|w| puts w.inspect }
128
+ # end
129
+ #
130
+ # client.on_failure do |err|
131
+ # puts err.message
132
+ # end
133
+ #
134
+ # client.send_request
135
+ #
136
+ def send_request
137
+ Thread.new { EM.run } unless EM.reactor_running?
138
+
139
+ EM.schedule do
140
+ log_debug '[client] Scheduling client connection to be created on next tick'
141
+ connection = ClientConnection.connect @options, &ensure_callback
142
+ connection.on_success &@success_callback unless @success_callback.nil?
143
+ connection.on_failure &ensure_callback
144
+ connection.on_complete { @do_block = false } if @do_block
145
+ log_debug '[client] Connection scheduled'
146
+ end
147
+
148
+ return synchronize_or_return
149
+ end
150
+
151
+ # Block the client call to send_request from returning if
152
+ # async is false, otherwise do nothing.
153
+ # Simple blocking algorithm to sleep while @do_block is set to true.
154
+ # The eventmachine connection has a registered callback to flip
155
+ # @do_block to false as soon as the response has been received and processed.
156
+ # If any errors are returned an appropriate RPC_ERROR is sent back to the client
157
+ # through the failure callback.
158
+ #
159
+ def synchronize_or_return
160
+ if @do_block
161
+ begin
162
+ Timeout.timeout(@options[:timeout]) do
163
+ sleep 0.5 while @do_block
164
+ true
165
+ end
166
+ rescue => ex
167
+ log_error 'An exception occurred while waiting for server response:'
168
+ log_error ex.message
169
+ log_error ex.backtrace.join("\n")
170
+
171
+ if ex.is_a?(Timeout::Error)
172
+ message = 'Client timeout of %d seconds expired' % @options[:timeout]
173
+ else
174
+ message = 'Client failed: %s' % ex.message
175
+ end
176
+
177
+ err = ClientError.new(Protobuf::Socketrpc::ErrorReason::RPC_ERROR, message)
178
+ ensure_callback.call(err)
179
+ end
180
+ else
181
+ true
182
+ end
183
+ end
184
+
185
+ # Returns a proc that ensures any errors will be returned to the client
186
+ #
187
+ # If a failure callback was set, just use that as a direct assignment
188
+ # otherwise implement one here that simply throws an exception, since we
189
+ # don't want to swallow the black holes.
190
+ #
191
+ # TODO: remove "else" portion below once 1.0 is gone
192
+ #
193
+ def ensure_callback
194
+ @ensure_callback ||= begin
195
+ if @options[:version] == 2.0
196
+ if @failure_callback.nil?
197
+ cbk = proc do |error|
198
+ raise '%s: %s' % [error.code.name, error.message]
199
+ end
200
+ else
201
+ cbk = @failure_callback
202
+ end
203
+ else
204
+ cbk = proc do |error|
205
+ @error = error
206
+ @failure_callback ? @failure_callback.call(self) : raise('%s: %s' % [error.code.name, error.message])
207
+ end
208
+ end
209
+ cbk
210
+ end
211
+ end
212
+
213
+ # Annoying deprecation warning to print if you are still on v1 DSL
214
+ def deprecation_warning
215
+ %Q{
216
+ ##################################################
217
+ # Deprecation Warning - Upgrade Client Callbacks
218
+ # ==============================================
219
+ #
220
+ # You are attempting to use two block arguments (presumably client and response)
221
+ # in your client callback for the call to #{@options[:service].name}.client.#{@options[:method]}.
222
+ #
223
+ # The next version of ruby-protobuf will completely remove the
224
+ # style of client calls that accepts two arguments in favor of a more explicit evented approach.
225
+ #
226
+ # You should refactor the code before upgrading to the next version of this gem. An example of callback style v1:
227
+ #
228
+ # #{@options[:service]}.client.#{@options[:method]}(request) do |client, response|
229
+ # if client.failed?
230
+ # # do something with client.error or client.message
231
+ # else
232
+ # # do something with response
233
+ # end
234
+ # end
235
+ #
236
+ # Refactor the previous example of callback style v1 usage to v2 with the following:
237
+ #
238
+ # #{@options[:service]}.client.#{@options[:method]}(request) do |c|
239
+ # c.on_failure do |error|
240
+ # # do something with error.code or error.message
241
+ # end
242
+ # c.on_success do |response|
243
+ # # do something with response
244
+ # end
245
+ # end
246
+ #
247
+ ##################################################
248
+ }
249
+ end
250
+
251
+ # Controller error/failure methods
252
+ # TODO remove these when v1 is gone
253
+ def failed?
254
+ !@error.nil? and !@error[:code].nil?
255
+ end
256
+ def error
257
+ @error[:message] if failed?
258
+ end
259
+ def error_reason
260
+ Protobuf::Socketrpc::ErrorReason.name_by_value(@error[:code]).to_s if failed?
261
+ end
262
+ def error_message
263
+ "%s: %s" % [error_reason, error] if failed?
264
+ end
265
+
266
+ end
267
+ end
268
+ end
@@ -0,0 +1,225 @@
1
+ require 'eventmachine'
2
+ require 'protobuf/common/logger'
3
+ require 'protobuf/rpc/rpc.pb'
4
+ require 'protobuf/rpc/buffer'
5
+ require 'protobuf/rpc/error'
6
+ require 'protobuf/rpc/stat'
7
+
8
+ # Handles client connections to the server
9
+ module Protobuf
10
+ module Rpc
11
+ ClientError = Struct.new("ClientError", :code, :message)
12
+
13
+ class ClientConnection < EM::Connection
14
+ include Protobuf::Logger::LogMethods
15
+
16
+ attr_reader :options, :request, :response
17
+ attr_reader :error, :error_reason, :error_message
18
+
19
+ DEFAULT_OPTIONS = {
20
+ :service => nil, # Service to invoke
21
+ :method => nil, # Service method to call
22
+ :host => 'localhost', # A default host (usually overridden)
23
+ :port => '9938', # A default port (usually overridden)
24
+ :request => nil, # The request object sent by the client
25
+ :request_type => nil, # The request type expected by the client
26
+ :response_type => nil, # The response type expected by the client
27
+ :async => false, # Whether or not to block a client call, this is actually handled by client.rb
28
+ :timeout => 30 # The default timeout for the request, also handled by client.rb
29
+ }
30
+
31
+ # For state tracking
32
+ STATES = {
33
+ :pending => 0,
34
+ :succeeded => 1,
35
+ :failed => 2,
36
+ :completed => 3
37
+ }
38
+
39
+ def self.connect options={}
40
+ options = DEFAULT_OPTIONS.merge(options)
41
+ Protobuf::Logger.debug '[client-cnxn] Connecting to server: %s' % options.inspect
42
+ host = options[:host]
43
+ port = options[:port]
44
+ EventMachine.connect host, port, self, options
45
+ end
46
+
47
+ def initialize options={}, &failure_callback
48
+ @failure_callback = failure_callback
49
+
50
+ # Verify the options that are necessary and merge them in
51
+ [:service, :method, :host, :port].each do |opt|
52
+ fail(:RPC_ERROR, "Invalid client connection configuration. #{opt} must be a defined option.") if !options[opt] || options[opt].nil?
53
+ end
54
+ @options = DEFAULT_OPTIONS.merge(options)
55
+ log_debug '[client-cnxn] Client Initialized: %s' % options.inspect
56
+
57
+ @error = ClientError.new
58
+ @success_callback = nil
59
+ @state = STATES[:pending]
60
+
61
+ @stats = Protobuf::Rpc::Stat.new(:CLIENT, true)
62
+ @stats.server = [@options[:port], @options[:host]]
63
+ @stats.service = @options[:service].name
64
+ @stats.method = @options[:method]
65
+ rescue
66
+ fail(:RPC_ERROR, 'Failed to initialize connection: %s' % $!.message) unless failed?
67
+ end
68
+
69
+ # Success callback registration
70
+ def on_success &success_callback
71
+ @success_callback = success_callback
72
+ end
73
+
74
+ # Failure callback registration
75
+ def on_failure &failure_callback
76
+ @failure_callback = failure_callback
77
+ end
78
+
79
+ # Completion callback registration
80
+ def on_complete &complete_callback
81
+ @complete_callback = complete_callback
82
+ end
83
+
84
+ # Called after the EM.connect
85
+ def connection_completed
86
+ log_debug '[client-cnxn] Established server connection, sending request'
87
+ send_request unless error?
88
+ rescue
89
+ fail(:RPC_ERROR, 'Connection error: %s' % $!.message) unless failed?
90
+ end
91
+
92
+ # Setup the read buffer for data coming back
93
+ def post_init
94
+ log_debug '[client-cnxn] Post init, new read buffer created'
95
+ @buffer = Protobuf::Rpc::Buffer.new :read
96
+ rescue
97
+ fail(:RPC_ERROR, 'Connection error: %s' % $!.message) unless failed?
98
+ end
99
+
100
+ def receive_data data
101
+ log_debug '[client-cnxn] receive_data: %s' % data
102
+ @buffer << data
103
+ parse_response if @buffer.flushed?
104
+ end
105
+
106
+ def pending?
107
+ @state == STATES[:pending]
108
+ end
109
+
110
+ def succeeded?
111
+ @state == STATES[:succeeded]
112
+ end
113
+
114
+ def failed?
115
+ @state == STATES[:failed]
116
+ end
117
+
118
+ def completed?
119
+ @state == STATES[:completed]
120
+ end
121
+
122
+ private
123
+
124
+ # Sends the request to the server, invoked by the connection_completed event
125
+ def send_request
126
+ request_wrapper = Protobuf::Socketrpc::Request.new
127
+ request_wrapper.service_name = @options[:service].name
128
+ request_wrapper.method_name = @options[:method].to_s
129
+
130
+ if @options[:request].class == @options[:request_type]
131
+ request_wrapper.request_proto = @options[:request].serialize_to_string
132
+ else
133
+ expected = @options[:request_type].name
134
+ actual = @options[:request].class.name
135
+ fail :INVALID_REQUEST_PROTO, 'Expected request type to be type of %s, got %s instead' % [expected, actual]
136
+ end
137
+
138
+ log_debug '[client-cnxn] Sending Request: %s' % request_wrapper.inspect
139
+ request_buffer = Protobuf::Rpc::Buffer.new(:write, request_wrapper)
140
+ send_data(request_buffer.write)
141
+ @stats.request_size = request_buffer.size
142
+ end
143
+
144
+ def parse_response
145
+ # Close up the connection as we no longer need it
146
+ close_connection
147
+
148
+ log_debug '[client-cnxn] Parsing response from server (connection closed)'
149
+ @stats.response_size = @buffer.size
150
+
151
+ # Parse out the raw response
152
+ response_wrapper = Protobuf::Socketrpc::Response.new
153
+ response_wrapper.parse_from_string @buffer.data
154
+
155
+ # Determine success or failure based on parsed data
156
+ if response_wrapper.has_field? :error_reason
157
+ log_debug '[client-cnxn] Error response parsed'
158
+
159
+ # fail the call if we already know the client is failed
160
+ # (don't try to parse out the response payload)
161
+ fail response_wrapper.error_reason, response_wrapper.error
162
+ else
163
+ log_debug '[client-cnxn] Successful response parsed'
164
+
165
+ # Ensure client_response is an instance
166
+ response_type = @options[:response_type].new
167
+ parsed = response_type.parse_from_string(response_wrapper.response_proto.to_s)
168
+
169
+ if parsed.nil? and not response_wrapper.has_field?(:error_reason)
170
+ fail :BAD_RESPONSE_PROTO, 'Unable to parse response from server'
171
+ else
172
+ succeed parsed
173
+ end
174
+ end
175
+ end
176
+
177
+ def fail code, message
178
+ @state = STATES[:failed]
179
+ @error.code = code.is_a?(Symbol) ? Protobuf::Socketrpc::ErrorReason.values[code] : code
180
+ @error.message = message
181
+ log_debug '[client-cnxn] Server failed request (invoking on_failure): %s' % @error.inspect
182
+ begin
183
+ @stats.end
184
+ @stats.log_stats
185
+ @failure_callback.call(@error) unless @failure_callback.nil?
186
+ rescue
187
+ log_error '[client-cnxn] Failure callback error encountered: %s' % $!.message
188
+ log_error '[client-cnxn] %s' % $!.backtrace.join("\n")
189
+ raise
190
+ ensure
191
+ complete
192
+ end
193
+ end
194
+
195
+ def succeed response
196
+ @state = STATES[:succeeded]
197
+ begin
198
+ log_debug '[client-cnxn] Server succeeded request (invoking on_success)'
199
+ @stats.end
200
+ @stats.log_stats
201
+ @success_callback.call(response) unless @success_callback.nil?
202
+ complete
203
+ rescue
204
+ log_error '[client-cnxn] Success callback error encountered: %s' % $!.message
205
+ log_error '[client-cnxn] %s' % $!.backtrace.join("\n")
206
+ fail :RPC_ERROR, 'An exception occurred while calling on_success: %s' % $!.message
207
+ end
208
+ end
209
+
210
+ def complete
211
+ @state = STATES[:completed]
212
+ begin
213
+ log_debug '[client-cnxn] Response proceessing complete'
214
+ @success_callback = @failure_callback = nil
215
+ @complete_callback.call(@state) unless @complete_callback.nil?
216
+ rescue
217
+ log_error '[client-cnxn] Complete callback error encountered: %s' % $!.message
218
+ log_error '[client-cnxn] %s' % $!.backtrace.join("\n")
219
+ raise
220
+ end
221
+ end
222
+
223
+ end
224
+ end
225
+ end