protobuf 1.0.1 → 1.1.0.beta0

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 (45) hide show
  1. data/.gitignore +3 -0
  2. data/.yardopts +5 -0
  3. data/Gemfile.lock +25 -10
  4. data/bin/rpc_server +38 -33
  5. data/lib/protobuf.rb +22 -3
  6. data/lib/protobuf/common/logger.rb +6 -8
  7. data/lib/protobuf/compiler/visitors.rb +8 -9
  8. data/lib/protobuf/descriptor/descriptor_builder.rb +6 -6
  9. data/lib/protobuf/ext/eventmachine.rb +2 -4
  10. data/lib/protobuf/message/message.rb +1 -3
  11. data/lib/protobuf/rpc/buffer.rb +6 -6
  12. data/lib/protobuf/rpc/client.rb +59 -21
  13. data/lib/protobuf/rpc/connector.rb +10 -9
  14. data/lib/protobuf/rpc/connectors/base.rb +23 -8
  15. data/lib/protobuf/rpc/connectors/common.rb +155 -0
  16. data/lib/protobuf/rpc/connectors/em_client.rb +23 -192
  17. data/lib/protobuf/rpc/connectors/eventmachine.rb +36 -44
  18. data/lib/protobuf/rpc/connectors/socket.rb +58 -1
  19. data/lib/protobuf/rpc/error.rb +6 -14
  20. data/lib/protobuf/rpc/server.rb +72 -99
  21. data/lib/protobuf/rpc/servers/evented_runner.rb +32 -0
  22. data/lib/protobuf/rpc/servers/evented_server.rb +29 -0
  23. data/lib/protobuf/rpc/servers/socket_runner.rb +17 -0
  24. data/lib/protobuf/rpc/servers/socket_server.rb +145 -0
  25. data/lib/protobuf/rpc/service.rb +50 -51
  26. data/lib/protobuf/rpc/stat.rb +2 -2
  27. data/lib/protobuf/version.rb +1 -1
  28. data/protobuf.gemspec +9 -4
  29. data/spec/helper/all.rb +1 -7
  30. data/spec/helper/server.rb +45 -5
  31. data/spec/helper/silent_constants.rb +40 -0
  32. data/spec/proto/test_service.rb +0 -1
  33. data/spec/proto/test_service_impl.rb +4 -3
  34. data/spec/spec_helper.rb +19 -6
  35. data/spec/unit/enum_spec.rb +4 -4
  36. data/spec/unit/rpc/client_spec.rb +32 -42
  37. data/spec/unit/rpc/connector_spec.rb +11 -16
  38. data/spec/unit/rpc/connectors/base_spec.rb +14 -3
  39. data/spec/unit/rpc/connectors/common_spec.rb +132 -0
  40. data/spec/unit/rpc/connectors/{eventmachine/client_spec.rb → eventmachine_client_spec.rb} +0 -0
  41. data/spec/unit/rpc/connectors/socket_spec.rb +49 -0
  42. data/spec/unit/rpc/servers/evented_server_spec.rb +18 -0
  43. data/spec/unit/rpc/servers/socket_server_spec.rb +57 -0
  44. metadata +86 -16
  45. data/spec/unit/rpc/server_spec.rb +0 -27
