protobuf 1.0.0 → 1.0.1

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 (42) hide show
  1. data/Gemfile.lock +1 -1
  2. data/README.md +138 -126
  3. data/bin/rpc_server +2 -2
  4. data/bin/rprotoc +2 -2
  5. data/examples/reading_a_message.rb +3 -3
  6. data/examples/writing_a_message.rb +3 -3
  7. data/lib/protobuf.rb +3 -0
  8. data/lib/protobuf/compiler/nodes.rb +1 -1
  9. data/lib/protobuf/compiler/proto_parser.rb +16 -16
  10. data/lib/protobuf/compiler/visitors.rb +11 -25
  11. data/lib/protobuf/descriptor/descriptor_builder.rb +58 -58
  12. data/lib/protobuf/descriptor/field_descriptor.rb +2 -2
  13. data/lib/protobuf/ext/eventmachine.rb +16 -0
  14. data/lib/protobuf/message/decoder.rb +6 -6
  15. data/lib/protobuf/message/field.rb +14 -14
  16. data/lib/protobuf/message/message.rb +4 -4
  17. data/lib/protobuf/rpc/client.rb +42 -183
  18. data/lib/protobuf/rpc/connector.rb +19 -0
  19. data/lib/protobuf/rpc/connectors/base.rb +29 -0
  20. data/lib/protobuf/rpc/connectors/em_client.rb +227 -0
  21. data/lib/protobuf/rpc/connectors/eventmachine.rb +84 -0
  22. data/lib/protobuf/rpc/connectors/socket.rb +14 -0
  23. data/lib/protobuf/rpc/service.rb +4 -4
  24. data/lib/protobuf/version.rb +1 -1
  25. data/protobuf.gemspec +3 -3
  26. data/spec/helper/all.rb +13 -0
  27. data/spec/helper/server.rb +36 -0
  28. data/spec/helper/tolerance_matcher.rb +40 -0
  29. data/spec/spec_helper.rb +3 -5
  30. data/spec/unit/rpc/client_spec.rb +174 -0
  31. data/spec/unit/rpc/connector_spec.rb +36 -0
  32. data/spec/unit/rpc/connectors/base_spec.rb +77 -0
  33. data/spec/unit/rpc/connectors/eventmachine/client_spec.rb +0 -0
  34. data/spec/unit/rpc/connectors/eventmachine_spec.rb +0 -0
  35. data/spec/unit/{server_spec.rb → rpc/server_spec.rb} +0 -0
  36. data/spec/unit/{service_spec.rb → rpc/service_spec.rb} +0 -0
  37. metadata +79 -63
  38. data/lib/protobuf/compiler/template/rpc_bin.erb +0 -4
  39. data/lib/protobuf/compiler/template/rpc_client.erb +0 -18
  40. data/lib/protobuf/compiler/template/rpc_service.erb +0 -25
  41. data/lib/protobuf/rpc/client_connection.rb +0 -225
  42. data/spec/unit/client_spec.rb +0 -128
