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,70 @@
1
+ require 'date'
2
+ require 'protobuf/common/logger'
3
+
4
+ module Protobuf
5
+ module Rpc
6
+ class Stat
7
+ attr_accessor :type, :start_time, :end_time, :request_size, :response_size, :client, :server, :service, :method
8
+
9
+ TYPES = [:SERVER, :CLIENT]
10
+
11
+ def initialize type=:SERVER, do_start=true
12
+ @type = type
13
+ start if do_start
14
+ end
15
+
16
+ def client= peer
17
+ @client = {:port => peer[0], :ip => peer[1]}
18
+ end
19
+
20
+ def client
21
+ @client ? '%s:%d' % [@client[:ip], @client[:port]] : nil
22
+ end
23
+
24
+ def server= peer
25
+ @server = {:port => peer[0], :ip => peer[1]}
26
+ end
27
+
28
+ def server
29
+ @server ? '%s:%d' % [@server[:ip], @server[:port]] : nil
30
+ end
31
+
32
+ def sizes
33
+ '%dB/%dB' % [@request_size || 0, @response_size || 0]
34
+ end
35
+
36
+ def start
37
+ @start_time ||= Time.now
38
+ end
39
+
40
+ def end
41
+ start if !@start_time
42
+ @end_time ||= Time.now
43
+ end
44
+
45
+ def rpc
46
+ service && method ? '%s#%s' % [service, method] : nil
47
+ end
48
+
49
+ def elapsed_time
50
+ (start_time && end_time ? '%ss' % (end_time - start_time).round(4) : nil)
51
+ end
52
+
53
+ def log_stats
54
+ Protobuf::Logger.info to_s
55
+ end
56
+
57
+ def to_s
58
+ [
59
+ @type == :SERVER ? '[SRV]' : '[CLT]',
60
+ rpc,
61
+ elapsed_time,
62
+ sizes,
63
+ @type == :SERVER ? server : client
64
+ ].delete_if{|v| v.nil? }.join(' - ')
65
+ end
66
+
67
+ end
68
+ end
69
+ end
70
+
@@ -0,0 +1,3 @@
1
+ module Protobuf
2
+ VERSION = '1.0.0'
3
+ end
data/proto/rpc.proto ADDED
@@ -0,0 +1,73 @@
1
+ // Copyright (c) 2009 Shardul Deo
2
+ //
3
+ // Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ // of this software and associated documentation files (the "Software"), to deal
5
+ // in the Software without restriction, including without limitation the rights
6
+ // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ // copies of the Software, and to permit persons to whom the Software is
8
+ // furnished to do so, subject to the following conditions:
9
+ //
10
+ // The above copyright notice and this permission notice shall be included in
11
+ // all copies or substantial portions of the Software.
12
+ //
13
+ // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ // THE SOFTWARE.
20
+
21
+ // Author: Shardul Deo
22
+ //
23
+ // Protobufs needed for socket rpcs.
24
+
25
+ package protobuf.socketrpc;
26
+
27
+ message Request {
28
+
29
+ // RPC service full name
30
+ required string service_name = 1;
31
+
32
+ // RPC method name
33
+ required string method_name = 2;
34
+
35
+ // RPC request proto
36
+ required bytes request_proto = 3;
37
+ }
38
+
39
+ message Response {
40
+
41
+ // RPC response proto
42
+ optional bytes response_proto = 1;
43
+
44
+ // Error, if any
45
+ optional string error = 2;
46
+
47
+ // Was callback invoked
48
+ optional bool callback = 3 [default = false];
49
+
50
+ // Error Reason
51
+ optional ErrorReason error_reason = 4;
52
+ }
53
+
54
+ // Possible error reasons
55
+ // The server-side errors are returned in the response from the server.
56
+ // The client-side errors are returned by the client-side code when it doesn't
57
+ // have a response from the server.
58
+ enum ErrorReason {
59
+
60
+ // Server-side errors
61
+ BAD_REQUEST_DATA = 0; // Server received bad request data
62
+ BAD_REQUEST_PROTO = 1; // Server received bad request proto
63
+ SERVICE_NOT_FOUND = 2; // Service not found on server
64
+ METHOD_NOT_FOUND = 3; // Method not found on server
65
+ RPC_ERROR = 4; // Rpc threw exception on server
66
+ RPC_FAILED = 5; // Rpc failed on server
67
+
68
+ // Client-side errors (these are returned by the client-side code)
69
+ INVALID_REQUEST_PROTO = 6; // Rpc was called with invalid request proto
70
+ BAD_RESPONSE_PROTO = 7; // Server returned a bad response proto
71
+ UNKNOWN_HOST = 8; // Could not find supplied host
72
+ IO_ERROR = 9; // I/O error while communicating with server
73
+ }
data/protobuf.gemspec ADDED
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("./lib", File.dirname(__FILE__))
3
+ require "protobuf/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = 'protobuf'
7
+ s.version = Protobuf::VERSION
8
+ s.date = %q{2011-11-06}
9
+
10
+ s.authors = ['BJ Neilsen']
11
+ s.email = ["bj.neilsen@gmail.com"]
12
+ s.homepage = %q{https://github.com/localshred/protobuf}
13
+ s.summary = 'Ruby implementation for Protocol Buffers. Works with other protobuf rpc implementations (e.g. Java, Python, C++).'
14
+ s.description = s.summary + "\n\nThis gem has diverged from https://github.com/macks/ruby-protobuf. All credit for serialization and rprotoc work most certainly goes to the original authors. All RPC implementation code (client/server/service) was written and is maintained by this author. Attempts to reconcile the original codebase with the current RPC implementation went unsuccessful."
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ s.add_dependency 'eventmachine', '~> 0.12.10'
22
+
23
+ s.add_development_dependency 'rake', '~> 0.8.7'
24
+ s.add_development_dependency 'rspec', '~> 2.7.0'
25
+ end
data/script/mk_parser ADDED
@@ -0,0 +1,2 @@
1
+ #!/bin/sh
2
+ racc -E lib/protobuf/compiler/proto.y -o lib/protobuf/compiler/proto_parser.rb
@@ -0,0 +1,7 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'An Embedded Service Call Hierarchy' do
4
+
5
+
6
+
7
+ end
@@ -0,0 +1,31 @@
1
+ ### Generated by rprotoc. DO NOT EDIT!
2
+ require 'protobuf/message/message'
3
+ require 'protobuf/message/enum'
4
+ require 'protobuf/message/extend'
5
+
6
+ module Spec
7
+ module Proto
8
+ class StatusType < ::Protobuf::Enum
9
+ define :PENDING, 0
10
+ define :ENABLED, 1
11
+ define :DISABLED, 2
12
+ define :DELETED, 3
13
+ end
14
+ class ResourceFindRequest < ::Protobuf::Message
15
+ optional :string, :name, 1
16
+ optional :bool, :active, 2
17
+ end
18
+ class Resource < ::Protobuf::Message
19
+ optional :string, :name, 1
20
+ optional :int64, :date_created, 2
21
+ optional :StatusType, :status, 3
22
+ repeated :StatusType, :repeated_enum, 4
23
+ end
24
+ class Nested < ::Protobuf::Message
25
+ optional :string, :name, 1
26
+ optional :Resource, :resource, 2
27
+ repeated :Resource, :multiple_resources, 3
28
+ optional :StatusType, :status, 4
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ package spec.proto;
2
+
3
+ enum StatusType {
4
+ PENDING = 0;
5
+ ENABLED = 1;
6
+ DISABLED = 2;
7
+ DELETED = 3;
8
+ }
9
+
10
+ message ResourceFindRequest {
11
+ optional string name = 1;
12
+ optional bool active = 2;
13
+ }
14
+
15
+ message Resource {
16
+ optional string name = 1;
17
+ optional int64 date_created = 2;
18
+ optional StatusType status = 3;
19
+ repeated StatusType repeated_enum = 4;
20
+ }
21
+
22
+ message Nested {
23
+ optional string name = 1;
24
+ optional Resource resource = 2;
25
+ repeated Resource multiple_resources = 3;
26
+ optional StatusType status = 4;
27
+ }
28
+
29
+ service TestService {
30
+ rpc Find (ResourceFindRequest) returns (Resource);
31
+ }
@@ -0,0 +1,30 @@
1
+ require 'protobuf/rpc/service'
2
+ require 'spec/proto/test.pb'
3
+
4
+ ## !! DO NOT EDIT THIS FILE !!
5
+ ##
6
+ ## To implement this service as defined by the protobuf, simply
7
+ ## reopen Spec::Proto::TestService and implement each service method:
8
+ ##
9
+ ## module Spec
10
+ ## module Proto
11
+ ## class TestService
12
+ ##
13
+ ## # request -> Spec::Proto::ResourceFindRequest
14
+ ## # response -> Spec::Proto::Resource
15
+ ## def find
16
+ ## # TODO: implement find
17
+ ## end
18
+ ##
19
+ ## end
20
+ ## end
21
+ ## end
22
+ ##
23
+
24
+ module Spec
25
+ module Proto
26
+ class TestService < Protobuf::Rpc::Service
27
+ rpc :find, ResourceFindRequest, Resource
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,17 @@
1
+ require 'spec/proto/test_service'
2
+
3
+ module Spec
4
+ module Proto
5
+ class TestService
6
+ located_at "localhost:9191"
7
+
8
+ # request -> Spec::Proto::ResourceFindRequest
9
+ # response -> Spec::Proto::Resource
10
+ def find
11
+ response.name = request.name
12
+ response.status = request.active ? 1 : 0
13
+ end
14
+
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,26 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ Bundler.setup :default, :development, :test
4
+
5
+ RSpec.configure do |c|
6
+ c.mock_with :rspec
7
+ end
8
+
9
+ $:.push File.expand_path('..', File.dirname(__FILE__))
10
+ $:.push File.expand_path('../lib', File.dirname(__FILE__))
11
+ require 'protobuf'
12
+
13
+ require 'protobuf/rpc/client'
14
+ class ::Protobuf::Rpc::Client
15
+ def == other
16
+ options == other.options && \
17
+ error == other.error && \
18
+ do_block == other.do_block && \
19
+ @success_callback == other.instance_variable_get(:@success_callback) && \
20
+ @failure_callback == other.instance_variable_get(:@failure_callback)
21
+ end
22
+ end
23
+
24
+ def reset_service_location service
25
+ service.instance_variable_set :@locations, nil
26
+ end
@@ -0,0 +1,128 @@
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