protobuffy 3.1.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.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/.travis.yml +12 -0
- data/.yardopts +5 -0
- data/CHANGES.md +261 -0
- data/CONTRIBUTING.md +16 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +14 -0
- data/README.md +58 -0
- data/Rakefile +61 -0
- data/bin/protoc-gen-ruby +17 -0
- data/bin/rpc_server +4 -0
- data/examples/bin/reverse-client-http +4 -0
- data/examples/bin/reverse-client-socket +4 -0
- data/examples/bin/reverse-client-zmq +4 -0
- data/examples/config.ru +6 -0
- data/examples/definitions/example/reverse.proto +12 -0
- data/examples/lib/example/reverse-client.rb +23 -0
- data/examples/lib/example/reverse-service.rb +9 -0
- data/examples/lib/example/reverse.pb.rb +36 -0
- data/lib/protobuf.rb +106 -0
- data/lib/protobuf/cli.rb +249 -0
- data/lib/protobuf/code_generator.rb +41 -0
- data/lib/protobuf/decoder.rb +74 -0
- data/lib/protobuf/deprecator.rb +42 -0
- data/lib/protobuf/descriptors.rb +3 -0
- data/lib/protobuf/descriptors/google/protobuf/compiler/plugin.pb.rb +52 -0
- data/lib/protobuf/descriptors/google/protobuf/descriptor.pb.rb +249 -0
- data/lib/protobuf/encoder.rb +62 -0
- data/lib/protobuf/enum.rb +319 -0
- data/lib/protobuf/exceptions.rb +9 -0
- data/lib/protobuf/field.rb +74 -0
- data/lib/protobuf/field/base_field.rb +280 -0
- data/lib/protobuf/field/bool_field.rb +53 -0
- data/lib/protobuf/field/bytes_field.rb +81 -0
- data/lib/protobuf/field/double_field.rb +26 -0
- data/lib/protobuf/field/enum_field.rb +57 -0
- data/lib/protobuf/field/field_array.rb +86 -0
- data/lib/protobuf/field/fixed32_field.rb +25 -0
- data/lib/protobuf/field/fixed64_field.rb +29 -0
- data/lib/protobuf/field/float_field.rb +38 -0
- data/lib/protobuf/field/int32_field.rb +22 -0
- data/lib/protobuf/field/int64_field.rb +22 -0
- data/lib/protobuf/field/integer_field.rb +24 -0
- data/lib/protobuf/field/message_field.rb +66 -0
- data/lib/protobuf/field/sfixed32_field.rb +28 -0
- data/lib/protobuf/field/sfixed64_field.rb +29 -0
- data/lib/protobuf/field/signed_integer_field.rb +30 -0
- data/lib/protobuf/field/sint32_field.rb +22 -0
- data/lib/protobuf/field/sint64_field.rb +22 -0
- data/lib/protobuf/field/string_field.rb +35 -0
- data/lib/protobuf/field/uint32_field.rb +22 -0
- data/lib/protobuf/field/uint64_field.rb +22 -0
- data/lib/protobuf/field/varint_field.rb +68 -0
- data/lib/protobuf/generators/base.rb +71 -0
- data/lib/protobuf/generators/enum_generator.rb +42 -0
- data/lib/protobuf/generators/extension_generator.rb +28 -0
- data/lib/protobuf/generators/field_generator.rb +132 -0
- data/lib/protobuf/generators/file_generator.rb +140 -0
- data/lib/protobuf/generators/group_generator.rb +113 -0
- data/lib/protobuf/generators/message_generator.rb +99 -0
- data/lib/protobuf/generators/printable.rb +161 -0
- data/lib/protobuf/generators/service_generator.rb +27 -0
- data/lib/protobuf/http.rb +20 -0
- data/lib/protobuf/lifecycle.rb +46 -0
- data/lib/protobuf/logger.rb +86 -0
- data/lib/protobuf/message.rb +182 -0
- data/lib/protobuf/message/fields.rb +122 -0
- data/lib/protobuf/message/serialization.rb +84 -0
- data/lib/protobuf/optionable.rb +23 -0
- data/lib/protobuf/rpc/buffer.rb +79 -0
- data/lib/protobuf/rpc/client.rb +168 -0
- data/lib/protobuf/rpc/connector.rb +21 -0
- data/lib/protobuf/rpc/connectors/base.rb +54 -0
- data/lib/protobuf/rpc/connectors/common.rb +172 -0
- data/lib/protobuf/rpc/connectors/http.rb +90 -0
- data/lib/protobuf/rpc/connectors/socket.rb +73 -0
- data/lib/protobuf/rpc/connectors/zmq.rb +205 -0
- data/lib/protobuf/rpc/dynamic_discovery.pb.rb +47 -0
- data/lib/protobuf/rpc/env.rb +58 -0
- data/lib/protobuf/rpc/error.rb +28 -0
- data/lib/protobuf/rpc/error/client_error.rb +31 -0
- data/lib/protobuf/rpc/error/server_error.rb +43 -0
- data/lib/protobuf/rpc/middleware.rb +25 -0
- data/lib/protobuf/rpc/middleware/exception_handler.rb +36 -0
- data/lib/protobuf/rpc/middleware/logger.rb +91 -0
- data/lib/protobuf/rpc/middleware/request_decoder.rb +83 -0
- data/lib/protobuf/rpc/middleware/response_encoder.rb +88 -0
- data/lib/protobuf/rpc/middleware/runner.rb +18 -0
- data/lib/protobuf/rpc/rpc.pb.rb +53 -0
- data/lib/protobuf/rpc/server.rb +39 -0
- data/lib/protobuf/rpc/servers/http/server.rb +101 -0
- data/lib/protobuf/rpc/servers/http_runner.rb +34 -0
- data/lib/protobuf/rpc/servers/socket/server.rb +113 -0
- data/lib/protobuf/rpc/servers/socket/worker.rb +56 -0
- data/lib/protobuf/rpc/servers/socket_runner.rb +34 -0
- data/lib/protobuf/rpc/servers/zmq/broker.rb +155 -0
- data/lib/protobuf/rpc/servers/zmq/server.rb +313 -0
- data/lib/protobuf/rpc/servers/zmq/util.rb +47 -0
- data/lib/protobuf/rpc/servers/zmq/worker.rb +105 -0
- data/lib/protobuf/rpc/servers/zmq_runner.rb +51 -0
- data/lib/protobuf/rpc/service.rb +179 -0
- data/lib/protobuf/rpc/service_directory.rb +245 -0
- data/lib/protobuf/rpc/service_dispatcher.rb +46 -0
- data/lib/protobuf/rpc/service_filters.rb +273 -0
- data/lib/protobuf/rpc/stat.rb +148 -0
- data/lib/protobuf/socket.rb +22 -0
- data/lib/protobuf/tasks.rb +1 -0
- data/lib/protobuf/tasks/compile.rake +61 -0
- data/lib/protobuf/version.rb +3 -0
- data/lib/protobuf/wire_type.rb +10 -0
- data/lib/protobuf/zmq.rb +21 -0
- data/proto/dynamic_discovery.proto +44 -0
- data/proto/google/protobuf/compiler/plugin.proto +147 -0
- data/proto/google/protobuf/descriptor.proto +620 -0
- data/proto/rpc.proto +62 -0
- data/protobuffy.gemspec +37 -0
- data/spec/benchmark/tasks.rb +113 -0
- data/spec/bin/protoc-gen-ruby_spec.rb +18 -0
- data/spec/data/data.bin +3 -0
- data/spec/data/types.bin +0 -0
- data/spec/encoding/all_types_spec.rb +91 -0
- data/spec/encoding/extreme_values_spec.rb +0 -0
- data/spec/functional/socket_server_spec.rb +59 -0
- data/spec/functional/zmq_server_spec.rb +103 -0
- data/spec/lib/protobuf/cli_spec.rb +267 -0
- data/spec/lib/protobuf/code_generator_spec.rb +60 -0
- data/spec/lib/protobuf/enum_spec.rb +239 -0
- data/spec/lib/protobuf/field/int32_field_spec.rb +7 -0
- data/spec/lib/protobuf/field/string_field_spec.rb +46 -0
- data/spec/lib/protobuf/field_spec.rb +194 -0
- data/spec/lib/protobuf/generators/base_spec.rb +87 -0
- data/spec/lib/protobuf/generators/enum_generator_spec.rb +68 -0
- data/spec/lib/protobuf/generators/extension_generator_spec.rb +43 -0
- data/spec/lib/protobuf/generators/field_generator_spec.rb +99 -0
- data/spec/lib/protobuf/generators/file_generator_spec.rb +29 -0
- data/spec/lib/protobuf/generators/message_generator_spec.rb +0 -0
- data/spec/lib/protobuf/generators/service_generator_spec.rb +43 -0
- data/spec/lib/protobuf/lifecycle_spec.rb +89 -0
- data/spec/lib/protobuf/logger_spec.rb +136 -0
- data/spec/lib/protobuf/message_spec.rb +368 -0
- data/spec/lib/protobuf/optionable_spec.rb +46 -0
- data/spec/lib/protobuf/rpc/client_spec.rb +66 -0
- data/spec/lib/protobuf/rpc/connector_spec.rb +26 -0
- data/spec/lib/protobuf/rpc/connectors/base_spec.rb +50 -0
- data/spec/lib/protobuf/rpc/connectors/common_spec.rb +170 -0
- data/spec/lib/protobuf/rpc/connectors/connector_spec.rb +13 -0
- data/spec/lib/protobuf/rpc/connectors/http_spec.rb +61 -0
- data/spec/lib/protobuf/rpc/connectors/socket_spec.rb +24 -0
- data/spec/lib/protobuf/rpc/connectors/zmq_spec.rb +129 -0
- data/spec/lib/protobuf/rpc/middleware/exception_handler_spec.rb +62 -0
- data/spec/lib/protobuf/rpc/middleware/logger_spec.rb +49 -0
- data/spec/lib/protobuf/rpc/middleware/request_decoder_spec.rb +115 -0
- data/spec/lib/protobuf/rpc/middleware/response_encoder_spec.rb +75 -0
- data/spec/lib/protobuf/rpc/servers/http/server_spec.rb +104 -0
- data/spec/lib/protobuf/rpc/servers/socket_server_spec.rb +38 -0
- data/spec/lib/protobuf/rpc/servers/zmq/server_spec.rb +41 -0
- data/spec/lib/protobuf/rpc/servers/zmq/util_spec.rb +55 -0
- data/spec/lib/protobuf/rpc/servers/zmq/worker_spec.rb +35 -0
- data/spec/lib/protobuf/rpc/service_directory_spec.rb +295 -0
- data/spec/lib/protobuf/rpc/service_dispatcher_spec.rb +52 -0
- data/spec/lib/protobuf/rpc/service_filters_spec.rb +484 -0
- data/spec/lib/protobuf/rpc/service_spec.rb +161 -0
- data/spec/lib/protobuf/rpc/stat_spec.rb +151 -0
- data/spec/lib/protobuf_spec.rb +78 -0
- data/spec/spec_helper.rb +57 -0
- data/spec/support/all.rb +7 -0
- data/spec/support/packed_field.rb +22 -0
- data/spec/support/server.rb +94 -0
- data/spec/support/test/all_types.data.bin +0 -0
- data/spec/support/test/all_types.data.txt +119 -0
- data/spec/support/test/defaults.pb.rb +25 -0
- data/spec/support/test/defaults.proto +9 -0
- data/spec/support/test/enum.pb.rb +59 -0
- data/spec/support/test/enum.proto +34 -0
- data/spec/support/test/extended.pb.rb +22 -0
- data/spec/support/test/extended.proto +10 -0
- data/spec/support/test/extreme_values.data.bin +0 -0
- data/spec/support/test/google_unittest.pb.rb +543 -0
- data/spec/support/test/google_unittest.proto +713 -0
- data/spec/support/test/google_unittest_import.pb.rb +37 -0
- data/spec/support/test/google_unittest_import.proto +64 -0
- data/spec/support/test/google_unittest_import_public.pb.rb +8 -0
- data/spec/support/test/google_unittest_import_public.proto +38 -0
- data/spec/support/test/multi_field_extensions.pb.rb +56 -0
- data/spec/support/test/multi_field_extensions.proto +33 -0
- data/spec/support/test/resource.pb.rb +117 -0
- data/spec/support/test/resource.proto +94 -0
- data/spec/support/test/resource_service.rb +26 -0
- data/spec/support/test_app_file.rb +2 -0
- data/spec/support/tolerance_matcher.rb +40 -0
- metadata +367 -0
@@ -0,0 +1,53 @@
|
|
1
|
+
##
|
2
|
+
# This file is auto-generated. DO NOT EDIT!
|
3
|
+
#
|
4
|
+
require 'protobuf/message'
|
5
|
+
|
6
|
+
module Protobuf
|
7
|
+
module Socketrpc
|
8
|
+
|
9
|
+
##
|
10
|
+
# Enum Classes
|
11
|
+
#
|
12
|
+
class ErrorReason < ::Protobuf::Enum
|
13
|
+
define :BAD_REQUEST_DATA, 0
|
14
|
+
define :BAD_REQUEST_PROTO, 1
|
15
|
+
define :SERVICE_NOT_FOUND, 2
|
16
|
+
define :METHOD_NOT_FOUND, 3
|
17
|
+
define :RPC_ERROR, 4
|
18
|
+
define :RPC_FAILED, 5
|
19
|
+
define :INVALID_REQUEST_PROTO, 6
|
20
|
+
define :BAD_RESPONSE_PROTO, 7
|
21
|
+
define :UNKNOWN_HOST, 8
|
22
|
+
define :IO_ERROR, 9
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
##
|
27
|
+
# Message Classes
|
28
|
+
#
|
29
|
+
class Request < ::Protobuf::Message; end
|
30
|
+
class Response < ::Protobuf::Message; end
|
31
|
+
|
32
|
+
|
33
|
+
##
|
34
|
+
# Message Fields
|
35
|
+
#
|
36
|
+
class Request
|
37
|
+
required :string, :service_name, 1
|
38
|
+
required :string, :method_name, 2
|
39
|
+
optional :bytes, :request_proto, 3
|
40
|
+
optional :string, :caller, 4
|
41
|
+
end
|
42
|
+
|
43
|
+
class Response
|
44
|
+
optional :bytes, :response_proto, 1
|
45
|
+
optional :string, :error, 2
|
46
|
+
optional :bool, :callback, 3, :default => false
|
47
|
+
optional ::Protobuf::Socketrpc::ErrorReason, :error_reason, 4
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'protobuf'
|
2
|
+
require 'protobuf/logger'
|
3
|
+
require 'protobuf/rpc/rpc.pb'
|
4
|
+
require 'protobuf/rpc/buffer'
|
5
|
+
require 'protobuf/rpc/env'
|
6
|
+
require 'protobuf/rpc/error'
|
7
|
+
require 'protobuf/rpc/middleware'
|
8
|
+
require 'protobuf/rpc/service_dispatcher'
|
9
|
+
|
10
|
+
module Protobuf
|
11
|
+
module Rpc
|
12
|
+
module Server
|
13
|
+
def gc_pause
|
14
|
+
::GC.disable if ::Protobuf.gc_pause_server_request?
|
15
|
+
|
16
|
+
yield
|
17
|
+
|
18
|
+
::GC.enable if ::Protobuf.gc_pause_server_request?
|
19
|
+
end
|
20
|
+
|
21
|
+
# Invoke the service method dictated by the proto wrapper request object
|
22
|
+
#
|
23
|
+
def handle_request(request_data)
|
24
|
+
# Create an env object that holds different parts of the environment and
|
25
|
+
# is available to all of the middlewares
|
26
|
+
env = Env.new('encoded_request' => request_data, 'log_signature' => log_signature)
|
27
|
+
|
28
|
+
# Invoke the middleware stack, the last of which is the service dispatcher
|
29
|
+
env = Rpc.middleware.call(env)
|
30
|
+
|
31
|
+
env.encoded_response
|
32
|
+
end
|
33
|
+
|
34
|
+
def log_signature
|
35
|
+
@_log_signature ||= "[server-#{self.class.name}]"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'protobuf/rpc/server'
|
2
|
+
|
3
|
+
require 'rack'
|
4
|
+
require 'rack/server'
|
5
|
+
|
6
|
+
module Protobuf
|
7
|
+
module Rpc
|
8
|
+
module Http
|
9
|
+
class Server
|
10
|
+
include ::Protobuf::Rpc::Server
|
11
|
+
include ::Protobuf::Logger::LogMethods
|
12
|
+
|
13
|
+
# TODO: more comprehensive mapping?
|
14
|
+
HTTP_STATUSES = {
|
15
|
+
Protobuf::Socketrpc::ErrorReason::BAD_REQUEST_DATA => 400,
|
16
|
+
Protobuf::Socketrpc::ErrorReason::BAD_REQUEST_PROTO => 400,
|
17
|
+
Protobuf::Socketrpc::ErrorReason::SERVICE_NOT_FOUND => 404,
|
18
|
+
Protobuf::Socketrpc::ErrorReason::METHOD_NOT_FOUND => 404,
|
19
|
+
Protobuf::Socketrpc::ErrorReason::RPC_ERROR => 500,
|
20
|
+
Protobuf::Socketrpc::ErrorReason::RPC_FAILED => 500,
|
21
|
+
Protobuf::Socketrpc::ErrorReason::INVALID_REQUEST_PROTO => 500,
|
22
|
+
Protobuf::Socketrpc::ErrorReason::BAD_RESPONSE_PROTO => 500,
|
23
|
+
Protobuf::Socketrpc::ErrorReason::UNKNOWN_HOST => 500,
|
24
|
+
Protobuf::Socketrpc::ErrorReason::IO_ERROR => 500
|
25
|
+
}
|
26
|
+
|
27
|
+
def initialize(options = {})
|
28
|
+
@options = options
|
29
|
+
end
|
30
|
+
|
31
|
+
def log_signature
|
32
|
+
@_log_signature ||= "[http-server-#{self.class.name}]"
|
33
|
+
end
|
34
|
+
|
35
|
+
def call(env)
|
36
|
+
path_components = env['PATH_INFO'].split("/").map{ |x| CGI::unescape(x) }.compact.reject{ |x| x.empty? }
|
37
|
+
if path_components.length < 2
|
38
|
+
return protobuf_http_response 400,
|
39
|
+
:error => "Expected path format /CLASS/METHOD",
|
40
|
+
:reason => Protobuf::Socketrpc::ErrorReason::INVALID_REQUEST_PROTO
|
41
|
+
end
|
42
|
+
|
43
|
+
service_name = path_components[0..-2].join("::")
|
44
|
+
method_name = path_components[-1]
|
45
|
+
|
46
|
+
rpc_request = ::Protobuf::Socketrpc::Request.new(
|
47
|
+
:service_name => service_name,
|
48
|
+
:method_name => method_name,
|
49
|
+
:request_proto => env['rack.input'].read,
|
50
|
+
:caller => env['HTTP_X_PROTOBUF_CALLER'] || ''
|
51
|
+
)
|
52
|
+
|
53
|
+
encoded_request = rpc_request.encode()
|
54
|
+
|
55
|
+
begin
|
56
|
+
encoded_response = handle_request(encoded_request)
|
57
|
+
rescue Exception => e
|
58
|
+
return protobuf_http_response 500,
|
59
|
+
:error => "Handle request failed: #{e.to_s}",
|
60
|
+
:reason => Protobuf::Socketrpc::ErrorReason::RPC_ERROR
|
61
|
+
end
|
62
|
+
|
63
|
+
rpc_response = Protobuf::Socketrpc::Response.decode(encoded_response)
|
64
|
+
|
65
|
+
if rpc_response[:error].length > 0
|
66
|
+
status = HTTP_STATUSES[rpc_response[:error_reason]] or 500
|
67
|
+
return protobuf_http_response status,
|
68
|
+
:error => rpc_response[:error],
|
69
|
+
:reason => rpc_response[:error_reason]
|
70
|
+
end
|
71
|
+
|
72
|
+
return protobuf_http_response 200, :body => rpc_response['response_proto']
|
73
|
+
end
|
74
|
+
|
75
|
+
def protobuf_http_response(status, options)
|
76
|
+
response = [status, { 'Content-Type' => 'application/x-protobuf' }, []]
|
77
|
+
response[1]['X-Protobuf-Error'] = options[:error] unless options[:error].nil?
|
78
|
+
response[1]['X-Protobuf-Error-Reason'] = options[:reason].to_s unless options[:reason].nil?
|
79
|
+
response[2] = [options[:body]] unless options[:body].nil?
|
80
|
+
response
|
81
|
+
end
|
82
|
+
|
83
|
+
def run
|
84
|
+
Rack::Server.start(
|
85
|
+
:app => self,
|
86
|
+
:Host => @options[:host],
|
87
|
+
:Port => @options[:port]
|
88
|
+
)
|
89
|
+
@running = true
|
90
|
+
end
|
91
|
+
|
92
|
+
def running?
|
93
|
+
!!@running
|
94
|
+
end
|
95
|
+
|
96
|
+
def stop
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Protobuf
|
2
|
+
module Rpc
|
3
|
+
class HttpRunner
|
4
|
+
|
5
|
+
def initialize(options)
|
6
|
+
@options = case
|
7
|
+
when options.is_a?(OpenStruct) then
|
8
|
+
options.marshal_dump
|
9
|
+
when options.is_a?(Hash) then
|
10
|
+
options
|
11
|
+
when options.respond_to?(:to_hash) then
|
12
|
+
options.to_hash
|
13
|
+
else
|
14
|
+
raise "Cannot parse HTTP Server - server options"
|
15
|
+
end
|
16
|
+
|
17
|
+
@server = ::Protobuf::Rpc::Http::Server.new(@options)
|
18
|
+
end
|
19
|
+
|
20
|
+
def run
|
21
|
+
yield if block_given?
|
22
|
+
@server.run
|
23
|
+
end
|
24
|
+
|
25
|
+
def running?
|
26
|
+
@server.running?
|
27
|
+
end
|
28
|
+
|
29
|
+
def stop
|
30
|
+
@server.stop
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'protobuf/rpc/server'
|
2
|
+
require 'protobuf/rpc/servers/socket/worker'
|
3
|
+
|
4
|
+
module Protobuf
|
5
|
+
module Rpc
|
6
|
+
module Socket
|
7
|
+
class Server
|
8
|
+
include ::Protobuf::Logger::LogMethods
|
9
|
+
|
10
|
+
AUTO_COLLECT_TIMEOUT = 5 # seconds
|
11
|
+
|
12
|
+
def initialize(options)
|
13
|
+
@options = options
|
14
|
+
end
|
15
|
+
|
16
|
+
def cleanup?
|
17
|
+
# every 10 connections run a cleanup routine after closing the response
|
18
|
+
@threads.size > (@threshold - 1) && (@threads.size % @threshold) == 0
|
19
|
+
end
|
20
|
+
|
21
|
+
def cleanup_threads
|
22
|
+
log_debug { sign_message("Thread cleanup - #{@threads.size} - start") }
|
23
|
+
|
24
|
+
@threads = @threads.select do |t|
|
25
|
+
if t[:thread].alive?
|
26
|
+
true
|
27
|
+
else
|
28
|
+
t[:thread].join
|
29
|
+
@working.delete(t[:socket])
|
30
|
+
false
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
log_debug { sign_message("Thread cleanup - #{@threads.size} - complete") }
|
35
|
+
end
|
36
|
+
|
37
|
+
def log_signature
|
38
|
+
@_log_signature ||= "server-#{self.class.name}"
|
39
|
+
end
|
40
|
+
|
41
|
+
def new_worker(socket)
|
42
|
+
Thread.new(socket) do |sock|
|
43
|
+
::Protobuf::Rpc::Socket::Worker.new(sock) do |s|
|
44
|
+
s.close
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def run
|
50
|
+
log_debug { sign_message("Run") }
|
51
|
+
host = @options[:host]
|
52
|
+
port = @options[:port]
|
53
|
+
backlog = @options[:backlog]
|
54
|
+
@threshold = @options[:threshold]
|
55
|
+
|
56
|
+
@threads = []
|
57
|
+
@server = ::TCPServer.new(host, port)
|
58
|
+
raise "The server was unable to start properly." if @server.closed?
|
59
|
+
|
60
|
+
@server.listen(backlog)
|
61
|
+
@working = []
|
62
|
+
@listen_fds = [@server]
|
63
|
+
@running = true
|
64
|
+
|
65
|
+
while running?
|
66
|
+
log_debug { sign_message("Waiting for connections") }
|
67
|
+
ready_cnxns = IO.select(@listen_fds, [], [], AUTO_COLLECT_TIMEOUT) rescue nil
|
68
|
+
|
69
|
+
if ready_cnxns
|
70
|
+
cnxns = ready_cnxns.first
|
71
|
+
cnxns.each do |client|
|
72
|
+
case
|
73
|
+
when !running? then
|
74
|
+
# no-op
|
75
|
+
when client == @server then
|
76
|
+
log_debug { sign_message("Accepted new connection") }
|
77
|
+
client, sockaddr = @server.accept
|
78
|
+
@listen_fds << client
|
79
|
+
else
|
80
|
+
unless @working.include?(client)
|
81
|
+
@working << @listen_fds.delete(client)
|
82
|
+
log_debug { sign_message("Working") }
|
83
|
+
@threads << { :thread => new_worker(client), :socket => client }
|
84
|
+
|
85
|
+
cleanup_threads if cleanup?
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
else
|
90
|
+
# Run a cleanup if select times out while waiting
|
91
|
+
cleanup_threads if @threads.size > 1
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
rescue Errno::EADDRINUSE
|
96
|
+
raise
|
97
|
+
rescue
|
98
|
+
# Closing the server causes the loop to raise an exception here
|
99
|
+
raise #if running?
|
100
|
+
end
|
101
|
+
|
102
|
+
def running?
|
103
|
+
!!@running
|
104
|
+
end
|
105
|
+
|
106
|
+
def stop
|
107
|
+
@running = false
|
108
|
+
@server.try(:close)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'protobuf/rpc/server'
|
2
|
+
require 'protobuf/logger'
|
3
|
+
|
4
|
+
module Protobuf
|
5
|
+
module Rpc
|
6
|
+
module Socket
|
7
|
+
class Worker
|
8
|
+
include ::Protobuf::Rpc::Server
|
9
|
+
include ::Protobuf::Logger::LogMethods
|
10
|
+
|
11
|
+
def initialize(sock, &complete_cb)
|
12
|
+
@socket = sock
|
13
|
+
@complete_cb = complete_cb
|
14
|
+
|
15
|
+
data = read_data
|
16
|
+
return unless data
|
17
|
+
|
18
|
+
gc_pause do
|
19
|
+
encoded_response = handle_request(data)
|
20
|
+
send_data(encoded_response)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def read_data
|
25
|
+
size_io = StringIO.new
|
26
|
+
|
27
|
+
until (size_reader = @socket.getc) == "-"
|
28
|
+
size_io << size_reader
|
29
|
+
end
|
30
|
+
str_size_io = size_io.string
|
31
|
+
|
32
|
+
@socket.read(str_size_io.to_i)
|
33
|
+
end
|
34
|
+
|
35
|
+
def send_data(data)
|
36
|
+
raise 'Socket closed unexpectedly' unless socket_writable?
|
37
|
+
response_buffer = Protobuf::Rpc::Buffer.new(:write)
|
38
|
+
response_buffer.set_data(data)
|
39
|
+
|
40
|
+
@socket.write(response_buffer.write)
|
41
|
+
@socket.flush
|
42
|
+
|
43
|
+
@complete_cb.call(@socket)
|
44
|
+
end
|
45
|
+
|
46
|
+
def log_signature
|
47
|
+
@_log_signature ||= "server-#{self.class}-#{object_id}"
|
48
|
+
end
|
49
|
+
|
50
|
+
def socket_writable?
|
51
|
+
! @socket.nil? && ! @socket.closed?
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Protobuf
|
2
|
+
module Rpc
|
3
|
+
class SocketRunner
|
4
|
+
|
5
|
+
def initialize(options)
|
6
|
+
@options = case
|
7
|
+
when options.is_a?(OpenStruct) then
|
8
|
+
options.marshal_dump
|
9
|
+
when options.is_a?(Hash) then
|
10
|
+
options
|
11
|
+
when options.respond_to?(:to_hash) then
|
12
|
+
options.to_hash
|
13
|
+
else
|
14
|
+
raise "Cannot parser Socket Server - server options"
|
15
|
+
end
|
16
|
+
|
17
|
+
@server = ::Protobuf::Rpc::Socket::Server.new(@options)
|
18
|
+
end
|
19
|
+
|
20
|
+
def run
|
21
|
+
yield if block_given?
|
22
|
+
@server.run
|
23
|
+
end
|
24
|
+
|
25
|
+
def running?
|
26
|
+
@server.running?
|
27
|
+
end
|
28
|
+
|
29
|
+
def stop
|
30
|
+
@server.stop
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,155 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
module Protobuf
|
4
|
+
module Rpc
|
5
|
+
module Zmq
|
6
|
+
class Broker
|
7
|
+
include ::Protobuf::Rpc::Zmq::Util
|
8
|
+
|
9
|
+
attr_reader :local_queue
|
10
|
+
|
11
|
+
def initialize(server)
|
12
|
+
@server = server
|
13
|
+
|
14
|
+
init_zmq_context
|
15
|
+
init_local_queue
|
16
|
+
init_backend_socket
|
17
|
+
init_frontend_socket
|
18
|
+
init_poller
|
19
|
+
rescue
|
20
|
+
teardown
|
21
|
+
raise
|
22
|
+
end
|
23
|
+
|
24
|
+
def run
|
25
|
+
@idle_workers = []
|
26
|
+
|
27
|
+
loop do
|
28
|
+
unless local_queue.empty?
|
29
|
+
process_local_queue
|
30
|
+
end
|
31
|
+
|
32
|
+
rc = @poller.poll(500)
|
33
|
+
|
34
|
+
# The server was shutdown and no requests are pending
|
35
|
+
break if rc == 0 && !running?
|
36
|
+
|
37
|
+
# Something went wrong
|
38
|
+
break if rc == -1
|
39
|
+
|
40
|
+
@poller.readables.each do |readable|
|
41
|
+
case readable
|
42
|
+
when @frontend_socket
|
43
|
+
process_frontend
|
44
|
+
when @backend_socket
|
45
|
+
process_backend
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
ensure
|
50
|
+
teardown
|
51
|
+
end
|
52
|
+
|
53
|
+
def running?
|
54
|
+
@server.running? || @server.workers.any?
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
def init_backend_socket
|
60
|
+
@backend_socket = @zmq_context.socket(ZMQ::ROUTER)
|
61
|
+
zmq_error_check(@backend_socket.bind(@server.backend_uri))
|
62
|
+
end
|
63
|
+
|
64
|
+
def init_frontend_socket
|
65
|
+
@frontend_socket = @zmq_context.socket(ZMQ::ROUTER)
|
66
|
+
zmq_error_check(@frontend_socket.bind(@server.frontend_uri))
|
67
|
+
end
|
68
|
+
|
69
|
+
def init_local_queue
|
70
|
+
@local_queue = ::Queue.new
|
71
|
+
end
|
72
|
+
|
73
|
+
def init_poller
|
74
|
+
@poller = ZMQ::Poller.new
|
75
|
+
@poller.register_readable(@frontend_socket)
|
76
|
+
@poller.register_readable(@backend_socket)
|
77
|
+
end
|
78
|
+
|
79
|
+
def init_zmq_context
|
80
|
+
if inproc?
|
81
|
+
@zmq_context = @server.zmq_context
|
82
|
+
else
|
83
|
+
@zmq_context = ZMQ::Context.new
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def inproc?
|
88
|
+
!!@server.try(:inproc?)
|
89
|
+
end
|
90
|
+
|
91
|
+
def process_backend
|
92
|
+
worker, ignore, *frames = read_from_backend
|
93
|
+
|
94
|
+
@idle_workers << worker
|
95
|
+
|
96
|
+
unless frames == [::Protobuf::Rpc::Zmq::WORKER_READY_MESSAGE]
|
97
|
+
write_to_frontend(frames)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def process_frontend
|
102
|
+
address, _, message, *frames = read_from_frontend
|
103
|
+
|
104
|
+
if message == ::Protobuf::Rpc::Zmq::CHECK_AVAILABLE_MESSAGE
|
105
|
+
if @idle_workers.any? || local_queue.empty?
|
106
|
+
write_to_frontend([address, "", ::Protobuf::Rpc::Zmq::WORKERS_AVAILABLE])
|
107
|
+
else
|
108
|
+
write_to_frontend([address, "", ::Protobuf::Rpc::Zmq::NO_WORKERS_AVAILABLE])
|
109
|
+
end
|
110
|
+
else
|
111
|
+
if @idle_workers.any?
|
112
|
+
write_to_backend([@idle_workers.shift, ""] + [address, "", message ] + frames)
|
113
|
+
else
|
114
|
+
local_queue.push([address, "", message ] + frames)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
def process_local_queue
|
120
|
+
return if local_queue.empty?
|
121
|
+
return if @idle_workers.empty?
|
122
|
+
|
123
|
+
write_to_backend([@idle_workers.shift, ""] + local_queue.pop)
|
124
|
+
process_local_queue
|
125
|
+
end
|
126
|
+
|
127
|
+
def read_from_backend
|
128
|
+
frames = []
|
129
|
+
zmq_error_check(@backend_socket.recv_strings(frames))
|
130
|
+
frames
|
131
|
+
end
|
132
|
+
|
133
|
+
def read_from_frontend
|
134
|
+
frames = []
|
135
|
+
zmq_error_check(@frontend_socket.recv_strings(frames))
|
136
|
+
frames
|
137
|
+
end
|
138
|
+
|
139
|
+
def teardown
|
140
|
+
@frontend_socket.try(:close)
|
141
|
+
@backend_socket.try(:close)
|
142
|
+
@zmq_context.try(:terminate)
|
143
|
+
end
|
144
|
+
|
145
|
+
def write_to_backend(frames)
|
146
|
+
zmq_error_check(@backend_socket.send_strings(frames))
|
147
|
+
end
|
148
|
+
|
149
|
+
def write_to_frontend(frames)
|
150
|
+
zmq_error_check(@frontend_socket.send_strings(frames))
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|