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.
Files changed (192) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.travis.yml +12 -0
  4. data/.yardopts +5 -0
  5. data/CHANGES.md +261 -0
  6. data/CONTRIBUTING.md +16 -0
  7. data/Gemfile +3 -0
  8. data/LICENSE.txt +14 -0
  9. data/README.md +58 -0
  10. data/Rakefile +61 -0
  11. data/bin/protoc-gen-ruby +17 -0
  12. data/bin/rpc_server +4 -0
  13. data/examples/bin/reverse-client-http +4 -0
  14. data/examples/bin/reverse-client-socket +4 -0
  15. data/examples/bin/reverse-client-zmq +4 -0
  16. data/examples/config.ru +6 -0
  17. data/examples/definitions/example/reverse.proto +12 -0
  18. data/examples/lib/example/reverse-client.rb +23 -0
  19. data/examples/lib/example/reverse-service.rb +9 -0
  20. data/examples/lib/example/reverse.pb.rb +36 -0
  21. data/lib/protobuf.rb +106 -0
  22. data/lib/protobuf/cli.rb +249 -0
  23. data/lib/protobuf/code_generator.rb +41 -0
  24. data/lib/protobuf/decoder.rb +74 -0
  25. data/lib/protobuf/deprecator.rb +42 -0
  26. data/lib/protobuf/descriptors.rb +3 -0
  27. data/lib/protobuf/descriptors/google/protobuf/compiler/plugin.pb.rb +52 -0
  28. data/lib/protobuf/descriptors/google/protobuf/descriptor.pb.rb +249 -0
  29. data/lib/protobuf/encoder.rb +62 -0
  30. data/lib/protobuf/enum.rb +319 -0
  31. data/lib/protobuf/exceptions.rb +9 -0
  32. data/lib/protobuf/field.rb +74 -0
  33. data/lib/protobuf/field/base_field.rb +280 -0
  34. data/lib/protobuf/field/bool_field.rb +53 -0
  35. data/lib/protobuf/field/bytes_field.rb +81 -0
  36. data/lib/protobuf/field/double_field.rb +26 -0
  37. data/lib/protobuf/field/enum_field.rb +57 -0
  38. data/lib/protobuf/field/field_array.rb +86 -0
  39. data/lib/protobuf/field/fixed32_field.rb +25 -0
  40. data/lib/protobuf/field/fixed64_field.rb +29 -0
  41. data/lib/protobuf/field/float_field.rb +38 -0
  42. data/lib/protobuf/field/int32_field.rb +22 -0
  43. data/lib/protobuf/field/int64_field.rb +22 -0
  44. data/lib/protobuf/field/integer_field.rb +24 -0
  45. data/lib/protobuf/field/message_field.rb +66 -0
  46. data/lib/protobuf/field/sfixed32_field.rb +28 -0
  47. data/lib/protobuf/field/sfixed64_field.rb +29 -0
  48. data/lib/protobuf/field/signed_integer_field.rb +30 -0
  49. data/lib/protobuf/field/sint32_field.rb +22 -0
  50. data/lib/protobuf/field/sint64_field.rb +22 -0
  51. data/lib/protobuf/field/string_field.rb +35 -0
  52. data/lib/protobuf/field/uint32_field.rb +22 -0
  53. data/lib/protobuf/field/uint64_field.rb +22 -0
  54. data/lib/protobuf/field/varint_field.rb +68 -0
  55. data/lib/protobuf/generators/base.rb +71 -0
  56. data/lib/protobuf/generators/enum_generator.rb +42 -0
  57. data/lib/protobuf/generators/extension_generator.rb +28 -0
  58. data/lib/protobuf/generators/field_generator.rb +132 -0
  59. data/lib/protobuf/generators/file_generator.rb +140 -0
  60. data/lib/protobuf/generators/group_generator.rb +113 -0
  61. data/lib/protobuf/generators/message_generator.rb +99 -0
  62. data/lib/protobuf/generators/printable.rb +161 -0
  63. data/lib/protobuf/generators/service_generator.rb +27 -0
  64. data/lib/protobuf/http.rb +20 -0
  65. data/lib/protobuf/lifecycle.rb +46 -0
  66. data/lib/protobuf/logger.rb +86 -0
  67. data/lib/protobuf/message.rb +182 -0
  68. data/lib/protobuf/message/fields.rb +122 -0
  69. data/lib/protobuf/message/serialization.rb +84 -0
  70. data/lib/protobuf/optionable.rb +23 -0
  71. data/lib/protobuf/rpc/buffer.rb +79 -0
  72. data/lib/protobuf/rpc/client.rb +168 -0
  73. data/lib/protobuf/rpc/connector.rb +21 -0
  74. data/lib/protobuf/rpc/connectors/base.rb +54 -0
  75. data/lib/protobuf/rpc/connectors/common.rb +172 -0
  76. data/lib/protobuf/rpc/connectors/http.rb +90 -0
  77. data/lib/protobuf/rpc/connectors/socket.rb +73 -0
  78. data/lib/protobuf/rpc/connectors/zmq.rb +205 -0
  79. data/lib/protobuf/rpc/dynamic_discovery.pb.rb +47 -0
  80. data/lib/protobuf/rpc/env.rb +58 -0
  81. data/lib/protobuf/rpc/error.rb +28 -0
  82. data/lib/protobuf/rpc/error/client_error.rb +31 -0
  83. data/lib/protobuf/rpc/error/server_error.rb +43 -0
  84. data/lib/protobuf/rpc/middleware.rb +25 -0
  85. data/lib/protobuf/rpc/middleware/exception_handler.rb +36 -0
  86. data/lib/protobuf/rpc/middleware/logger.rb +91 -0
  87. data/lib/protobuf/rpc/middleware/request_decoder.rb +83 -0
  88. data/lib/protobuf/rpc/middleware/response_encoder.rb +88 -0
  89. data/lib/protobuf/rpc/middleware/runner.rb +18 -0
  90. data/lib/protobuf/rpc/rpc.pb.rb +53 -0
  91. data/lib/protobuf/rpc/server.rb +39 -0
  92. data/lib/protobuf/rpc/servers/http/server.rb +101 -0
  93. data/lib/protobuf/rpc/servers/http_runner.rb +34 -0
  94. data/lib/protobuf/rpc/servers/socket/server.rb +113 -0
  95. data/lib/protobuf/rpc/servers/socket/worker.rb +56 -0
  96. data/lib/protobuf/rpc/servers/socket_runner.rb +34 -0
  97. data/lib/protobuf/rpc/servers/zmq/broker.rb +155 -0
  98. data/lib/protobuf/rpc/servers/zmq/server.rb +313 -0
  99. data/lib/protobuf/rpc/servers/zmq/util.rb +47 -0
  100. data/lib/protobuf/rpc/servers/zmq/worker.rb +105 -0
  101. data/lib/protobuf/rpc/servers/zmq_runner.rb +51 -0
  102. data/lib/protobuf/rpc/service.rb +179 -0
  103. data/lib/protobuf/rpc/service_directory.rb +245 -0
  104. data/lib/protobuf/rpc/service_dispatcher.rb +46 -0
  105. data/lib/protobuf/rpc/service_filters.rb +273 -0
  106. data/lib/protobuf/rpc/stat.rb +148 -0
  107. data/lib/protobuf/socket.rb +22 -0
  108. data/lib/protobuf/tasks.rb +1 -0
  109. data/lib/protobuf/tasks/compile.rake +61 -0
  110. data/lib/protobuf/version.rb +3 -0
  111. data/lib/protobuf/wire_type.rb +10 -0
  112. data/lib/protobuf/zmq.rb +21 -0
  113. data/proto/dynamic_discovery.proto +44 -0
  114. data/proto/google/protobuf/compiler/plugin.proto +147 -0
  115. data/proto/google/protobuf/descriptor.proto +620 -0
  116. data/proto/rpc.proto +62 -0
  117. data/protobuffy.gemspec +37 -0
  118. data/spec/benchmark/tasks.rb +113 -0
  119. data/spec/bin/protoc-gen-ruby_spec.rb +18 -0
  120. data/spec/data/data.bin +3 -0
  121. data/spec/data/types.bin +0 -0
  122. data/spec/encoding/all_types_spec.rb +91 -0
  123. data/spec/encoding/extreme_values_spec.rb +0 -0
  124. data/spec/functional/socket_server_spec.rb +59 -0
  125. data/spec/functional/zmq_server_spec.rb +103 -0
  126. data/spec/lib/protobuf/cli_spec.rb +267 -0
  127. data/spec/lib/protobuf/code_generator_spec.rb +60 -0
  128. data/spec/lib/protobuf/enum_spec.rb +239 -0
  129. data/spec/lib/protobuf/field/int32_field_spec.rb +7 -0
  130. data/spec/lib/protobuf/field/string_field_spec.rb +46 -0
  131. data/spec/lib/protobuf/field_spec.rb +194 -0
  132. data/spec/lib/protobuf/generators/base_spec.rb +87 -0
  133. data/spec/lib/protobuf/generators/enum_generator_spec.rb +68 -0
  134. data/spec/lib/protobuf/generators/extension_generator_spec.rb +43 -0
  135. data/spec/lib/protobuf/generators/field_generator_spec.rb +99 -0
  136. data/spec/lib/protobuf/generators/file_generator_spec.rb +29 -0
  137. data/spec/lib/protobuf/generators/message_generator_spec.rb +0 -0
  138. data/spec/lib/protobuf/generators/service_generator_spec.rb +43 -0
  139. data/spec/lib/protobuf/lifecycle_spec.rb +89 -0
  140. data/spec/lib/protobuf/logger_spec.rb +136 -0
  141. data/spec/lib/protobuf/message_spec.rb +368 -0
  142. data/spec/lib/protobuf/optionable_spec.rb +46 -0
  143. data/spec/lib/protobuf/rpc/client_spec.rb +66 -0
  144. data/spec/lib/protobuf/rpc/connector_spec.rb +26 -0
  145. data/spec/lib/protobuf/rpc/connectors/base_spec.rb +50 -0
  146. data/spec/lib/protobuf/rpc/connectors/common_spec.rb +170 -0
  147. data/spec/lib/protobuf/rpc/connectors/connector_spec.rb +13 -0
  148. data/spec/lib/protobuf/rpc/connectors/http_spec.rb +61 -0
  149. data/spec/lib/protobuf/rpc/connectors/socket_spec.rb +24 -0
  150. data/spec/lib/protobuf/rpc/connectors/zmq_spec.rb +129 -0
  151. data/spec/lib/protobuf/rpc/middleware/exception_handler_spec.rb +62 -0
  152. data/spec/lib/protobuf/rpc/middleware/logger_spec.rb +49 -0
  153. data/spec/lib/protobuf/rpc/middleware/request_decoder_spec.rb +115 -0
  154. data/spec/lib/protobuf/rpc/middleware/response_encoder_spec.rb +75 -0
  155. data/spec/lib/protobuf/rpc/servers/http/server_spec.rb +104 -0
  156. data/spec/lib/protobuf/rpc/servers/socket_server_spec.rb +38 -0
  157. data/spec/lib/protobuf/rpc/servers/zmq/server_spec.rb +41 -0
  158. data/spec/lib/protobuf/rpc/servers/zmq/util_spec.rb +55 -0
  159. data/spec/lib/protobuf/rpc/servers/zmq/worker_spec.rb +35 -0
  160. data/spec/lib/protobuf/rpc/service_directory_spec.rb +295 -0
  161. data/spec/lib/protobuf/rpc/service_dispatcher_spec.rb +52 -0
  162. data/spec/lib/protobuf/rpc/service_filters_spec.rb +484 -0
  163. data/spec/lib/protobuf/rpc/service_spec.rb +161 -0
  164. data/spec/lib/protobuf/rpc/stat_spec.rb +151 -0
  165. data/spec/lib/protobuf_spec.rb +78 -0
  166. data/spec/spec_helper.rb +57 -0
  167. data/spec/support/all.rb +7 -0
  168. data/spec/support/packed_field.rb +22 -0
  169. data/spec/support/server.rb +94 -0
  170. data/spec/support/test/all_types.data.bin +0 -0
  171. data/spec/support/test/all_types.data.txt +119 -0
  172. data/spec/support/test/defaults.pb.rb +25 -0
  173. data/spec/support/test/defaults.proto +9 -0
  174. data/spec/support/test/enum.pb.rb +59 -0
  175. data/spec/support/test/enum.proto +34 -0
  176. data/spec/support/test/extended.pb.rb +22 -0
  177. data/spec/support/test/extended.proto +10 -0
  178. data/spec/support/test/extreme_values.data.bin +0 -0
  179. data/spec/support/test/google_unittest.pb.rb +543 -0
  180. data/spec/support/test/google_unittest.proto +713 -0
  181. data/spec/support/test/google_unittest_import.pb.rb +37 -0
  182. data/spec/support/test/google_unittest_import.proto +64 -0
  183. data/spec/support/test/google_unittest_import_public.pb.rb +8 -0
  184. data/spec/support/test/google_unittest_import_public.proto +38 -0
  185. data/spec/support/test/multi_field_extensions.pb.rb +56 -0
  186. data/spec/support/test/multi_field_extensions.proto +33 -0
  187. data/spec/support/test/resource.pb.rb +117 -0
  188. data/spec/support/test/resource.proto +94 -0
  189. data/spec/support/test/resource_service.rb +26 -0
  190. data/spec/support/test_app_file.rb +2 -0
  191. data/spec/support/tolerance_matcher.rb +40 -0
  192. 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