protobuf 2.2.5-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (256) hide show
  1. data/.gitignore +17 -0
  2. data/.travis.yml +9 -0
  3. data/.yardopts +5 -0
  4. data/Gemfile +3 -0
  5. data/README.md +316 -0
  6. data/Rakefile +29 -0
  7. data/UPGRADING.md +60 -0
  8. data/bin/rpc_server +5 -0
  9. data/bin/rprotoc +62 -0
  10. data/examples/addressbook.pb.rb +55 -0
  11. data/examples/addressbook.proto +24 -0
  12. data/examples/reading_a_message.rb +32 -0
  13. data/examples/writing_a_message.rb +46 -0
  14. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/code_generator.h +142 -0
  15. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/command_line_interface.h +318 -0
  16. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/cpp/cpp_enum.h +99 -0
  17. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/cpp/cpp_enum_field.h +103 -0
  18. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/cpp/cpp_extension.h +85 -0
  19. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/cpp/cpp_field.h +167 -0
  20. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/cpp/cpp_file.h +98 -0
  21. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/cpp/cpp_generator.h +72 -0
  22. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/cpp/cpp_helpers.h +159 -0
  23. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/cpp/cpp_message.h +170 -0
  24. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/cpp/cpp_message_field.h +102 -0
  25. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/cpp/cpp_primitive_field.h +103 -0
  26. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/cpp/cpp_service.h +118 -0
  27. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/cpp/cpp_string_field.h +104 -0
  28. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/cpp/cpp_test_bad_identifiers.pb.h +2721 -0
  29. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/importer.h +303 -0
  30. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/java/java_enum.h +84 -0
  31. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/java/java_enum_field.h +121 -0
  32. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/java/java_extension.h +77 -0
  33. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/java/java_field.h +108 -0
  34. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/java/java_file.h +101 -0
  35. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/java/java_generator.h +72 -0
  36. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/java/java_helpers.h +213 -0
  37. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/java/java_message.h +109 -0
  38. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/java/java_message_field.h +134 -0
  39. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/java/java_primitive_field.h +121 -0
  40. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/java/java_service.h +113 -0
  41. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/java/java_string_field.h +120 -0
  42. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/mock_code_generator.h +113 -0
  43. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/package_info.h +64 -0
  44. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/parser.h +434 -0
  45. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/plugin.h +73 -0
  46. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/plugin.pb.h +790 -0
  47. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/python/python_generator.h +156 -0
  48. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/subprocess.h +108 -0
  49. data/ext/protobuf-2.4.1/src/google/protobuf/compiler/zip_writer.h +93 -0
  50. data/ext/protobuf-2.4.1/src/google/protobuf/descriptor.h +1367 -0
  51. data/ext/protobuf-2.4.1/src/google/protobuf/descriptor.pb.h +5223 -0
  52. data/ext/protobuf-2.4.1/src/google/protobuf/descriptor_database.h +366 -0
  53. data/ext/protobuf-2.4.1/src/google/protobuf/dynamic_message.h +136 -0
  54. data/ext/protobuf-2.4.1/src/google/protobuf/extension_set.h +904 -0
  55. data/ext/protobuf-2.4.1/src/google/protobuf/generated_message_reflection.h +424 -0
  56. data/ext/protobuf-2.4.1/src/google/protobuf/generated_message_util.h +82 -0
  57. data/ext/protobuf-2.4.1/src/google/protobuf/io/coded_stream.h +1102 -0
  58. data/ext/protobuf-2.4.1/src/google/protobuf/io/coded_stream_inl.h +64 -0
  59. data/ext/protobuf-2.4.1/src/google/protobuf/io/gzip_stream.h +207 -0
  60. data/ext/protobuf-2.4.1/src/google/protobuf/io/package_info.h +54 -0
  61. data/ext/protobuf-2.4.1/src/google/protobuf/io/printer.h +136 -0
  62. data/ext/protobuf-2.4.1/src/google/protobuf/io/tokenizer.h +313 -0
  63. data/ext/protobuf-2.4.1/src/google/protobuf/io/zero_copy_stream.h +238 -0
  64. data/ext/protobuf-2.4.1/src/google/protobuf/io/zero_copy_stream_impl.h +357 -0
  65. data/ext/protobuf-2.4.1/src/google/protobuf/io/zero_copy_stream_impl_lite.h +340 -0
  66. data/ext/protobuf-2.4.1/src/google/protobuf/message.h +692 -0
  67. data/ext/protobuf-2.4.1/src/google/protobuf/message_lite.h +239 -0
  68. data/ext/protobuf-2.4.1/src/google/protobuf/package_info.h +64 -0
  69. data/ext/protobuf-2.4.1/src/google/protobuf/reflection_ops.h +80 -0
  70. data/ext/protobuf-2.4.1/src/google/protobuf/repeated_field.h +1295 -0
  71. data/ext/protobuf-2.4.1/src/google/protobuf/service.h +291 -0
  72. data/ext/protobuf-2.4.1/src/google/protobuf/stubs/common.h +1211 -0
  73. data/ext/protobuf-2.4.1/src/google/protobuf/stubs/hash.h +220 -0
  74. data/ext/protobuf-2.4.1/src/google/protobuf/stubs/map-util.h +119 -0
  75. data/ext/protobuf-2.4.1/src/google/protobuf/stubs/once.h +123 -0
  76. data/ext/protobuf-2.4.1/src/google/protobuf/stubs/stl_util-inl.h +121 -0
  77. data/ext/protobuf-2.4.1/src/google/protobuf/stubs/strutil.h +457 -0
  78. data/ext/protobuf-2.4.1/src/google/protobuf/stubs/substitute.h +170 -0
  79. data/ext/protobuf-2.4.1/src/google/protobuf/test_util.h +174 -0
  80. data/ext/protobuf-2.4.1/src/google/protobuf/test_util_lite.h +101 -0
  81. data/ext/protobuf-2.4.1/src/google/protobuf/testing/file.h +83 -0
  82. data/ext/protobuf-2.4.1/src/google/protobuf/testing/googletest.h +98 -0
  83. data/ext/protobuf-2.4.1/src/google/protobuf/text_format.h +285 -0
  84. data/ext/protobuf-2.4.1/src/google/protobuf/unittest.pb.h +11915 -0
  85. data/ext/protobuf-2.4.1/src/google/protobuf/unittest_custom_options.pb.h +2895 -0
  86. data/ext/protobuf-2.4.1/src/google/protobuf/unittest_embed_optimize_for.pb.h +211 -0
  87. data/ext/protobuf-2.4.1/src/google/protobuf/unittest_empty.pb.h +56 -0
  88. data/ext/protobuf-2.4.1/src/google/protobuf/unittest_import.pb.h +188 -0
  89. data/ext/protobuf-2.4.1/src/google/protobuf/unittest_import_lite.pb.h +151 -0
  90. data/ext/protobuf-2.4.1/src/google/protobuf/unittest_lite.pb.h +4752 -0
  91. data/ext/protobuf-2.4.1/src/google/protobuf/unittest_lite_imports_nonlite.pb.h +150 -0
  92. data/ext/protobuf-2.4.1/src/google/protobuf/unittest_mset.pb.h +816 -0
  93. data/ext/protobuf-2.4.1/src/google/protobuf/unittest_no_generic_services.pb.h +197 -0
  94. data/ext/protobuf-2.4.1/src/google/protobuf/unittest_optimize_for.pb.h +403 -0
  95. data/ext/protobuf-2.4.1/src/google/protobuf/unknown_field_set.h +268 -0
  96. data/ext/protobuf-2.4.1/src/google/protobuf/wire_format.h +304 -0
  97. data/ext/protobuf-2.4.1/src/google/protobuf/wire_format_lite.h +620 -0
  98. data/ext/protobuf-2.4.1/src/google/protobuf/wire_format_lite_inl.h +774 -0
  99. data/ext/ruby_generator/Makefile +10 -0
  100. data/ext/ruby_generator/RubyGenerator.cpp +450 -0
  101. data/ext/ruby_generator/RubyGenerator.h +199 -0
  102. data/ext/ruby_generator/extconf.rb +36 -0
  103. data/ext/ruby_generator/protoc-ruby +0 -0
  104. data/lib/protobuf/cli.rb +188 -0
  105. data/lib/protobuf/enum.rb +58 -0
  106. data/lib/protobuf/enum_value.rb +59 -0
  107. data/lib/protobuf/evented.rb +22 -0
  108. data/lib/protobuf/exceptions.rb +11 -0
  109. data/lib/protobuf/ext/eventmachine.rb +14 -0
  110. data/lib/protobuf/field/base_field.rb +240 -0
  111. data/lib/protobuf/field/bool_field.rb +36 -0
  112. data/lib/protobuf/field/bytes_field.rb +38 -0
  113. data/lib/protobuf/field/double_field.rb +19 -0
  114. data/lib/protobuf/field/enum_field.rb +50 -0
  115. data/lib/protobuf/field/extension_fields.rb +32 -0
  116. data/lib/protobuf/field/field_array.rb +65 -0
  117. data/lib/protobuf/field/fixed32_field.rb +19 -0
  118. data/lib/protobuf/field/fixed64_field.rb +22 -0
  119. data/lib/protobuf/field/float_field.rb +31 -0
  120. data/lib/protobuf/field/int32_field.rb +12 -0
  121. data/lib/protobuf/field/int64_field.rb +12 -0
  122. data/lib/protobuf/field/integer_field.rb +19 -0
  123. data/lib/protobuf/field/message_field.rb +53 -0
  124. data/lib/protobuf/field/sfixed32_field.rb +21 -0
  125. data/lib/protobuf/field/sfixed64_field.rb +24 -0
  126. data/lib/protobuf/field/signed_integer_field.rb +23 -0
  127. data/lib/protobuf/field/sint32_field.rb +12 -0
  128. data/lib/protobuf/field/sint64_field.rb +12 -0
  129. data/lib/protobuf/field/string_field.rb +14 -0
  130. data/lib/protobuf/field/uint32_field.rb +12 -0
  131. data/lib/protobuf/field/uint64_field.rb +12 -0
  132. data/lib/protobuf/field/varint_field.rb +61 -0
  133. data/lib/protobuf/field.rb +57 -0
  134. data/lib/protobuf/logger.rb +86 -0
  135. data/lib/protobuf/message/decoder.rb +83 -0
  136. data/lib/protobuf/message/encoder.rb +48 -0
  137. data/lib/protobuf/message/extend.rb +8 -0
  138. data/lib/protobuf/message/message.rb +1 -0
  139. data/lib/protobuf/message.rb +320 -0
  140. data/lib/protobuf/rpc/buffer.rb +79 -0
  141. data/lib/protobuf/rpc/client.rb +166 -0
  142. data/lib/protobuf/rpc/connector.rb +19 -0
  143. data/lib/protobuf/rpc/connectors/base.rb +38 -0
  144. data/lib/protobuf/rpc/connectors/common.rb +156 -0
  145. data/lib/protobuf/rpc/connectors/em_client.rb +84 -0
  146. data/lib/protobuf/rpc/connectors/eventmachine.rb +87 -0
  147. data/lib/protobuf/rpc/connectors/socket.rb +73 -0
  148. data/lib/protobuf/rpc/connectors/zmq.rb +69 -0
  149. data/lib/protobuf/rpc/error/client_error.rb +31 -0
  150. data/lib/protobuf/rpc/error/server_error.rb +43 -0
  151. data/lib/protobuf/rpc/error.rb +25 -0
  152. data/lib/protobuf/rpc/rpc.pb.rb +118 -0
  153. data/lib/protobuf/rpc/server.rb +89 -0
  154. data/lib/protobuf/rpc/servers/evented/server.rb +41 -0
  155. data/lib/protobuf/rpc/servers/evented_runner.rb +21 -0
  156. data/lib/protobuf/rpc/servers/socket/server.rb +111 -0
  157. data/lib/protobuf/rpc/servers/socket/worker.rb +66 -0
  158. data/lib/protobuf/rpc/servers/socket_runner.rb +27 -0
  159. data/lib/protobuf/rpc/servers/zmq/broker.rb +87 -0
  160. data/lib/protobuf/rpc/servers/zmq/server.rb +50 -0
  161. data/lib/protobuf/rpc/servers/zmq/util.rb +27 -0
  162. data/lib/protobuf/rpc/servers/zmq/worker.rb +60 -0
  163. data/lib/protobuf/rpc/servers/zmq_runner.rb +25 -0
  164. data/lib/protobuf/rpc/service.rb +173 -0
  165. data/lib/protobuf/rpc/service_dispatcher.rb +130 -0
  166. data/lib/protobuf/rpc/service_filters.rb +267 -0
  167. data/lib/protobuf/rpc/stat.rb +83 -0
  168. data/lib/protobuf/socket.rb +22 -0
  169. data/lib/protobuf/version.rb +4 -0
  170. data/lib/protobuf/wire_type.rb +10 -0
  171. data/lib/protobuf/zmq.rb +21 -0
  172. data/lib/protobuf.rb +86 -0
  173. data/proto/rpc.pb.rb +48 -0
  174. data/proto/rpc.proto +73 -0
  175. data/protobuf.gemspec +44 -0
  176. data/spec/benchmark/tasks.rb +179 -0
  177. data/spec/functional/embedded_service_spec.rb +7 -0
  178. data/spec/functional/evented_server_spec.rb +64 -0
  179. data/spec/functional/socket_server_spec.rb +58 -0
  180. data/spec/functional/zmq_server_spec.rb +58 -0
  181. data/spec/lib/protobuf/cli_spec.rb +212 -0
  182. data/spec/lib/protobuf/enum_spec.rb +98 -0
  183. data/spec/lib/protobuf/enum_value_spec.rb +15 -0
  184. data/spec/lib/protobuf/logger_spec.rb +131 -0
  185. data/spec/lib/protobuf/message/encoder_spec.rb +19 -0
  186. data/spec/lib/protobuf/message_spec.rb +209 -0
  187. data/spec/lib/protobuf/rpc/client_spec.rb +158 -0
  188. data/spec/lib/protobuf/rpc/connector_spec.rb +32 -0
  189. data/spec/lib/protobuf/rpc/connectors/base_spec.rb +50 -0
  190. data/spec/lib/protobuf/rpc/connectors/common_spec.rb +128 -0
  191. data/spec/lib/protobuf/rpc/connectors/socket_spec.rb +36 -0
  192. data/spec/lib/protobuf/rpc/connectors/zmq_spec.rb +22 -0
  193. data/spec/lib/protobuf/rpc/servers/evented_server_spec.rb +18 -0
  194. data/spec/lib/protobuf/rpc/servers/socket_server_spec.rb +43 -0
  195. data/spec/lib/protobuf/rpc/servers/zmq/broker_spec.rb +35 -0
  196. data/spec/lib/protobuf/rpc/servers/zmq/server_spec.rb +41 -0
  197. data/spec/lib/protobuf/rpc/servers/zmq/util_spec.rb +45 -0
  198. data/spec/lib/protobuf/rpc/servers/zmq/worker_spec.rb +44 -0
  199. data/spec/lib/protobuf/rpc/service_dispatcher_spec.rb +116 -0
  200. data/spec/lib/protobuf/rpc/service_filters_spec.rb +451 -0
  201. data/spec/lib/protobuf/rpc/service_spec.rb +165 -0
  202. data/spec/lib/protobuf_spec.rb +62 -0
  203. data/spec/spec_helper.rb +51 -0
  204. data/spec/support/all.rb +6 -0
  205. data/spec/support/server.rb +101 -0
  206. data/spec/support/test/enum.pb.rb +34 -0
  207. data/spec/support/test/enum.proto +12 -0
  208. data/spec/support/test/resource.pb.rb +58 -0
  209. data/spec/support/test/resource.proto +31 -0
  210. data/spec/support/test/resource_service.rb +14 -0
  211. data/spec/support/test_app_file.rb +2 -0
  212. data/spec/support/tolerance_matcher.rb +40 -0
  213. data/test/data/data.bin +3 -0
  214. data/test/data/data_source.py +14 -0
  215. data/test/data/types.bin +0 -0
  216. data/test/data/types_source.py +22 -0
  217. data/test/data/unk.png +0 -0
  218. data/test/proto/addressbook.pb.rb +66 -0
  219. data/test/proto/addressbook.proto +33 -0
  220. data/test/proto/addressbook_base.pb.rb +58 -0
  221. data/test/proto/addressbook_base.proto +26 -0
  222. data/test/proto/addressbook_ext.pb.rb +20 -0
  223. data/test/proto/addressbook_ext.proto +6 -0
  224. data/test/proto/collision.pb.rb +17 -0
  225. data/test/proto/collision.proto +5 -0
  226. data/test/proto/ext_collision.pb.rb +24 -0
  227. data/test/proto/ext_collision.proto +8 -0
  228. data/test/proto/ext_range.pb.rb +22 -0
  229. data/test/proto/ext_range.proto +7 -0
  230. data/test/proto/float_default.proto +10 -0
  231. data/test/proto/lowercase.pb.rb +30 -0
  232. data/test/proto/lowercase.proto +9 -0
  233. data/test/proto/merge.pb.rb +39 -0
  234. data/test/proto/merge.proto +15 -0
  235. data/test/proto/nested.pb.rb +30 -0
  236. data/test/proto/nested.proto +9 -0
  237. data/test/proto/optional_field.pb.rb +35 -0
  238. data/test/proto/optional_field.proto +12 -0
  239. data/test/proto/packed.pb.rb +22 -0
  240. data/test/proto/packed.proto +6 -0
  241. data/test/proto/rpc.proto +6 -0
  242. data/test/proto/types.pb.rb +84 -0
  243. data/test/proto/types.proto +37 -0
  244. data/test/test_addressbook.rb +56 -0
  245. data/test/test_enum_value.rb +41 -0
  246. data/test/test_extension.rb +36 -0
  247. data/test/test_lowercase.rb +11 -0
  248. data/test/test_message.rb +128 -0
  249. data/test/test_optional_field.rb +103 -0
  250. data/test/test_packed_field.rb +40 -0
  251. data/test/test_parse.rb +15 -0
  252. data/test/test_repeated_types.rb +132 -0
  253. data/test/test_serialize.rb +61 -0
  254. data/test/test_standard_message.rb +96 -0
  255. data/test/test_types.rb +226 -0
  256. metadata +461 -0