@@ -1,4 +0,0 @@
1
- #!/usr/bin/env ruby
2
- require '<%= underscored_name %>'
3
-
4
- <%= module_name %>::<%= service_name %>.new(:Port => <%= default_port %>).start
@@ -1,18 +0,0 @@
1
- #!/usr/bin/env ruby
2
- require 'protobuf/rpc/client'
3
- require '<%= required_file %>'
4
-
5
- # build request
6
- request = <%= message_module %>::<%= request %>.new
7
- # TODO: setup a request
8
- raise StandardError, 'setup a request'
9
-
10
- # create blunk response
11
- response = <%= message_module %>::<%= response %>.new
12
-
13
- # execute rpc
14
- Protobuf::Rpc::Client.new('localhost', <%= default_port %>).call :<%= underscore name %>, request, response
15
-
16
- # show response
17
- puts response
18
-
@@ -1,25 +0,0 @@
1
- require 'protobuf/rpc/server'
2
- require 'protobuf/rpc/handler'
3
- require '<%= required_file %>'
4
-
5
- <%- rpcs.each do |name, request, response| -%>
6
- class <%= module_name %>::<%= name %>Handler < Protobuf::Rpc::Handler
7
- request <%= module_name %>::<%= request %>
8
- response <%= module_name %>::<%= response %>
9
-
10
- def self.process_request(request, response)
11
- # TODO: edit this method
12
- end
13
- end
14
-
15
- <%- end -%>
16
- class <%= module_name %>::<%= service_name %> < Protobuf::Rpc::Server
17
- def setup_handlers
18
- @handlers = {
19
- <%- rpcs.each do |name, | -%>
20
- :<%= underscore name %> => <%= module_name %>::<%= name %>Handler,
21
- <%- end -%>
22
- }
23
- end
24
- end
25
-
@@ -1,225 +0,0 @@
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
@@ -1,128 +0,0 @@
1
- require 'spec_helper'
2
- require 'spec/proto/test_service_impl'
3
-
4
- describe Protobuf::Rpc::Client do
5
-
6
- context 'when creating a client from a service' do
7
-
8
- it 'should be able to get a client through the Service#client helper method' do
9
- Spec::Proto::TestService.client(:port => 9191).should == Protobuf::Rpc::Client.new(:service => Spec::Proto::TestService, :port => 9191)
10
- end
11
-
12
- it "should be able to override a service location's host and port" do
13
- Spec::Proto::TestService.located_at 'somewheregreat.com:12345'
14
- clean_client = Spec::Proto::TestService.client
15
- clean_client.options[:host].should == 'somewheregreat.com'
16
- clean_client.options[:port].should == 12345
17
-
18
- updated_client = Spec::Proto::TestService.client(:host => 'amazing.com', :port => 54321)
19
- updated_client.options[:host].should == 'amazing.com'
20
- updated_client.options[:port].should == 54321
21
- end
22
-
23
- it 'should be able to define the syncronicity of the client request' do
24
- client = Spec::Proto::TestService.client(:async => false)
25
- client.options[:async].should be_false
26
- client.do_block.should be_true
27
-
28
- client = Spec::Proto::TestService.client(:async => true)
29
- client.options[:async].should be_true
30
- client.do_block.should be_false
31
- end
32
-
33
- it 'should be able to define which service to create itself for' do
34
- client = Protobuf::Rpc::Client.new :service => Spec::Proto::TestService
35
- client.options[:service].should == Spec::Proto::TestService
36
- end
37
-
38
- it 'should have a hard default for host and port on a service that has not been configured' do
39
- reset_service_location Spec::Proto::TestService
40
- client = Spec::Proto::TestService.client
41
- client.options[:host].should == Protobuf::Rpc::Service::DEFAULT_LOCATION[:host]
42
- client.options[:port].should == Protobuf::Rpc::Service::DEFAULT_LOCATION[:port]
43
- end
44
-
45
- end
46
-
47
- context 'when calling methods on a service client' do
48
-
49
- # NOTE: we are assuming the service methods are accurately
50
- # defined inside spec/proto/test_service.rb,
51
- # namely the :find method
52
-
53
- it 'should respond to defined service methods' do
54
- client = Spec::Proto::TestService.client
55
- client.should_receive(:send_request).and_return(nil)
56
- expect { client.find(nil) }.should_not raise_error
57
- end
58
-
59
- it 'raises a NameError when accessing a var that does not exist' do
60
- pending
61
- end
62
-
63
- it 'should be able to set and get local variables within client response blocks' do
64
- outer_value = 'OUTER'
65
- inner_value = 'INNER'
66
- client = Spec::Proto::TestService.client(:async => true)
67
-
68
- EM.should_receive(:reactor_running?).and_return(true)
69
- EM.stub!(:schedule) do
70
- client.instance_variable_get(:@success_callback).call(inner_value)
71
- end
72
-
73
- client.find(nil) do |c|
74
- c.on_success do |response|
75
- outer_value.should == 'OUTER'
76
- outer_value = response
77
- end
78
- end
79
- outer_value.should == inner_value
80
- end
81
-
82
- end
83
-
84
- context 'when receiving request objects' do
85
-
86
- it 'should be able to create the correct request object if passed a hash' do
87
- client = Spec::Proto::TestService.client
88
- client.should_receive(:send_request)
89
- client.find({:name => 'Test Name', :active => false})
90
- client.options[:request].should be_a Spec::Proto::ResourceFindRequest
91
- client.options[:request].name.should == 'Test Name'
92
- client.options[:request].active.should == false
93
- end
94
-
95
- end
96
-
97
- describe '#synchronize_or_return' do
98
-
99
- context 'when a timeout error occurs' do
100
- it 'returns a timeout error' do
101
- client = Spec::Proto::TestService.client :timeout => 1
102
- client.stub(:ensure_callback).and_return(proc {|err|
103
- err.should be_a Protobuf::Rpc::ClientError
104
- err.message.should == 'Client timeout of 1 seconds expired'
105
- err.code.should == Protobuf::Socketrpc::ErrorReason::RPC_ERROR
106
- })
107
- Timeout.timeout(2) { client.synchronize_or_return }
108
- end
109
- end
110
-
111
- context 'when any other error occurs' do
112
- it 'returns the error' do
113
- client = Spec::Proto::TestService.client
114
- client.stub(:ensure_callback).and_return(proc {|err|
115
- err.should be_a Protobuf::Rpc::ClientError
116
- err.message.should == 'Client failed: This is another type of error'
117
- err.code.should == Protobuf::Socketrpc::ErrorReason::RPC_ERROR
118
- })
119
- Timeout.timeout(2) {
120
- Timeout.stub(:timeout).and_raise(RuntimeError.new('This is another type of error'))
121
- client.synchronize_or_return
122
- }
123
- end
124
- end
125
-
126
- end
127
-
128
- end