data/.gitignore CHANGED
@@ -3,3 +3,6 @@ pkg/*
3
3
  .bundle
4
4
  .rvmrc
5
5
  *.log
6
+ coverage
7
+ doc
8
+ .yardoc
data/.yardopts ADDED
@@ -0,0 +1,5 @@
1
+ --no-private
2
+ --hide-void-return
3
+
4
+ --markup-provider=redcarpet
5
+ --markup=markdown
data/Gemfile.lock CHANGED
@@ -1,28 +1,43 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- protobuf (1.0.1)
4
+ protobuf (1.1.0.beta0)
5
5
  eventmachine (~> 0.12.10)
6
+ eventually (~> 0.1.0)
7
+ json_pure (~> 1.6.4)
6
8
 
7
9
  GEM
8
10
  remote: http://rubygems.org/
9
11
  specs:
10
- diff-lcs (1.1.2)
12
+ diff-lcs (1.1.3)
11
13
  eventmachine (0.12.10)
14
+ eventually (0.1.0)
15
+ json_pure (1.6.4)
16
+ multi_json (1.0.4)
12
17
  rake (0.8.7)
13
- rspec (2.7.0)
14
- rspec-core (~> 2.7.0)
15
- rspec-expectations (~> 2.7.0)
16
- rspec-mocks (~> 2.7.0)
17
- rspec-core (2.7.1)
18
- rspec-expectations (2.7.0)
18
+ redcarpet (1.17.2)
19
+ rspec (2.8.0)
20
+ rspec-core (~> 2.8.0)
21
+ rspec-expectations (~> 2.8.0)
22
+ rspec-mocks (~> 2.8.0)
23
+ rspec-core (2.8.0)
24
+ rspec-expectations (2.8.0)
19
25
  diff-lcs (~> 1.1.2)
20
- rspec-mocks (2.7.0)
26
+ rspec-mocks (2.8.0)
27
+ simplecov (0.5.4)
28
+ multi_json (~> 1.0.3)
29
+ simplecov-html (~> 0.5.3)
30
+ simplecov-html (0.5.3)
31
+ yard (0.7.4)
21
32
 
22
33
  PLATFORMS
34
+ java
23
35
  ruby
24
36
 
25
37
  DEPENDENCIES
26
38
  protobuf!
27
39
  rake (~> 0.8.7)
28
- rspec (~> 2.7.0)
40
+ redcarpet (~> 1.17.2)
41
+ rspec (~> 2.8.0)
42
+ simplecov (~> 0.5.4)
43
+ yard (~> 0.7.4)
data/bin/rpc_server CHANGED
@@ -3,16 +3,9 @@
3
3
  require 'optparse'
4
4
  require 'ostruct'
5
5
  require 'logger'
6
- require 'protobuf'
7
- require 'protobuf/rpc/server'
8
-
9
- [:INT, :QUIT, :TERM].each do |sig|
10
- trap(sig) do
11
- EventMachine.stop_event_loop if EventMachine.reactor_running?
12
- Protobuf::Logger.info 'Shutdown complete'
13
- $stdout.puts 'Shutdown complete'
14
- end
15
- end
6
+ require 'protobuf/version'
7
+ require 'protobuf/rpc/servers/evented_runner'
8
+ require 'protobuf/rpc/servers/socket_runner'
16
9
 
17
10
  # Default options
18
11
  server = OpenStruct.new({
@@ -20,8 +13,11 @@ server = OpenStruct.new({
20
13
  :env => ENV['RPC_SERVER_ENV'] || 'development',
21
14
  :host => '127.0.0.1',
22
15
  :port => 9595,
16
+ :backlog => 100,
17
+ :threshold => 100,
23
18
  :log => File.expand_path('./protobuf.log'),
24
19
  :level => ::Logger::INFO,
20
+ :runner => Protobuf::Rpc::EventedRunner,
25
21
  :debug => false
26
22
  })
27
23
 
@@ -47,6 +43,23 @@ parser = OptionParser.new do |opts|
47
43
  opts.on("-v N", "--level=N", Integer, "Log level to use, 0-5 (see http://www.ruby-doc.org/stdlib/libdoc/logger/rdoc/)") do |v|
48
44
  server.level = v.to_i
49
45
  end
46
+
47
+ opts.on("-b N", "--backlog=N", Integer, "Backlog for listening socket when using Socket Server") do |v|
48
+ server.backlog = v.to_i
49
+ end
50
+
51
+ opts.on("-t N", "--threshold=N", Integer, "Multi-threaded Socket Server cleanup threshold") do |v|
52
+ server.threshold = v.to_i
53
+ end
54
+
55
+ opts.on("-c", "--client_socket", "Socket Mode for client connections (No EventMachine)") do |v|
56
+ Protobuf::ConnectorType = "Socket"
57
+ end
58
+
59
+ opts.on("-s", "--socket", "Socket Server Mode (No EventMachine)") do |v|
60
+ Protobuf::ServerType = "SocketServer"
61
+ server.runner = Protobuf::Rpc::SocketRunner
62
+ end
50
63
 
51
64
  opts.on("-d", "--[no-]debug", "Debug Mode. Override log level to DEBUG.") do |v|
52
65
  server.debug = v
@@ -67,49 +80,41 @@ parser = OptionParser.new do |opts|
67
80
  end
68
81
  end
69
82
 
83
+ parser.parse!
84
+ require 'protobuf'
85
+
86
+ [:INT, :QUIT, :TERM].each do |sig|
87
+ trap(sig) do
88
+ server.runner.stop
89
+ end
90
+ end
91
+
70
92
  begin
71
- parser.parse!
72
-
73
93
  if ARGV.empty?
74
- raise 'You must specify an app file to use.'
94
+ puts 'You must specify an app file to use.'
95
+ puts parser.help
96
+ exit
75
97
  else
76
98
  server.app = ARGV.pop
77
99
  raise 'Invalid app file specified (%s).' % server.app unless File.exists?(server.app)
78
100
  end
79
-
101
+
80
102
  # Configure the Protobuf::Logger
81
103
  Protobuf::Logger.configure :file => server.log, :level => server.debug ? ::Logger::DEBUG : server.level
82
104
 
83
105
  # Output the server opts
84
106
  Protobuf::Logger.debug 'Debugging options:'
85
107
  Protobuf::Logger.debug server.inspect
86
-
87
- # Ensure errors thrown within EM are caught and logged appropriately
88
- EventMachine.error_handler do |error|
89
- if error.message == 'no acceptor'
90
- raise 'Failed binding to %s:%d (%s)' % [server.host, server.port, error.message]
91
- else
92
- Protobuf::Logger.error error.message
93
- Protobuf::Logger.error error.backtrace.join("\n")
94
- end
95
- end
96
108
 
97
109
  # Set the name of the process
98
110
  $0 = 'rpc_server %s:%d %s' % [server.host, server.port, server.app]
99
111
 
100
112
  # Require the given application file
101
113
  require server.app
102
-
103
- # Startup and run the rpc server
104
- EM.schedule do
105
- EventMachine.start_server(server.host, server.port, Protobuf::Rpc::Server) && \
106
- Protobuf::Logger.info('RPC Server listening at %s:%d in %s' % [server.host, server.port, server.env])
107
- end
108
114
 
109
- # Join or start the reactor
110
- EM.reactor_running? ? EM.reactor_thread.join : EM.run
115
+ server.runner.run(server)
111
116
  rescue
112
- msg = 'ERROR: RPC Server failed to start. %s' % $!.message
117
+ msg = 'ERROR: RPC Server failed to start. %s' % $!.inspect
113
118
  $stderr.puts msg, *($!.backtrace)
114
119
  Protobuf::Logger.error msg
115
120
  Protobuf::Logger.error $!.backtrace.join("\n")
data/lib/protobuf.rb CHANGED
@@ -1,9 +1,28 @@
1
- require 'eventmachine'
2
- require 'protobuf/ext/eventmachine'
1
+ require 'logger'
2
+ require 'socket'
3
+ require 'pp'
4
+ require 'stringio'
3
5
 
4
6
  module Protobuf
5
7
  end
6
8
 
9
+ # When setting up a client
10
+ unless defined?(Protobuf::ConnectorType) && Protobuf::ConnectorType == "Socket"
11
+ Protobuf::ConnectorType = "EventMachine"
12
+ require 'eventmachine'
13
+ require 'protobuf/ext/eventmachine'
14
+ require 'protobuf/rpc/connectors/eventmachine'
15
+ end
16
+
17
+ # For running the rpc_server
18
+ unless defined?(Protobuf::ServerType) && Protobuf::ServerType == "SocketServer"
19
+ Protobuf::ServerType = "EventedServer"
20
+ require 'eventmachine'
21
+ require 'protobuf/ext/eventmachine'
22
+ require 'protobuf/rpc/servers/evented_server'
23
+ end
24
+
7
25
  require 'protobuf/rpc/client'
8
- require 'protobuf/rpc/server'
26
+ require 'protobuf/rpc/connectors/socket'
9
27
  require 'protobuf/rpc/service'
28
+ require 'protobuf/rpc/servers/socket_server'
@@ -1,5 +1,3 @@
1
- require 'logger'
2
-
3
1
  module Protobuf
4
2
  class Logger < ::Logger
5
3
 
@@ -7,15 +5,11 @@ module Protobuf
7
5
  attr_accessor :file, :level
8
6
 
9
7
  # One-line file/level configuration
10
- def configure options
8
+ def configure(options)
11
9
  self.file = options[:file] if options[:file]
12
10
  self.level = options[:level] if options[:level]
13
11
  end
14
12
 
15
- def configured?
16
- ! instance.nil?
17
- end
18
-
19
13
  # Use to reset the instance
20
14
  def reset_device!
21
15
  self.file = self.level = @__instance = nil
@@ -58,7 +52,11 @@ module Protobuf
58
52
  Protobuf::Logger.__send__(m, *params, &block)
59
53
  end
60
54
  end
55
+
56
+ def self.included(base)
57
+ base.extend(LogMethods)
58
+ end
61
59
  end
62
60
 
63
61
  end
64
- end
62
+ end
@@ -110,15 +110,14 @@ module Protobuf
110
110
  end
111
111
 
112
112
  def create_files(filename, out_dir, file_create)
113
- begin
114
- $: << File.expand_path(out_dir)
115
- Class.new.class_eval(to_s) # check the message
116
- $:.delete File.expand_path(out_dir)
117
- rescue LoadError
118
- puts "Error creating file #{filename}"
119
- puts $!.message
120
- exit 1
121
- end
113
+ $: << File.expand_path(out_dir)
114
+ Class.new.class_eval(to_s) # check the message
115
+ $:.delete File.expand_path(out_dir)
116
+ rescue LoadError
117
+ puts "Error creating file #{filename}"
118
+ puts $!.message
119
+ exit 1
120
+ else
122
121
 
123
122
  file = File.basename(filename)
124
123
  message_module = Util.module_to_path(package.map{|p| p.to_s.capitalize}.join('::'))
@@ -107,12 +107,12 @@ module Protobuf
107
107
  def self.label2id(label)
108
108
  require 'protobuf/descriptor/descriptor_proto'
109
109
  case label
110
- when :required
111
- Google::Protobuf::FieldDescriptorProto::Label::LABEL_REQUIRED then
112
- when :optional
113
- Google::Protobuf::FieldDescriptorProto::Label::LABEL_OPTIONAL then
114
- when :repeated
115
- Google::Protobuf::FieldDescriptorProto::Label::LABEL_REPEATED then
110
+ when :required then
111
+ Google::Protobuf::FieldDescriptorProto::Label::LABEL_REQUIRED
112
+ when :optional then
113
+ Google::Protobuf::FieldDescriptorProto::Label::LABEL_OPTIONAL
114
+ when :repeated then
115
+ Google::Protobuf::FieldDescriptorProto::Label::LABEL_REPEATED
116
116
  else
117
117
  raise ArgumentError, "Invalid label: #{label}"
118
118
  end
@@ -1,6 +1,6 @@
1
1
  require 'fiber'
2
2
 
3
- # Method and concept from em-synchrony
3
+ # Method from em-synchrony
4
4
  # https://github.com/igrigorik/em-synchrony
5
5
  #
6
6
  # A convenience method for wrapping EM.run body within
@@ -8,9 +8,7 @@ require 'fiber'
8
8
  # paused and resumed based on IO scheduling
9
9
  module EventMachine
10
10
  def self.fiber_run(blk=nil, tail=nil, &block)
11
- blk ||= block
12
- context = Proc.new{ Fiber.new{ blk.call }.resume }
13
-
11
+ context = Proc.new{ Fiber.new{ (b = blk || block) and b.call }.resume }
14
12
  self.run(context, tail)
15
13
  end
16
14
  end
@@ -1,5 +1,3 @@
1
- require 'pp'
2
- require 'stringio'
3
1
  require 'protobuf/descriptor/descriptor'
4
2
  require 'protobuf/message/decoder'
5
3
  require 'protobuf/message/encoder'
@@ -27,7 +25,7 @@ module Protobuf
27
25
  end
28
26
  end
29
27
 
30
- class <<self
28
+ class << self
31
29
  include Protoable
32
30
 
33
31
  # Reserve field numbers for extensions. Don't use this method directly.
@@ -7,21 +7,21 @@ module Protobuf
7
7
 
8
8
  MODES = [:read, :write]
9
9
 
10
- def initialize mode=:read, data=''
10
+ def initialize(mode=:read, data='')
11
11
  @data = data.is_a?(Protobuf::Message) ? data.serialize_to_string : data.to_s
12
12
  @flush = false
13
13
  self.mode = mode
14
14
  end
15
15
 
16
- def mode= mode
17
- if MODES.include? mode
16
+ def mode=(mode)
17
+ if MODES.include?(mode)
18
18
  @mode = mode
19
19
  else
20
20
  @mode = :read
21
21
  end
22
22
  end
23
23
 
24
- def write force_mode=true
24
+ def write(force_mode=true)
25
25
  if force_mode and reading?
26
26
  mode = :write
27
27
  elsif not force_mode and reading?
@@ -32,7 +32,7 @@ module Protobuf
32
32
  '%d-%s' % [@size, @data]
33
33
  end
34
34
 
35
- def << data
35
+ def <<(data)
36
36
  @data << data
37
37
  if reading?
38
38
  get_data_size
@@ -71,4 +71,4 @@ module Protobuf
71
71
 
72
72
  end
73
73
  end
74
- end
74
+ end
@@ -9,7 +9,7 @@ module Protobuf
9
9
  extend Forwardable
10
10
  include Protobuf::Logger::LogMethods
11
11
 
12
- delegate [:options, :success_cb, :failure_cb, :async?] => :@connector
12
+ delegate [:options, :complete_cb, :success_cb, :failure_cb, :async?] => :@connector
13
13
  attr_reader :connector
14
14
 
15
15
  # Create a new client with default options (defined in ClientConnection)
@@ -25,22 +25,32 @@ module Protobuf
25
25
  # :request => request
26
26
  # })
27
27
  #
28
- def initialize opts={}
29
- raise "Invalid client configuration. Service must be defined." if !opts[:service] || opts[:service].nil?
30
- @connector = Connector.connector_for_platform.new(opts)
31
- log_debug '[client] Initialized with options: %s' % opts.inspect
28
+ def initialize(opts={})
29
+ raise "Invalid client configuration. Service must be defined." if opts[:service].nil?
30
+ @connector = Connector.connector_for_client.new(opts)
31
+ log_debug "[#{log_signature}] Initialized with options: %s" % opts.inspect
32
+ end
33
+
34
+ def log_signature
35
+ @log_signature ||= "client-#{self.class}"
32
36
  end
33
37
 
34
- # Set a success callback on the client to return the
35
- # successful response from the service when it is returned.
36
- # If this callback is called, failure_cb will NOT be called.
38
+ # Set a complete callback on the client to return the object (self).
37
39
  # Callback is called regardless of :async setting.
38
40
  #
39
41
  # client = Client.new(:service => WidgetService)
40
- # client.on_success {|res| ... }
42
+ # client.on_complete {|obj| ... }
41
43
  #
42
- def on_success &success_cb
43
- @connector.success_cb = success_cb
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
+ raise "callable must take a single argument and respond to :call"
51
+ end
52
+
53
+ @connector.complete_cb = callable
44
54
  end
45
55
 
46
56
  # Set a failure callback on the client to return the
@@ -51,9 +61,37 @@ module Protobuf
51
61
  # client = Client.new(:service => WidgetService)
52
62
  # client.on_failure {|err| ... }
53
63
  #
54
- def on_failure &failure_cb
64
+ def on_failure(&failure_cb)
55
65
  @connector.failure_cb = failure_cb
56
66
  end
67
+
68
+ def on_failure=(callable)
69
+ if callable != nil && !callable.respond_to?(:call) && callable.arity != 1
70
+ raise "callable must take a single argument and respond to :call"
71
+ end
72
+
73
+ @connector.failure_cb = callable
74
+ end
75
+
76
+ # Set a success callback on the client to return the
77
+ # successful response from the service when it is returned.
78
+ # If this callback is called, failure_cb will NOT be called.
79
+ # Callback is called regardless of :async setting.
80
+ #
81
+ # client = Client.new(:service => WidgetService)
82
+ # client.on_success {|res| ... }
83
+ #
84
+ def on_success(&success_cb)
85
+ @connector.success_cb = success_cb
86
+ end
87
+
88
+ def on_success=(callable)
89
+ if callable != nil && !callable.respond_to?(:call) && callable.arity != 1
90
+ raise "callable must take a single argument and respond to :call"
91
+ end
92
+
93
+ @connector.success_cb = callable
94
+ end
57
95
 
58
96
  # Provides a mechanism to call the service method against the client
59
97
  # which will automatically setup the service_class and method_name
@@ -67,28 +105,28 @@ module Protobuf
67
105
  # c.on_failure {|err| ... }
68
106
  # end
69
107
  #
70
- def method_missing method, *params
108
+ def method_missing(method, *params)
71
109
  service = options[:service]
72
110
  unless service.rpcs[service].keys.include?(method)
73
- log_error '[client] %s#%s not rpc method, passing to super' % [service.name, method.to_s]
74
- super method, *params
111
+ log_error "[#{log_signature}] %s#%s not rpc method, passing to super" % [service.name, method.to_s]
112
+ super(method, *params)
75
113
  else
76
- log_debug '[client] %s#%s' % [service.name, method.to_s]
114
+ log_debug "[#{log_signature}] %s#%s" % [service.name, method.to_s]
77
115
  rpc = service.rpcs[service][method.to_sym]
78
116
  options[:request_type] = rpc.request_type
79
- log_debug '[client] Request Type: %s' % options[:request_type].name
117
+ log_debug "[#{log_signature}] Request Type: %s" % options[:request_type].name
80
118
  options[:response_type] = rpc.response_type
81
- log_debug '[client] Response Type: %s' % options[:response_type].name
119
+ log_debug "[#{log_signature}] Response Type: %s" % options[:response_type].name
82
120
  options[:method] = method.to_s
83
121
  options[:request] = params[0].is_a?(Hash) ? options[:request_type].new(params[0]) : params[0]
84
- log_debug '[client] Request Data: %s' % options[:request].inspect
122
+ log_debug "[#{log_signature}] Request Data: %s" % options[:request].inspect
85
123
 
86
124
  # Call client to setup on_success and on_failure event callbacks
87
125
  if block_given?
88
- log_debug '[client] client setup callback given, invoking'
126
+ log_debug "[#{log_signature}] client setup callback given, invoking"
89
127
  yield(self)
90
128
  else
91
- log_debug '[client] no callbacks given'
129
+ log_debug "[#{log_signature}] no block given for callbacks"
92
130
  end
93
131
 
94
132
  send_request