@@ -0,0 +1,60 @@
1
+ require 'protobuf/rpc/server'
2
+ require 'protobuf/rpc/servers/zmq/util'
3
+ module Protobuf
4
+ module Rpc
5
+ module Zmq
6
+
7
+ class Worker
8
+ include ::Protobuf::Rpc::Server
9
+ include ::Protobuf::Rpc::Zmq::Util
10
+
11
+ ##
12
+ # Constructor
13
+ #
14
+ def initialize(options = {})
15
+ host = options[:host]
16
+ port = options[:port]
17
+
18
+ @zmq_context = ::ZMQ::Context.new
19
+ @socket = @zmq_context.socket(::ZMQ::REP)
20
+ zmq_error_check(@socket.connect("tcp://#{resolve_ip(host)}:#{port}"))
21
+
22
+ @poller = ::ZMQ::Poller.new
23
+ @poller.register(@socket, ::ZMQ::POLLIN)
24
+ end
25
+
26
+ ##
27
+ # Instance Methods
28
+ #
29
+ def handle_request(socket)
30
+ @request_data = ''
31
+ zmq_error_check(socket.recv_string(@request_data))
32
+ log_debug { sign_message("handling request") } if !@request_data.nil?
33
+ end
34
+
35
+ def run
36
+ while ::Protobuf::Rpc::Zmq::Server.running? do
37
+ # poll for 1_000 milliseconds then continue looping
38
+ # This lets us see whether we need to die
39
+ @poller.poll(1_000)
40
+ @poller.readables.each do |socket|
41
+ initialize_request!
42
+ handle_request(socket)
43
+ handle_client unless @request_data.nil?
44
+ end
45
+ end
46
+ ensure
47
+ @socket.close
48
+ @zmq_context.terminate
49
+ end
50
+
51
+ def send_data
52
+ response_data = @response.is_a?(::Protobuf::Message) ? @response.serialize_to_string : @response.to_s
53
+ @stats.response_size = response_data.size
54
+ zmq_error_check(@socket.send_string(response_data))
55
+ end
56
+ end
57
+
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,25 @@
1
+ module Protobuf
2
+ module Rpc
3
+ class ZmqRunner
4
+
5
+ def self.stop
6
+ Protobuf::Rpc::Zmq::Server.stop
7
+ end
8
+
9
+ def self.run(server)
10
+ server_config = case
11
+ when server.is_a?(OpenStruct) then
12
+ server.marshal_dump
13
+ when server.respond_to?(:to_hash) then
14
+ server.to_hash
15
+ else
16
+ raise "Cannot parser Zmq Server - server options"
17
+ end
18
+
19
+ yield if block_given?
20
+ Protobuf::Rpc::Zmq::Server.run(server_config)
21
+ end
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,173 @@
1
+ require 'protobuf/logger'
2
+ require 'protobuf/rpc/client'
3
+ require 'protobuf/rpc/error'
4
+ require 'protobuf/rpc/service_filters'
5
+
6
+ module Protobuf
7
+ module Rpc
8
+
9
+ # Object to encapsulate the request/response types for a given service method
10
+ #
11
+ RpcMethod = Struct.new("RpcMethod", :method, :request_type, :response_type)
12
+
13
+ class Service
14
+ include Protobuf::Rpc::ServiceFilters
15
+ include Protobuf::Logger::LogMethods
16
+
17
+
18
+ attr_reader :response, :rpc
19
+
20
+ DEFAULT_HOST = '127.0.0.1'.freeze
21
+ DEFAULT_PORT = 9399
22
+
23
+ ##
24
+ # Class Methods
25
+ #
26
+
27
+ # Create a new client for the given service.
28
+ # See Client#initialize and ClientConnection::DEFAULT_OPTIONS
29
+ # for all available options.
30
+ #
31
+ def self.client(options = {})
32
+ ::Protobuf::Rpc::Client.new({ :service => self,
33
+ :host => host,
34
+ :port => port }.merge(options))
35
+ end
36
+
37
+ # Allows service-level configuration of location.
38
+ # Useful for system-startup configuration of a service
39
+ # so that any Clients using the Service.client sugar
40
+ # will not have to configure the location each time.
41
+ #
42
+ def self.configure(config = {})
43
+ self.host = config[:host] if config.key?(:host)
44
+ self.port = config[:port] if config.key?(:port)
45
+ end
46
+
47
+ # The host location of the service.
48
+ #
49
+ def self.host
50
+ @_host ||= DEFAULT_HOST
51
+ end
52
+
53
+ # The host location setter.
54
+ #
55
+ def self.host=(new_host)
56
+ @_host = new_host
57
+ end
58
+
59
+ # Shorthand call to configure, passing a string formatted as hostname:port
60
+ # e.g. 127.0.0.1:9933
61
+ # e.g. localhost:0
62
+ #
63
+ def self.located_at(location)
64
+ return if location.nil? || location.downcase.strip !~ /.+:\d+/
65
+ host, port = location.downcase.strip.split ':'
66
+ configure(:host => host, :port => port.to_i)
67
+ end
68
+
69
+ # The port of the service on the destination server.
70
+ #
71
+ def self.port
72
+ @_port ||= DEFAULT_PORT
73
+ end
74
+
75
+ # The port location setter.
76
+ #
77
+ def self.port=(new_port)
78
+ @_port = new_port
79
+ end
80
+
81
+ # Define an rpc method with the given request and response types.
82
+ # This methods is only used by the generated service definitions
83
+ # and not useful for user code.
84
+ #
85
+ def self.rpc(method, request_type, response_type)
86
+ rpcs[method] = RpcMethod.new(method, request_type, response_type)
87
+ end
88
+
89
+ # Hash containing the set of methods defined via `rpc`.
90
+ #
91
+ def self.rpcs
92
+ @_rpcs ||= {}
93
+ end
94
+
95
+ # Check if the given method name is a known rpc endpoint.
96
+ #
97
+ def self.rpc_method?(name)
98
+ rpcs.key?(name)
99
+ end
100
+
101
+
102
+ ##
103
+ # Instance Methods
104
+ #
105
+
106
+ # Initialize a service with the rpc endpoint name and the bytes
107
+ # for the request.
108
+ def initialize(rpc, request_bytes)
109
+ @rpc = rpc
110
+ @request_bytes = request_bytes
111
+ end
112
+
113
+ # Register a failure callback for use when rpc_failed is invoked.
114
+ #
115
+ def on_rpc_failed(callable)
116
+ @rpc_failed_callback ||= callable
117
+ end
118
+
119
+ # Response object for this rpc cycle. Not assignable.
120
+ #
121
+ def response
122
+ @_response ||= rpcs[@rpc].response_type.new
123
+ end
124
+
125
+ # Convenience method to get back to class method.
126
+ #
127
+ def rpc_method?(name)
128
+ self.class.rpc_method?(name)
129
+ end
130
+
131
+ # Convenience method to get back to class rpcs hash.
132
+ #
133
+ def rpcs
134
+ self.class.rpcs
135
+ end
136
+
137
+ # Get a callable object that will be used by the dispatcher
138
+ # to invoke the specified rpc method. Facilitates callback dispatch.
139
+ # The returned lambda is expected to be called at a later time (which
140
+ # is why we wrap the method call).
141
+ #
142
+ def callable_rpc_method(method_name)
143
+ lambda { run_filters(method_name) }
144
+ end
145
+
146
+ private
147
+
148
+ # Request object for this rpc cycle. Not assignable.
149
+ #
150
+ def request
151
+ @_request ||= rpcs[@rpc].request_type.new.parse_from_string(@request_bytes)
152
+ rescue => e
153
+ raise BadRequestProto, "Unable to parse request: #{e.message}"
154
+ end
155
+
156
+ # Sugar to make an rpc method feel like a controller method.
157
+ # If this method is not called, the response will be the memoized
158
+ # object returned by the response reader.
159
+ #
160
+ def respond_with(candidate)
161
+ @_response = candidate
162
+ end
163
+ alias_method :return_from_whence_you_came, :respond_with
164
+
165
+ # Automatically fail a service method.
166
+ #
167
+ def rpc_failed(message)
168
+ @rpc_failed_callback.call(message)
169
+ end
170
+
171
+ end
172
+ end
173
+ end
@@ -0,0 +1,130 @@
1
+ require 'protobuf/logger'
2
+
3
+ module Protobuf
4
+ module Rpc
5
+ class ServiceDispatcher
6
+
7
+ include ::Protobuf::Logger::LogMethods
8
+
9
+ attr_accessor :service, :service_klass, :callable_method, :outer_request
10
+ attr_accessor :definition, :response, :error
11
+
12
+ def initialize(wrapper_request)
13
+ self.error = nil
14
+ self.outer_request = wrapper_request
15
+
16
+ init_service
17
+ init_method if service_klass.present?
18
+ register_rpc_failed if service.present?
19
+ end
20
+
21
+ # Call the given service method. If we get to this point and an error
22
+ # has already occurred, do not invoke the method and simply respond.
23
+ #
24
+ def invoke!
25
+ unless error?
26
+ callable_method.call
27
+ validate_response
28
+ end
29
+
30
+ return error || response
31
+ end
32
+
33
+ # We're successful if the error is not populated.
34
+ #
35
+ def success?
36
+ error.nil?
37
+ end
38
+
39
+ # We're in error if the error is populated.
40
+ #
41
+ def error?
42
+ ! success?
43
+ end
44
+
45
+ private
46
+
47
+ def assign_error(error_klass, message)
48
+ self.error = error_klass.new(message)
49
+ end
50
+
51
+ # Prod the object to see if we can produce a proto object as a response
52
+ # candidate. Either way, return the candidate for validation.
53
+ def coerced_response
54
+ candidate = service.response
55
+
56
+ case
57
+ when candidate.is_a?(::Protobuf::Message) then
58
+ # no-op
59
+ when candidate.respond_to?(:to_proto) then
60
+ candidate = candidate.to_proto
61
+ when candidate.respond_to?(:to_proto_hash) then
62
+ candidate = definition.response_type.new(candidate.to_proto_hash)
63
+ when candidate.respond_to?(:to_hash) then
64
+ candidate = definition.response_type.new(candidate.to_hash)
65
+ end
66
+
67
+ candidate
68
+ end
69
+
70
+ # Get the method for the current request.
71
+ #
72
+ def init_method
73
+ method_name = outer_request.method_name.underscore.to_sym
74
+ if service_klass.rpc_method?(method_name)
75
+ self.service = service_klass.new(method_name, outer_request.request_proto)
76
+ self.callable_method = service.callable_rpc_method(method_name)
77
+ self.definition = service.rpcs[method_name]
78
+ else
79
+ assign_error(MethodNotFound, "#{service.class.name}##{method_name} is not a defined rpc method.")
80
+ end
81
+ rescue NameError => e
82
+ # FIXME I think this is no longer applicable since the method extract
83
+ # is now wrapped in a lambda (@see Service#callable_rpc_method).
84
+ log_exception(e)
85
+ assign_error(MethodNotFound, "#{service.class.name}##{method_name} is not implemented.")
86
+ end
87
+
88
+ # Constantize the service for this request. Initialization of the service
89
+ # happens when we verify that the method is callable for this service.
90
+ #
91
+ def init_service
92
+ self.service_klass = outer_request.service_name.constantize
93
+ rescue NameError => e
94
+ log_exception(e)
95
+ assign_error(ServiceNotFound, "Service class #{outer_request.service_name} is not defined.")
96
+ end
97
+
98
+ # Make sure we get rpc errors back.
99
+ #
100
+ def register_rpc_failed
101
+ service.on_rpc_failed(method(:rpc_failed_callback))
102
+ end
103
+
104
+ # Receive the failure message from the service. This method is registered
105
+ # as the callable to the service when an `rpc_failed` call is invoked.
106
+ #
107
+ def rpc_failed_callback(message)
108
+ assign_error(RpcFailed, (message.respond_to?(:message) ? message.message : message))
109
+ log_error { sign_message("RPC Failed: #{error.message}") }
110
+ end
111
+
112
+ # Ensure that the response candidate we've been given is of the type
113
+ # we expect so that deserialization on the client side works.
114
+ #
115
+ def validate_response
116
+ candidate = coerced_response
117
+ expected = definition.response_type
118
+ actual = candidate.class
119
+
120
+ if expected == actual
121
+ self.response = candidate
122
+ else
123
+ assign_error(BadResponseProto, "Response proto changed from #{expected.name} to #{actual.name}")
124
+ end
125
+ end
126
+
127
+ end
128
+ end
129
+ end
130
+
@@ -0,0 +1,267 @@
1
+ module Protobuf
2
+ module Rpc
3
+ module ServiceFilters
4
+
5
+ def self.included(other)
6
+ other.class_eval do
7
+ extend Protobuf::Rpc::ServiceFilters::ClassMethods
8
+ include Protobuf::Rpc::ServiceFilters::InstanceMethods
9
+ end
10
+ end
11
+
12
+ module ClassMethods
13
+
14
+ [:after, :around, :before].each do |type|
15
+ # Setter DSL method for given filter types.
16
+ #
17
+ define_method "#{type}_filter" do |*args|
18
+ set_filters(type, *args)
19
+ end
20
+ end
21
+
22
+ # Filters hash keyed based on filter type (e.g. :before, :after, :around),
23
+ # whose values are Sets.
24
+ #
25
+ def filters
26
+ @filters ||= Hash.new { |h,k| h[k] = [] }
27
+ end
28
+
29
+ # Filters hash keyed based on filter type (e.g. :before, :after, :around),
30
+ # whose values are Sets.
31
+ #
32
+ def rescue_filters
33
+ @rescue_filters ||= {}
34
+ end
35
+
36
+ def rescue_from(*ex_klasses, &block)
37
+ options = ex_klasses.last.is_a?(Hash) ? ex_klasses.pop : {}
38
+ callable = options.delete(:with) { block }
39
+ raise ArgumentError, 'Option :with missing from rescue_from options' if callable.nil?
40
+ ex_klasses.each { |ex_klass| rescue_filters[ex_klass] = callable }
41
+ end
42
+
43
+ private
44
+
45
+ def define_filter(type, filter, options = {})
46
+ return if filter_defined?(type, filter)
47
+ filters[type] << options.merge({ :callable => filter })
48
+ remember_filter(type, filter)
49
+ end
50
+
51
+ def defined_filters
52
+ @defined_filters ||= Hash.new { |h,k| h[k] = Set.new }
53
+ end
54
+
55
+ # Check to see if the filter has been defined.
56
+ #
57
+ def filter_defined?(type, filter)
58
+ defined_filters[type].include?(filter)
59
+ end
60
+
61
+ # Remember that we stored the filter.
62
+ #
63
+ def remember_filter(type, filter)
64
+ defined_filters[type] << filter
65
+ end
66
+
67
+ # Takes a list of actually (or potentially) callable objects.
68
+ # TODO add support for if/unless
69
+ # TODO add support for only/except sub-filters
70
+ #
71
+ def set_filters(type, *args)
72
+ options = args.last.is_a?(Hash) ? args.pop : {}
73
+ args.each do |filter|
74
+ define_filter(type, filter, options)
75
+ end
76
+ end
77
+
78
+ end
79
+
80
+ module InstanceMethods
81
+
82
+ private
83
+
84
+ # Get back to class filters.
85
+ #
86
+ def filters
87
+ self.class.filters
88
+ end
89
+
90
+ # Predicate which uses the filter options to determine if the filter
91
+ # should be called. Specifically checks the :if, :unless, :only, and :except
92
+ # options for every filter. Each option check is expected to return false
93
+ # if the filter should not be invoked, true if invocation should occur.
94
+ #
95
+ def invoke_filter?(rpc_method, filter)
96
+ return invoke_via_only?(rpc_method, filter) \
97
+ && invoke_via_except?(rpc_method, filter) \
98
+ && invoke_via_if?(rpc_method, filter) \
99
+ && invoke_via_unless?(rpc_method, filter)
100
+ end
101
+
102
+ # If the target rpc endpoint method is listed under an :except option,
103
+ # return false to indicate that the filter should not be invoked. Any
104
+ # other target rpc endpoint methods not listed should be invoked.
105
+ # This option is the opposite of :only.
106
+ #
107
+ # Value should be a symbol/string or an array of symbols/strings.
108
+ #
109
+ def invoke_via_except?(rpc_method, filter)
110
+ except = [ filter.fetch(:except) { [] } ].flatten
111
+ return except.empty? || ! except.include?(rpc_method)
112
+ end
113
+
114
+ # Invoke the given :if callable (if any) and return its return value.
115
+ # Used by `invoke_filter?` which expects a true/false
116
+ # return value to determine if we should invoke the target filter.
117
+ #
118
+ # Value can either be a symbol/string indicating an instance method to call
119
+ # or an object that responds to `call`.
120
+ #
121
+ def invoke_via_if?(rpc_method, filter)
122
+ if_check = filter.fetch(:if) { lambda { |service| return true } }
123
+ do_invoke = case
124
+ when if_check.nil? then
125
+ true
126
+ else
127
+ call_or_send(if_check)
128
+ end
129
+
130
+ return do_invoke
131
+ end
132
+
133
+ # If the target rpc endpoint method is listed in the :only option,
134
+ # it should be invoked. Any target rpc endpoint methods not listed in this
135
+ # option should not be invoked. This option is the opposite of :except.
136
+ #
137
+ # Value should be a symbol/string or an array of symbols/strings.
138
+ #
139
+ def invoke_via_only?(rpc_method, filter)
140
+ only = [ filter.fetch(:only) { [] } ].flatten
141
+ return only.empty? || only.include?(rpc_method)
142
+ end
143
+
144
+ # Invoke the given :unless callable (if any) and return the opposite
145
+ # of it's return value. Used by `invoke_filter?` which expects a true/false
146
+ # return value to determine if we should invoke the target filter.
147
+ #
148
+ # Value can either be a symbol/string indicating an instance method to call
149
+ # or an object that responds to `call`.
150
+ #
151
+ def invoke_via_unless?(rpc_method, filter)
152
+ unless_check = filter.fetch(:unless) { lambda { |service| return false } }
153
+ skip_invoke = case
154
+ when unless_check.nil? then
155
+ false
156
+ else
157
+ call_or_send(unless_check)
158
+ end
159
+
160
+ return ! skip_invoke
161
+ end
162
+
163
+ def rescue_filters
164
+ self.class.rescue_filters
165
+ end
166
+
167
+ # Loop over the unwrapped filters and invoke them. An unwrapped filter
168
+ # is either a before or after filter, not an around filter.
169
+ #
170
+ def run_unwrapped_filters(unwrapped_filters, rpc_method, stop_on_false_return = false)
171
+ unwrapped_filters.each do |filter|
172
+ if invoke_filter?(rpc_method, filter)
173
+ return_value = call_or_send(filter[:callable])
174
+ return false if stop_on_false_return && return_value == false
175
+ end
176
+ end
177
+
178
+ return true
179
+ end
180
+
181
+ # Reverse build a chain of around filters. To implement an around chain,
182
+ # simply build a method that yields control when it expects the underlying
183
+ # method to be invoked. If the endpoint should not be run (due to some
184
+ # condition), simply do not yield.
185
+ #
186
+ # Around filters are invoked in the order they are defined, outer to inner,
187
+ # with the inner-most method called being the actual rpc endpoint.
188
+ #
189
+ # Let's say you have a class defined with the following filters:
190
+ #
191
+ # class MyService
192
+ # around_filter :filter1, :filter2, :filter3
193
+ #
194
+ # def my_endpoint
195
+ # # do stuff
196
+ # end
197
+ # end
198
+ #
199
+ # When the my_endpoint method is invoked using Service#callable_rpc_method,
200
+ # It is similar to this call chain:
201
+ #
202
+ # filter1 do
203
+ # filter2 do
204
+ # filter3 do
205
+ # my_endpoint
206
+ # end
207
+ # end
208
+ # end
209
+ #
210
+ def run_around_filters(rpc_method)
211
+ final = lambda { __send__(rpc_method) }
212
+ filters[:around].reverse.inject(final) { |previous, filter|
213
+ if invoke_filter?(rpc_method, filter)
214
+ lambda { call_or_send(filter[:callable], &previous) }
215
+ else
216
+ previous
217
+ end
218
+ }.call
219
+ end
220
+
221
+
222
+ # Entry method to call each filter type in the appropriate order. This should
223
+ # be used instead of the other run methods directly.
224
+ #
225
+ def run_filters(rpc_method)
226
+ run_rescue_filters do
227
+ continue = run_unwrapped_filters(filters[:before], rpc_method, true)
228
+ if continue
229
+ run_around_filters(rpc_method)
230
+ run_unwrapped_filters(filters[:after], rpc_method)
231
+ end
232
+ end
233
+ end
234
+
235
+ def run_rescue_filters
236
+ if rescue_filters.keys.empty?
237
+ yield
238
+ else
239
+ begin
240
+ yield
241
+ rescue *rescue_filters.keys => ex
242
+ call_or_send(rescue_filters[ex.class], ex)
243
+ end
244
+ end
245
+ end
246
+
247
+ # Call the object if it is callable, otherwise invoke the method using
248
+ # __send__ assuming that we respond_to it. Return the call's return value.
249
+ #
250
+ def call_or_send(callable, *args, &block)
251
+ return_value = case
252
+ when callable.respond_to?(:call) then
253
+ callable.call(self, *args, &block)
254
+ when respond_to?(callable, true) then
255
+ __send__(callable, *args, &block)
256
+ else
257
+ raise "Object #{callable} is not callable"
258
+ end
259
+
260
+ return return_value
261
+ end
262
+
263
+ end
264
+
265
+ end
266
+ end
267
+ end