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,28 @@
1
+ require 'protobuf/rpc/rpc.pb'
2
+
3
+ module Protobuf
4
+ module Rpc
5
+ ClientError = Struct.new("ClientError", :code, :message)
6
+
7
+ # Base PbError class for client and server errors
8
+ class PbError < StandardError
9
+ attr_reader :error_type
10
+
11
+ def initialize(message='An unknown RpcError occurred', error_type='RPC_ERROR')
12
+ @error_type = error_type.is_a?(String) ? Socketrpc::ErrorReason.const_get(error_type) : error_type
13
+ super message
14
+ end
15
+
16
+ def encode
17
+ to_response.encode
18
+ end
19
+
20
+ def to_response
21
+ Socketrpc::Response.new(:error => message, :error_reason => error_type)
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ require 'protobuf/rpc/error/server_error'
28
+ require 'protobuf/rpc/error/client_error'
@@ -0,0 +1,31 @@
1
+ require 'protobuf/rpc/error'
2
+
3
+ module Protobuf
4
+ module Rpc
5
+
6
+ class InvalidRequestProto < PbError
7
+ def initialize(message='Invalid request type given')
8
+ super message, 'INVALID_REQUEST_PROTO'
9
+ end
10
+ end
11
+
12
+ class BadResponseProto < PbError
13
+ def initialize(message='Bad response type from server')
14
+ super message, 'BAD_RESPONSE_PROTO'
15
+ end
16
+ end
17
+
18
+ class UnkownHost < PbError
19
+ def initialize(message='Unknown host or port')
20
+ super message, 'UNKNOWN_HOST'
21
+ end
22
+ end
23
+
24
+ class IOError < PbError
25
+ def initialize(message='IO Error occurred')
26
+ super message, 'IO_ERROR'
27
+ end
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,43 @@
1
+ require 'protobuf/rpc/rpc.pb'
2
+
3
+ module Protobuf
4
+ module Rpc
5
+
6
+ class BadRequestData < PbError
7
+ def initialize message='Unable to parse request'
8
+ super message, 'BAD_REQUEST_DATA'
9
+ end
10
+ end
11
+
12
+ class BadRequestProto < PbError
13
+ def initialize message='Request is of wrong type'
14
+ super message, 'BAD_REQUEST_PROTO'
15
+ end
16
+ end
17
+
18
+ class ServiceNotFound < PbError
19
+ def initialize message='Service class not found'
20
+ super message, 'SERVICE_NOT_FOUND'
21
+ end
22
+ end
23
+
24
+ class MethodNotFound < PbError
25
+ def initialize message='Service method not found'
26
+ super message, 'METHOD_NOT_FOUND'
27
+ end
28
+ end
29
+
30
+ class RpcError < PbError
31
+ def initialize message='RPC exception occurred'
32
+ super message, 'RPC_ERROR'
33
+ end
34
+ end
35
+
36
+ class RpcFailed < PbError
37
+ def initialize message='RPC failed'
38
+ super message, 'RPC_FAILED'
39
+ end
40
+ end
41
+
42
+ end
43
+ end
@@ -0,0 +1,25 @@
1
+ require 'middleware'
2
+
3
+ require 'protobuf/rpc/middleware/exception_handler'
4
+ require 'protobuf/rpc/middleware/logger'
5
+ require 'protobuf/rpc/middleware/request_decoder'
6
+ require 'protobuf/rpc/middleware/response_encoder'
7
+ require 'protobuf/rpc/middleware/runner'
8
+
9
+ module Protobuf
10
+ module Rpc
11
+ def self.middleware
12
+ @middleware ||= ::Middleware::Builder.new(:runner_class => ::Protobuf::Rpc::Middleware::Runner)
13
+ end
14
+
15
+ # Ensure the middleware stack is initialized
16
+ middleware
17
+ end
18
+
19
+ Rpc.middleware.use(Rpc::Middleware::ExceptionHandler)
20
+ Rpc.middleware.use(Rpc::Middleware::RequestDecoder)
21
+ Rpc.middleware.use(Rpc::Middleware::Logger)
22
+ Rpc.middleware.use(Rpc::Middleware::ResponseEncoder)
23
+
24
+ ActiveSupport.run_load_hooks(:protobuf_rpc_middleware, Rpc)
25
+ end
@@ -0,0 +1,36 @@
1
+ module Protobuf
2
+ module Rpc
3
+ module Middleware
4
+ class ExceptionHandler
5
+ include ::Protobuf::Logger::LogMethods
6
+
7
+ attr_reader :app
8
+
9
+ def initialize(app)
10
+ @app = app
11
+ end
12
+
13
+ def call(env)
14
+ app.call(env)
15
+ rescue => exception
16
+ log_exception(exception)
17
+
18
+ # Rescue exceptions, re-wrap them as generic Protobuf errors,
19
+ # and encode them
20
+ env.response = wrap_exception(exception)
21
+ env.encoded_response = env.response.encode
22
+ env
23
+ end
24
+
25
+ private
26
+
27
+ # Wrap exceptions in a generic Protobuf errors unless they already are
28
+ #
29
+ def wrap_exception(exception)
30
+ exception = RpcFailed.new(exception.message) unless exception.is_a?(PbError)
31
+ exception
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,91 @@
1
+ module Protobuf
2
+ module Rpc
3
+ module Middleware
4
+ class Logger
5
+ def initialize(app)
6
+ @app = app
7
+ end
8
+
9
+ # TODO: Figure out how to control when logs are flushed
10
+ def call(env)
11
+ instrumenter.start
12
+ instrumenter.flush(env) # Log request stats
13
+
14
+ env = @app.call(env)
15
+
16
+ instrumenter.stop
17
+ instrumenter.flush(env) # Log response stats
18
+
19
+ env
20
+ end
21
+
22
+ private
23
+
24
+ def instrumenter
25
+ @instrumenter ||= Instrumenter.new
26
+ end
27
+
28
+ # TODO: Replace this with ActiveSupport::Notifications and log subscribers
29
+ # TODO: Consider adopting Rails-style logging so we can track serialization
30
+ # time as well as ActiveRecord time, etc.:
31
+ #
32
+ # Started GET "/" for 127.0.0.1 at 2014-02-12 09:40:29 -0700
33
+ # Processing by ReleasesController#index as HTML
34
+ # Rendered releases/_release.html.erb (0.0ms)
35
+ # Rendered releases/_release.html.erb (0.0ms)
36
+ # Rendered releases/_release.html.erb (0.0ms)
37
+ # Rendered releases/_release.html.erb (0.0ms)
38
+ # Rendered releases/index.html.erb within layouts/application (11.0ms)
39
+ # Completed 200 OK in 142ms (Views: 117.6ms | ActiveRecord: 1.7ms)
40
+ #
41
+ class Instrumenter
42
+ attr_reader :env
43
+
44
+ def flush(env)
45
+ Protobuf::Logger.info { to_s(env) }
46
+ end
47
+
48
+ def start
49
+ @start_time = ::Time.now.utc
50
+ end
51
+
52
+ def stop
53
+ @end_time = ::Time.now.utc
54
+ end
55
+
56
+ def to_s(env)
57
+ @env = env
58
+
59
+ [
60
+ "[SRV]",
61
+ env.client_host,
62
+ env.worker_id,
63
+ rpc,
64
+ sizes,
65
+ elapsed_time,
66
+ @end_time.try(:iso8601)
67
+ ].compact.join(' - ')
68
+ end
69
+
70
+ private
71
+
72
+ def elapsed_time
73
+ (@start_time && @end_time ? "#{(@end_time - @start_time).round(4)}s" : nil)
74
+ end
75
+
76
+ def rpc
77
+ env.service_name && env.method_name ? "#{env.service_name}##{env.method_name}" : nil
78
+ end
79
+
80
+ def sizes
81
+ if env.encoded_response?
82
+ "#{env.encoded_request.size}B/#{env.encoded_response.size}B"
83
+ else
84
+ "#{env.encoded_request.size}B/-"
85
+ end
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,83 @@
1
+ module Protobuf
2
+ module Rpc
3
+ module Middleware
4
+ class RequestDecoder
5
+ include ::Protobuf::Logger::LogMethods
6
+
7
+ attr_reader :app, :env
8
+
9
+ def initialize(app)
10
+ @app = app
11
+ end
12
+
13
+ def call(env)
14
+ @env = env
15
+
16
+ env.service_name = service_name
17
+ env.method_name = method_name
18
+ env.request = request
19
+ env.client_host = request_wrapper.caller
20
+
21
+ env.rpc_service = service
22
+ env.rpc_method = rpc_method
23
+ env.request_type = rpc_method.request_type
24
+ env.response_type = rpc_method.response_type
25
+
26
+ app.call(env)
27
+ end
28
+
29
+ def log_signature
30
+ env.signature || super
31
+ end
32
+
33
+ private
34
+
35
+ def method_name
36
+ @method_name ||= begin
37
+ method_name = request_wrapper.method_name.underscore.to_sym
38
+
39
+ unless service.rpc_method?(method_name)
40
+ raise MethodNotFound.new("#{service.name}##{method_name} is not a defined RPC method.")
41
+ end
42
+
43
+ method_name
44
+ end
45
+ end
46
+
47
+ def request
48
+ @request ||= begin
49
+ data = request_wrapper.request_proto
50
+ rpc_method.request_type.decode(data)
51
+ end
52
+ rescue => exception
53
+ raise BadRequestData.new("Unable to decode request: #{exception.message}")
54
+ end
55
+
56
+ # Decode the incoming request object into our expected request object
57
+ #
58
+ def request_wrapper
59
+ @request_wrapper ||= begin
60
+ log_debug { sign_message("Decoding request: #{env.encoded_request}") }
61
+ Socketrpc::Request.decode(env.encoded_request)
62
+ end
63
+ rescue => exception
64
+ raise BadRequestData.new("Unable to decode request: #{exception.message}")
65
+ end
66
+
67
+ def rpc_method
68
+ @rpc_method ||= service.rpcs[method_name]
69
+ end
70
+
71
+ def service
72
+ @service ||= service_name.constantize
73
+ rescue NameError
74
+ raise ServiceNotFound.new("Service class #{service_name} is not defined.")
75
+ end
76
+
77
+ def service_name
78
+ @service_name ||= request_wrapper.service_name
79
+ end
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,88 @@
1
+ module Protobuf
2
+ module Rpc
3
+ module Middleware
4
+ class ResponseEncoder
5
+ include ::Protobuf::Logger::LogMethods
6
+
7
+ attr_reader :app, :env
8
+
9
+ def initialize(app)
10
+ @app = app
11
+ end
12
+
13
+ def call(env)
14
+ @env = app.call(env)
15
+
16
+ env.response = response
17
+ env.encoded_response = encoded_response
18
+ env
19
+ end
20
+
21
+ def log_signature
22
+ env.signature || super
23
+ end
24
+
25
+ private
26
+
27
+ # Encode the response wrapper to return to the client
28
+ #
29
+ def encoded_response
30
+ log_debug { sign_message("Encoding response: #{response.inspect}") }
31
+
32
+ env.encoded_response = wrapped_response.encode
33
+ rescue => exception
34
+ log_exception(exception)
35
+
36
+ # Rescue encoding exceptions, re-wrap them as generic protobuf errors,
37
+ # and re-raise them
38
+ raise PbError.new(exception.message)
39
+ end
40
+
41
+ # Prod the object to see if we can produce a proto object as a response
42
+ # candidate. Validate the candidate protos.
43
+ def response
44
+ @response ||= begin
45
+ candidate = env.response
46
+ case
47
+ when candidate.is_a?(Message) then
48
+ validate!(candidate)
49
+ when candidate.respond_to?(:to_proto) then
50
+ validate!(candidate.to_proto)
51
+ when candidate.respond_to?(:to_hash) then
52
+ env.response_type.new(candidate.to_hash)
53
+ when candidate.is_a?(PbError) then
54
+ candidate
55
+ else
56
+ validate!(candidate)
57
+ end
58
+ end
59
+ end
60
+
61
+ # Ensure that the response candidate we've been given is of the type
62
+ # we expect so that deserialization on the client side works.
63
+ #
64
+ def validate!(candidate)
65
+ actual = candidate.class
66
+ expected = env.response_type
67
+
68
+ if expected != actual
69
+ raise BadResponseProto.new("Expected response to be of type #{expected.name} but was #{actual.name}")
70
+ end
71
+
72
+ candidate
73
+ end
74
+
75
+ # The middleware stack returns either an error or response proto. Package
76
+ # it up so that it's in the correct spot in the response wrapper
77
+ #
78
+ def wrapped_response
79
+ if response.is_a?(Protobuf::Rpc::PbError)
80
+ Socketrpc::Response.new(:error => response.message, :error_reason => response.error_type)
81
+ else
82
+ Socketrpc::Response.new(:response_proto => response.encode)
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,18 @@
1
+ require 'middleware/runner'
2
+
3
+ module Protobuf
4
+ module Rpc
5
+ module Middleware
6
+ class Runner < ::Middleware::Runner
7
+ # Override the default middleware runner so we can ensure that the
8
+ # service dispatcher is the last thing called in the stack.
9
+ #
10
+ def initialize(stack)
11
+ stack << Protobuf::Rpc::ServiceDispatcher
12
+
13
+ super(stack)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end