protobuf 2.7.12 → 2.8.0.beta1
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.
- data/README.md +39 -2
- data/lib/protobuf.rb +17 -26
- data/lib/protobuf/cli.rb +106 -86
- data/lib/protobuf/field/bytes_field.rb +6 -8
- data/lib/protobuf/field/float_field.rb +5 -1
- data/lib/protobuf/field/string_field.rb +7 -8
- data/lib/protobuf/rpc/connectors/base.rb +1 -1
- data/lib/protobuf/rpc/connectors/zmq.rb +157 -29
- data/lib/protobuf/rpc/dynamic_discovery.pb.rb +49 -0
- data/lib/protobuf/rpc/error/client_error.rb +5 -5
- data/lib/protobuf/rpc/error/server_error.rb +7 -7
- data/lib/protobuf/rpc/rpc.pb.rb +13 -12
- data/lib/protobuf/rpc/servers/evented_runner.rb +11 -6
- data/lib/protobuf/rpc/servers/socket/server.rb +19 -15
- data/lib/protobuf/rpc/servers/socket_runner.rb +21 -18
- data/lib/protobuf/rpc/servers/zmq/broker.rb +104 -94
- data/lib/protobuf/rpc/servers/zmq/server.rb +263 -43
- data/lib/protobuf/rpc/servers/zmq/util.rb +18 -6
- data/lib/protobuf/rpc/servers/zmq/worker.rb +102 -39
- data/lib/protobuf/rpc/servers/zmq_runner.rb +31 -20
- data/lib/protobuf/rpc/service.rb +24 -12
- data/lib/protobuf/rpc/service_directory.rb +206 -0
- data/lib/protobuf/rpc/stat.rb +1 -1
- data/lib/protobuf/version.rb +1 -1
- data/proto/dynamic_discovery.proto +44 -0
- data/spec/benchmark/tasks.rb +1 -3
- data/spec/functional/socket_server_spec.rb +6 -5
- data/spec/functional/zmq_server_spec.rb +59 -30
- data/spec/lib/protobuf/cli_spec.rb +49 -54
- data/spec/lib/protobuf/enum_spec.rb +1 -1
- data/spec/lib/protobuf/rpc/client_spec.rb +1 -1
- data/spec/lib/protobuf/rpc/connectors/zmq_spec.rb +43 -1
- data/spec/lib/protobuf/rpc/servers/evented_server_spec.rb +2 -1
- data/spec/lib/protobuf/rpc/servers/socket_server_spec.rb +9 -8
- data/spec/lib/protobuf/rpc/servers/zmq/server_spec.rb +24 -19
- data/spec/lib/protobuf/rpc/servers/zmq/util_spec.rb +5 -5
- data/spec/lib/protobuf/rpc/service_directory_spec.rb +183 -0
- data/spec/support/server.rb +21 -12
- data/spec/support/test/resource.pb.rb +6 -0
- data/spec/support/test/resource.proto +5 -0
- data/spec/support/test/resource_service.rb +7 -0
- metadata +70 -38
- checksums.yaml +0 -7
- data/spec/lib/protobuf/field/string_field_spec.rb +0 -46
- data/spec/lib/protobuf/rpc/servers/zmq/broker_spec.rb +0 -31
@@ -4,6 +4,10 @@ module Protobuf
|
|
4
4
|
module Field
|
5
5
|
class FloatField < BaseField
|
6
6
|
def self.default; 0.0; end
|
7
|
+
def self.max; 1.0/0; end
|
8
|
+
def self.min; -1.0/0; end
|
9
|
+
def max; 1.0/0; end
|
10
|
+
def min; -1.0/0; end
|
7
11
|
|
8
12
|
def wire_type
|
9
13
|
WireType::FIXED32
|
@@ -18,7 +22,7 @@ module Protobuf
|
|
18
22
|
end
|
19
23
|
|
20
24
|
def acceptable?(val)
|
21
|
-
val
|
25
|
+
(val > min || val < max) rescue false
|
22
26
|
end
|
23
27
|
end
|
24
28
|
end
|
@@ -6,18 +6,17 @@ module Protobuf
|
|
6
6
|
ENCODING = 'UTF-8'.freeze
|
7
7
|
|
8
8
|
def decode(bytes)
|
9
|
-
|
10
|
-
|
11
|
-
bytes_to_decode
|
9
|
+
bytes.force_encoding(::Protobuf::Field::StringField::ENCODING)
|
10
|
+
bytes
|
12
11
|
end
|
13
12
|
|
14
13
|
def encode(value)
|
15
|
-
|
16
|
-
|
17
|
-
|
14
|
+
# TODO: make replace character configurable?
|
15
|
+
value.encode!(::Protobuf::Field::StringField::ENCODING, :invalid => :replace, :undef => :replace, :replace => "")
|
16
|
+
value.force_encoding(::Protobuf::Field::BytesField::BYTES_ENCODING)
|
18
17
|
|
19
|
-
string_size = ::Protobuf::Field::VarintField.encode(
|
20
|
-
string_size <<
|
18
|
+
string_size = ::Protobuf::Field::VarintField.encode(value.size)
|
19
|
+
string_size << value
|
21
20
|
end
|
22
21
|
end
|
23
22
|
end
|
@@ -17,7 +17,7 @@ module Protobuf
|
|
17
17
|
:request => nil, # The request object sent by the client
|
18
18
|
:request_type => nil, # The request type expected by the client
|
19
19
|
:response_type => nil, # The response type expected by the client
|
20
|
-
:timeout =>
|
20
|
+
:timeout => 15, # The default timeout for the request, also handled by client.rb
|
21
21
|
:client_host => nil # The hostname or address of this client
|
22
22
|
}
|
23
23
|
|
@@ -1,23 +1,38 @@
|
|
1
1
|
require 'protobuf/rpc/connectors/base'
|
2
|
+
require 'protobuf/rpc/service_directory'
|
2
3
|
|
3
4
|
module Protobuf
|
4
5
|
module Rpc
|
5
6
|
module Connectors
|
6
7
|
class Zmq < Base
|
8
|
+
|
9
|
+
##
|
10
|
+
# Included Modules
|
11
|
+
#
|
12
|
+
|
7
13
|
include Protobuf::Rpc::Connectors::Common
|
8
14
|
include Protobuf::Logger::LogMethods
|
9
15
|
|
16
|
+
##
|
17
|
+
# Class Constants
|
18
|
+
#
|
19
|
+
|
20
|
+
CLIENT_RETRIES = (ENV['PB_CLIENT_RETRIES'] || 3)
|
21
|
+
|
22
|
+
##
|
23
|
+
# Instance methods
|
24
|
+
#
|
25
|
+
|
26
|
+
# Start the request/response cycle. We implement the Lazy Pirate
|
27
|
+
# req/reply reliability pattern as laid out in the ZMQ Guide, Chapter 4.
|
28
|
+
#
|
29
|
+
# @see http://zguide.zeromq.org/php:chapter4#Client-side-Reliability-Lazy-Pirate-Pattern
|
30
|
+
#
|
10
31
|
def send_request
|
11
|
-
|
12
|
-
|
13
|
-
connect_to_rpc_server
|
14
|
-
post_init
|
15
|
-
read_response
|
16
|
-
end
|
32
|
+
setup_connection
|
33
|
+
poll_send_data
|
17
34
|
ensure
|
18
|
-
|
19
|
-
@zmq_context.terminate if @zmq_context
|
20
|
-
@zmq_context = nil
|
35
|
+
close_connection
|
21
36
|
end
|
22
37
|
|
23
38
|
def log_signature
|
@@ -26,45 +41,158 @@ module Protobuf
|
|
26
41
|
|
27
42
|
private
|
28
43
|
|
44
|
+
##
|
45
|
+
# Private Instance methods
|
46
|
+
#
|
47
|
+
|
29
48
|
def close_connection
|
30
|
-
|
31
|
-
|
32
|
-
zmq_error_check(@zmq_context.terminate)
|
33
|
-
log_debug { sign_message("Connector closed") }
|
49
|
+
socket_close
|
50
|
+
zmq_context_terminate
|
34
51
|
end
|
35
52
|
|
53
|
+
# Establish a request socket connection to the remote rpc_server.
|
54
|
+
# Set the socket option LINGER to 0 so that we don't wait
|
55
|
+
# for queued messages to be accepted when the socket/context are
|
56
|
+
# asked to close/terminate.
|
57
|
+
#
|
36
58
|
def connect_to_rpc_server
|
37
|
-
return if
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
59
|
+
return if error?
|
60
|
+
|
61
|
+
server_uri = lookup_server_uri
|
62
|
+
log_debug { sign_message("Establishing connection: #{server_uri}") }
|
63
|
+
socket.setsockopt(::ZMQ::LINGER, 0)
|
64
|
+
zmq_error_check(socket.connect(server_uri), :socket_connect)
|
65
|
+
zmq_error_check(poller.register_readable(socket), :poller_register_readable)
|
66
|
+
log_debug { sign_message("Connection established to #{server_uri}") }
|
43
67
|
end
|
44
68
|
|
45
|
-
# Method to determine error state, must be used with Connector
|
69
|
+
# Method to determine error state, must be used with Connector API.
|
70
|
+
#
|
46
71
|
def error?
|
47
|
-
|
72
|
+
!! @error
|
73
|
+
end
|
74
|
+
|
75
|
+
# Lookup a server uri for the requested service in the service
|
76
|
+
# directory. If the service directory is not running, default
|
77
|
+
# to the host and port in the options
|
78
|
+
#
|
79
|
+
def lookup_server_uri
|
80
|
+
if service_directory.running?
|
81
|
+
listing = service_directory.lookup(service)
|
82
|
+
host, port = listing.address, listing.port if listing
|
83
|
+
end
|
84
|
+
|
85
|
+
host, port = options[:host], options[:port] unless host && port
|
86
|
+
|
87
|
+
"tcp://#{host}:#{port}"
|
88
|
+
end
|
89
|
+
|
90
|
+
# Trying a number of times, attempt to get a response from the server.
|
91
|
+
# If we haven't received a legitimate response in the CLIENT_RETRIES number
|
92
|
+
# of retries, fail the request.
|
93
|
+
#
|
94
|
+
def poll_send_data
|
95
|
+
return if error?
|
96
|
+
|
97
|
+
poll_timeout = (options[:timeout].to_f / CLIENT_RETRIES.to_f) * 1000
|
98
|
+
|
99
|
+
CLIENT_RETRIES.times do |n|
|
100
|
+
connect_to_rpc_server
|
101
|
+
log_debug { sign_message("Sending Request (attempt #{n + 1}, #{socket})") }
|
102
|
+
send_data
|
103
|
+
log_debug { sign_message("Request sending complete (attempt #{n + 1}, #{socket})") }
|
104
|
+
|
105
|
+
if poller.poll(poll_timeout) == 1
|
106
|
+
read_response
|
107
|
+
return
|
108
|
+
else
|
109
|
+
close_connection
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
fail(:RPC_FAILED, "The server took longer than #{options[:timeout]} seconds to respond")
|
48
114
|
end
|
49
115
|
|
116
|
+
def poller
|
117
|
+
@poller ||= ::ZMQ::Poller.new
|
118
|
+
end
|
119
|
+
|
120
|
+
# Read the string response from the available readable. This will be
|
121
|
+
# the current @socket. Calls `parse_response` to invoke the success or
|
122
|
+
# failed callbacks, depending on the state of the communication
|
123
|
+
# and response data.
|
124
|
+
#
|
50
125
|
def read_response
|
51
|
-
return if
|
126
|
+
return if error?
|
127
|
+
|
52
128
|
@response_data = ''
|
53
|
-
zmq_error_check(
|
129
|
+
zmq_error_check(socket.recv_string(@response_data), :socket_recv_string)
|
130
|
+
|
54
131
|
parse_response
|
55
132
|
end
|
56
133
|
|
134
|
+
# Send the request data to the remote rpc_server.
|
135
|
+
#
|
57
136
|
def send_data
|
58
|
-
return if
|
59
|
-
|
137
|
+
return if error?
|
138
|
+
|
60
139
|
@stats.request_size = @request_data.size
|
61
|
-
zmq_error_check(
|
62
|
-
|
140
|
+
zmq_error_check(socket.send_string(@request_data), :socket_send_string)
|
141
|
+
end
|
142
|
+
|
143
|
+
# The service we're attempting to connect to
|
144
|
+
#
|
145
|
+
def service
|
146
|
+
options[:service]
|
147
|
+
end
|
148
|
+
|
149
|
+
# Alias for ::Protobuf::Rpc::ServiceDirectory.instance
|
150
|
+
def service_directory
|
151
|
+
::Protobuf::Rpc::ServiceDirectory.instance
|
152
|
+
end
|
153
|
+
|
154
|
+
# Setup a ZMQ request socket in the current zmq context.
|
155
|
+
#
|
156
|
+
def socket
|
157
|
+
@socket ||= zmq_context.socket(::ZMQ::REQ)
|
63
158
|
end
|
64
159
|
|
65
|
-
def
|
66
|
-
|
160
|
+
def socket_close
|
161
|
+
if socket
|
162
|
+
log_debug { sign_message("Closing Socket") }
|
163
|
+
zmq_error_check(socket.close, :socket_close)
|
164
|
+
log_debug { sign_message("Socket closed") }
|
165
|
+
@socket = nil
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# Return the ZMQ Context to use for this process.
|
170
|
+
# If the context does not exist, create it, then register
|
171
|
+
# an exit block to ensure the context is terminated correctly.
|
172
|
+
#
|
173
|
+
def zmq_context
|
174
|
+
@zmq_context ||= ::ZMQ::Context.new
|
175
|
+
end
|
176
|
+
|
177
|
+
# Terminate the zmq_context (if any).
|
178
|
+
#
|
179
|
+
def zmq_context_terminate
|
180
|
+
log_debug { sign_message("Terminating ZMQ Context") }
|
181
|
+
@zmq_context.try(:terminate)
|
182
|
+
@zmq_context = nil
|
183
|
+
log_debug { sign_message("ZMQ Context terminated") }
|
67
184
|
end
|
185
|
+
|
186
|
+
def zmq_error_check(return_code, source)
|
187
|
+
unless ::ZMQ::Util.resultcode_ok?(return_code || -1)
|
188
|
+
raise <<-ERROR
|
189
|
+
Last ZMQ API call to #{source} failed with "#{::ZMQ::Util.error_string}".
|
190
|
+
|
191
|
+
#{caller(1).join($/)}
|
192
|
+
ERROR
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
68
196
|
end
|
69
197
|
end
|
70
198
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
##
|
2
|
+
# This file is auto-generated. DO NOT EDIT!
|
3
|
+
#
|
4
|
+
require 'protobuf/message'
|
5
|
+
|
6
|
+
module Protobuf
|
7
|
+
|
8
|
+
module Rpc
|
9
|
+
|
10
|
+
module DynamicDiscovery
|
11
|
+
|
12
|
+
##
|
13
|
+
# Enum Classes
|
14
|
+
#
|
15
|
+
class BeaconType < ::Protobuf::Enum
|
16
|
+
define :HEARTBEAT, 0
|
17
|
+
define :FLATLINE, 1
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
##
|
22
|
+
# Message Classes
|
23
|
+
#
|
24
|
+
class Server < ::Protobuf::Message; end
|
25
|
+
class Beacon < ::Protobuf::Message; end
|
26
|
+
|
27
|
+
##
|
28
|
+
# Message Fields
|
29
|
+
#
|
30
|
+
class Server
|
31
|
+
optional ::Protobuf::Field::StringField, :uuid, 1
|
32
|
+
optional ::Protobuf::Field::StringField, :address, 2
|
33
|
+
optional ::Protobuf::Field::StringField, :port, 3
|
34
|
+
optional ::Protobuf::Field::Int32Field, :ttl, 4
|
35
|
+
repeated ::Protobuf::Field::StringField, :services, 5
|
36
|
+
end
|
37
|
+
|
38
|
+
class Beacon
|
39
|
+
optional ::Protobuf::Rpc::DynamicDiscovery::BeaconType, :beacon_type, 1
|
40
|
+
optional ::Protobuf::Rpc::DynamicDiscovery::Server, :server, 2
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
@@ -2,30 +2,30 @@ require 'protobuf/rpc/error'
|
|
2
2
|
|
3
3
|
module Protobuf
|
4
4
|
module Rpc
|
5
|
-
|
5
|
+
|
6
6
|
class InvalidRequestProto < PbError
|
7
7
|
def initialize(message='Invalid request type given')
|
8
8
|
super message, 'INVALID_REQUEST_PROTO'
|
9
9
|
end
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
class BadResponseProto < PbError
|
13
13
|
def initialize(message='Bad response type from server')
|
14
14
|
super message, 'BAD_RESPONSE_PROTO'
|
15
15
|
end
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
class UnkownHost < PbError
|
19
19
|
def initialize(message='Unknown host or port')
|
20
20
|
super message, 'UNKNOWN_HOST'
|
21
21
|
end
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
class IOError < PbError
|
25
25
|
def initialize(message='IO Error occurred')
|
26
26
|
super message, 'IO_ERROR'
|
27
27
|
end
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
end
|
31
31
|
end
|
@@ -2,42 +2,42 @@ require 'protobuf/rpc/rpc.pb'
|
|
2
2
|
|
3
3
|
module Protobuf
|
4
4
|
module Rpc
|
5
|
-
|
5
|
+
|
6
6
|
class BadRequestData < PbError
|
7
7
|
def initialize message='Unable to parse request'
|
8
8
|
super message, 'BAD_REQUEST_DATA'
|
9
9
|
end
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
class BadRequestProto < PbError
|
13
13
|
def initialize message='Request is of wrong type'
|
14
14
|
super message, 'BAD_REQUEST_PROTO'
|
15
15
|
end
|
16
16
|
end
|
17
|
-
|
17
|
+
|
18
18
|
class ServiceNotFound < PbError
|
19
19
|
def initialize message='Service class not found'
|
20
20
|
super message, 'SERVICE_NOT_FOUND'
|
21
21
|
end
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
class MethodNotFound < PbError
|
25
25
|
def initialize message='Service method not found'
|
26
26
|
super message, 'METHOD_NOT_FOUND'
|
27
27
|
end
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
class RpcError < PbError
|
31
31
|
def initialize message='RPC exception occurred'
|
32
32
|
super message, 'RPC_ERROR'
|
33
33
|
end
|
34
34
|
end
|
35
|
-
|
35
|
+
|
36
36
|
class RpcFailed < PbError
|
37
37
|
def initialize message='RPC failed'
|
38
38
|
super message, 'RPC_FAILED'
|
39
39
|
end
|
40
40
|
end
|
41
|
-
|
41
|
+
|
42
42
|
end
|
43
43
|
end
|
data/lib/protobuf/rpc/rpc.pb.rb
CHANGED
@@ -4,22 +4,13 @@
|
|
4
4
|
require 'protobuf/message'
|
5
5
|
|
6
6
|
module Protobuf
|
7
|
+
|
7
8
|
module Socketrpc
|
9
|
+
|
8
10
|
##
|
9
11
|
# Enum Classes
|
10
12
|
#
|
11
|
-
class ErrorReason < ::Protobuf::Enum
|
12
|
-
|
13
|
-
##
|
14
|
-
# Message Classes
|
15
|
-
#
|
16
|
-
class Request < ::Protobuf::Message; end
|
17
|
-
class Response < ::Protobuf::Message; end
|
18
|
-
|
19
|
-
##
|
20
|
-
# Enum Values
|
21
|
-
#
|
22
|
-
class ErrorReason
|
13
|
+
class ErrorReason < ::Protobuf::Enum
|
23
14
|
define :BAD_REQUEST_DATA, 0
|
24
15
|
define :BAD_REQUEST_PROTO, 1
|
25
16
|
define :SERVICE_NOT_FOUND, 2
|
@@ -32,6 +23,13 @@ module Protobuf
|
|
32
23
|
define :IO_ERROR, 9
|
33
24
|
end
|
34
25
|
|
26
|
+
|
27
|
+
##
|
28
|
+
# Message Classes
|
29
|
+
#
|
30
|
+
class Request < ::Protobuf::Message; end
|
31
|
+
class Response < ::Protobuf::Message; end
|
32
|
+
|
35
33
|
##
|
36
34
|
# Message Fields
|
37
35
|
#
|
@@ -49,5 +47,8 @@ module Protobuf
|
|
49
47
|
optional ::Protobuf::Socketrpc::ErrorReason, :error_reason, 4
|
50
48
|
end
|
51
49
|
|
50
|
+
|
52
51
|
end
|
52
|
+
|
53
53
|
end
|
54
|
+
|