protobuf 1.0.1 → 1.1.0.beta0

Sign up to get free protection for your applications and to get access to all the features.
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