aggro 0.0.1 → 0.0.2

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 (141) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +8 -0
  3. data/.travis.yml +15 -0
  4. data/Gemfile +9 -0
  5. data/README.md +5 -1
  6. data/Rakefile +10 -0
  7. data/aggro.gemspec +8 -1
  8. data/lib/aggro.rb +191 -7
  9. data/lib/aggro/abstract_store.rb +12 -0
  10. data/lib/aggro/aggregate.rb +98 -0
  11. data/lib/aggro/aggregate_ref.rb +68 -6
  12. data/lib/aggro/attribute_dsl.rb +96 -0
  13. data/lib/aggro/binding_dsl.rb +45 -0
  14. data/lib/aggro/block_helper.rb +14 -0
  15. data/lib/aggro/channel.rb +37 -0
  16. data/lib/aggro/client.rb +12 -0
  17. data/lib/aggro/cluster_config.rb +57 -0
  18. data/lib/aggro/command.rb +16 -0
  19. data/lib/aggro/concurrent_actor.rb +26 -0
  20. data/lib/aggro/event_bus.rb +94 -0
  21. data/lib/aggro/event_dsl.rb +53 -0
  22. data/lib/aggro/event_proxy.rb +23 -0
  23. data/lib/aggro/event_serializer.rb +14 -0
  24. data/lib/aggro/file_store.rb +97 -0
  25. data/lib/aggro/file_store/reader.rb +21 -0
  26. data/lib/aggro/file_store/writer.rb +27 -0
  27. data/lib/aggro/handler/command.rb +60 -0
  28. data/lib/aggro/handler/create_aggregate.rb +42 -0
  29. data/lib/aggro/handler/get_events.rb +30 -0
  30. data/lib/aggro/handler/query.rb +60 -0
  31. data/lib/aggro/handler/start_saga.rb +56 -0
  32. data/lib/aggro/local_node.rb +28 -0
  33. data/lib/aggro/locator.rb +32 -0
  34. data/lib/aggro/message/ask.rb +16 -0
  35. data/lib/aggro/message/command.rb +36 -0
  36. data/lib/aggro/message/create_aggregate.rb +16 -0
  37. data/lib/aggro/message/endpoint.rb +16 -0
  38. data/lib/aggro/message/events.rb +24 -0
  39. data/lib/aggro/message/get_events.rb +16 -0
  40. data/lib/aggro/message/heartbeat.rb +16 -0
  41. data/lib/aggro/message/invalid_target.rb +20 -0
  42. data/lib/aggro/message/ok.rb +20 -0
  43. data/lib/aggro/message/publisher_endpoint_inquiry.rb +16 -0
  44. data/lib/aggro/message/query.rb +36 -0
  45. data/lib/aggro/message/result.rb +16 -0
  46. data/lib/aggro/message/start_saga.rb +28 -0
  47. data/lib/aggro/message/unhandled_operation.rb +20 -0
  48. data/lib/aggro/message/unknown_operation.rb +20 -0
  49. data/lib/aggro/message_parser.rb +10 -0
  50. data/lib/aggro/message_router.rb +26 -0
  51. data/lib/aggro/nanomsg_transport.rb +31 -0
  52. data/lib/aggro/nanomsg_transport/client.rb +35 -0
  53. data/lib/aggro/nanomsg_transport/connection.rb +98 -0
  54. data/lib/aggro/nanomsg_transport/publish.rb +17 -0
  55. data/lib/aggro/nanomsg_transport/publisher.rb +37 -0
  56. data/lib/aggro/nanomsg_transport/raw_reply.rb +18 -0
  57. data/lib/aggro/nanomsg_transport/raw_request.rb +18 -0
  58. data/lib/aggro/nanomsg_transport/reply.rb +17 -0
  59. data/lib/aggro/nanomsg_transport/request.rb +17 -0
  60. data/lib/aggro/nanomsg_transport/server.rb +84 -0
  61. data/lib/aggro/nanomsg_transport/socket_error.rb +20 -0
  62. data/lib/aggro/nanomsg_transport/subscribe.rb +27 -0
  63. data/lib/aggro/nanomsg_transport/subscriber.rb +82 -0
  64. data/lib/aggro/node.rb +29 -0
  65. data/lib/aggro/node_list.rb +39 -0
  66. data/lib/aggro/projection.rb +13 -0
  67. data/lib/aggro/query.rb +11 -0
  68. data/lib/aggro/saga.rb +94 -0
  69. data/lib/aggro/saga_runner.rb +87 -0
  70. data/lib/aggro/saga_runner/start_saga.rb +12 -0
  71. data/lib/aggro/saga_status.rb +29 -0
  72. data/lib/aggro/server.rb +88 -0
  73. data/lib/aggro/subscriber.rb +48 -0
  74. data/lib/aggro/subscription.rb +41 -0
  75. data/lib/aggro/transform/boolean.rb +16 -0
  76. data/lib/aggro/transform/email.rb +26 -0
  77. data/lib/aggro/transform/id.rb +34 -0
  78. data/lib/aggro/transform/integer.rb +22 -0
  79. data/lib/aggro/transform/money.rb +22 -0
  80. data/lib/aggro/transform/noop.rb +16 -0
  81. data/lib/aggro/transform/string.rb +16 -0
  82. data/lib/aggro/transform/time_interval.rb +24 -0
  83. data/lib/aggro/version.rb +1 -1
  84. data/spec/lib/aggro/abstract_store_spec.rb +15 -0
  85. data/spec/lib/aggro/aggregate_ref_spec.rb +63 -12
  86. data/spec/lib/aggro/aggregate_spec.rb +207 -0
  87. data/spec/lib/aggro/channel_spec.rb +87 -0
  88. data/spec/lib/aggro/client_spec.rb +26 -0
  89. data/spec/lib/aggro/cluster_config_spec.rb +33 -0
  90. data/spec/lib/aggro/command_spec.rb +52 -0
  91. data/spec/lib/aggro/concurrent_actor_spec.rb +44 -0
  92. data/spec/lib/aggro/event_bus_spec.rb +20 -0
  93. data/spec/lib/aggro/event_serializer_spec.rb +28 -0
  94. data/spec/lib/aggro/file_store/reader_spec.rb +32 -0
  95. data/spec/lib/aggro/file_store/writer_spec.rb +67 -0
  96. data/spec/lib/aggro/file_store_spec.rb +51 -0
  97. data/spec/lib/aggro/handler/command_spec.rb +78 -0
  98. data/spec/lib/aggro/handler/create_aggregate_spec.rb +64 -0
  99. data/spec/lib/aggro/handler/get_events_handler_spec.rb +45 -0
  100. data/spec/lib/aggro/handler/query_spec.rb +78 -0
  101. data/spec/lib/aggro/handler/start_saga_spec.rb +64 -0
  102. data/spec/lib/aggro/local_node_spec.rb +52 -0
  103. data/spec/lib/aggro/locator_spec.rb +61 -0
  104. data/spec/lib/aggro/message/ask_spec.rb +23 -0
  105. data/spec/lib/aggro/message/command_spec.rb +50 -0
  106. data/spec/lib/aggro/message/create_aggregate_spec.rb +28 -0
  107. data/spec/lib/aggro/message/endpoint_spec.rb +23 -0
  108. data/spec/lib/aggro/message/events_spec.rb +37 -0
  109. data/spec/lib/aggro/message/get_events_spec.rb +33 -0
  110. data/spec/lib/aggro/message/heartbeat_spec.rb +23 -0
  111. data/spec/lib/aggro/message/invalid_target_spec.rb +28 -0
  112. data/spec/lib/aggro/message/ok_spec.rb +27 -0
  113. data/spec/lib/aggro/message/publisher_endpoint_inquiry_spec.rb +23 -0
  114. data/spec/lib/aggro/message/query_spec.rb +50 -0
  115. data/spec/lib/aggro/message/start_saga_spec.rb +37 -0
  116. data/spec/lib/aggro/message/unhandled_operation_spec.rb +28 -0
  117. data/spec/lib/aggro/message/unknown_operation_spec.rb +28 -0
  118. data/spec/lib/aggro/message_parser_spec.rb +16 -0
  119. data/spec/lib/aggro/message_router_spec.rb +35 -0
  120. data/spec/lib/aggro/nanomsg_transport/socket_error_spec.rb +21 -0
  121. data/spec/lib/aggro/nanomsg_transport_spec.rb +37 -0
  122. data/spec/lib/aggro/node_list_spec.rb +38 -0
  123. data/spec/lib/aggro/node_spec.rb +44 -0
  124. data/spec/lib/aggro/projection_spec.rb +22 -0
  125. data/spec/lib/aggro/query_spec.rb +47 -0
  126. data/spec/lib/aggro/saga_runner_spec.rb +84 -0
  127. data/spec/lib/aggro/saga_spec.rb +126 -0
  128. data/spec/lib/aggro/saga_status_spec.rb +56 -0
  129. data/spec/lib/aggro/server_spec.rb +118 -0
  130. data/spec/lib/aggro/subscriber_spec.rb +59 -0
  131. data/spec/lib/aggro/subscription_spec.rb +50 -0
  132. data/spec/lib/aggro/transform/boolean_spec.rb +23 -0
  133. data/spec/lib/aggro/transform/email_spec.rb +13 -0
  134. data/spec/lib/aggro/transform/id_spec.rb +70 -0
  135. data/spec/lib/aggro/transform/integer_spec.rb +30 -0
  136. data/spec/lib/aggro/transform/money_spec.rb +34 -0
  137. data/spec/lib/aggro/transform/string_spec.rb +15 -0
  138. data/spec/lib/aggro/transform/time_interval_spec.rb +29 -0
  139. data/spec/lib/aggro_spec.rb +63 -19
  140. data/spec/spec_helper.rb +21 -2
  141. metadata +283 -3
@@ -0,0 +1,32 @@
1
+ module Aggro
2
+ # Public: Locates the nodes responsible for a given entity ID.
3
+ class Locator
4
+ def initialize(id)
5
+ @id = id
6
+ end
7
+
8
+ def local?
9
+ primary_node.is_a? LocalNode
10
+ end
11
+
12
+ def nodes
13
+ current_node_list_state = Aggro.node_list.state
14
+
15
+ if @last_node_list_state == current_node_list_state
16
+ @nodes ||= Aggro.node_list.nodes_for(@id)
17
+ else
18
+ @last_node_list_state = current_node_list_state
19
+
20
+ @nodes = Aggro.node_list.nodes_for(@id)
21
+ end
22
+ end
23
+
24
+ def primary_node
25
+ nodes.first
26
+ end
27
+
28
+ def secondary_nodes
29
+ nodes[1..-1]
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,16 @@
1
+ module Aggro
2
+ module Message
3
+ # Public: Ask message.
4
+ class Ask < Struct.new(:node_id)
5
+ TYPE_CODE = '05'.freeze
6
+
7
+ def self.parse(string)
8
+ new string[2..37]
9
+ end
10
+
11
+ def to_s
12
+ "#{TYPE_CODE}#{node_id}"
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,36 @@
1
+ module Aggro
2
+ module Message
3
+ # Public: Command message.
4
+ class Command < Struct.new(:sender, :commandee_id, :details)
5
+ TYPE_CODE = '03'.freeze
6
+
7
+ def self.parse(string)
8
+ new string[2..37], string[38..73], parse_details(string[74..-1])
9
+ end
10
+
11
+ def self.parse_details(details)
12
+ Marshal.load details
13
+ end
14
+
15
+ def args
16
+ details[:args]
17
+ end
18
+
19
+ def command_class
20
+ ActiveSupport::Inflector.safe_constantize name
21
+ end
22
+
23
+ def name
24
+ details[:name]
25
+ end
26
+
27
+ def to_command
28
+ command_class.new args if command_class
29
+ end
30
+
31
+ def to_s
32
+ "#{TYPE_CODE}#{sender}#{commandee_id}#{Marshal.dump details}"
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,16 @@
1
+ module Aggro
2
+ module Message
3
+ # Public: Create aggregate message.
4
+ class CreateAggregate < Struct.new(:sender, :id, :type)
5
+ TYPE_CODE = '08'.freeze
6
+
7
+ def self.parse(string)
8
+ new string[2..37], string[38..73], string[74..-1]
9
+ end
10
+
11
+ def to_s
12
+ "#{TYPE_CODE}#{sender}#{id}#{type}"
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module Aggro
2
+ module Message
3
+ # Public: Endpoint message.
4
+ class Endpoint < Struct.new(:endpoint)
5
+ TYPE_CODE = '12'.freeze
6
+
7
+ def self.parse(string)
8
+ new string[2..-1]
9
+ end
10
+
11
+ def to_s
12
+ "#{TYPE_CODE}#{endpoint}"
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,24 @@
1
+ module Aggro
2
+ module Message
3
+ # Public: Get events message.
4
+ class Events < Struct.new(:id, :events)
5
+ TYPE_CODE = '10'.freeze
6
+
7
+ def self.parse(string)
8
+ new string[2..37], parse_events(string[38..-1])
9
+ end
10
+
11
+ def self.parse_events(string)
12
+ ObjectStream.new(StringIO.new(string), type: 'marshal')
13
+ end
14
+
15
+ def serialize_events
16
+ events.map { |event| EventSerializer.serialize event }.join
17
+ end
18
+
19
+ def to_s
20
+ "#{TYPE_CODE}#{id}#{serialize_events}"
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,16 @@
1
+ module Aggro
2
+ module Message
3
+ # Public: Get events message.
4
+ class GetEvents < Struct.new(:sender, :id, :from_version)
5
+ TYPE_CODE = '09'.freeze
6
+
7
+ def self.parse(string)
8
+ new string[2..37], string[38..73], string[74..-1].to_i
9
+ end
10
+
11
+ def to_s
12
+ "#{TYPE_CODE}#{sender}#{id}#{from_version || 0}"
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,16 @@
1
+ module Aggro
2
+ module Message
3
+ # Public: Heartbeat message.
4
+ class Heartbeat < Struct.new(:sender)
5
+ TYPE_CODE = '02'.freeze
6
+
7
+ def self.parse(string)
8
+ new string[2..37]
9
+ end
10
+
11
+ def to_s
12
+ "#{TYPE_CODE}#{sender}"
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,20 @@
1
+ module Aggro
2
+ module Message
3
+ # Public: Invalid target message.
4
+ class InvalidTarget
5
+ TYPE_CODE = '06'.freeze
6
+
7
+ def self.parse(_string)
8
+ new
9
+ end
10
+
11
+ def self.new
12
+ @singleton ||= super
13
+ end
14
+
15
+ def to_s
16
+ "#{TYPE_CODE}"
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ module Aggro
2
+ module Message
3
+ # Public: OK message.
4
+ class OK
5
+ TYPE_CODE = '01'.freeze
6
+
7
+ def self.parse(_string)
8
+ new
9
+ end
10
+
11
+ def self.new
12
+ @singleton ||= super
13
+ end
14
+
15
+ def to_s
16
+ "#{TYPE_CODE}"
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,16 @@
1
+ module Aggro
2
+ module Message
3
+ # Public: Publisher endpoint inquiry message.
4
+ class PublisherEndpointInquiry < Struct.new(:sender)
5
+ TYPE_CODE = '11'.freeze
6
+
7
+ def self.parse(string)
8
+ new string[2..37]
9
+ end
10
+
11
+ def to_s
12
+ "#{TYPE_CODE}#{sender}"
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,36 @@
1
+ module Aggro
2
+ module Message
3
+ # Public: Query message.
4
+ class Query < Struct.new(:sender, :queryable_id, :details)
5
+ TYPE_CODE = '15'.freeze
6
+
7
+ def self.parse(string)
8
+ new string[2..37], string[38..73], parse_details(string[74..-1])
9
+ end
10
+
11
+ def self.parse_details(details)
12
+ Marshal.load details
13
+ end
14
+
15
+ def args
16
+ details[:args]
17
+ end
18
+
19
+ def name
20
+ details[:name]
21
+ end
22
+
23
+ def query_class
24
+ ActiveSupport::Inflector.safe_constantize name
25
+ end
26
+
27
+ def to_query
28
+ query_class.new args if query_class
29
+ end
30
+
31
+ def to_s
32
+ "#{TYPE_CODE}#{sender}#{queryable_id}#{Marshal.dump details}"
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,16 @@
1
+ module Aggro
2
+ module Message
3
+ # Public: Result message.
4
+ class Result < Struct.new(:result)
5
+ TYPE_CODE = '14'.freeze
6
+
7
+ def self.parse(string)
8
+ new Marshal.load(string[2..-1])
9
+ end
10
+
11
+ def to_s
12
+ "#{TYPE_CODE}#{Marshal.dump result}"
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,28 @@
1
+ module Aggro
2
+ module Message
3
+ # Public: Start saga message.
4
+ class StartSaga < Struct.new(:sender, :id, :details)
5
+ TYPE_CODE = '13'.freeze
6
+
7
+ def self.parse(string)
8
+ new string[2..37], string[38..73], parse_details(string[74..-1])
9
+ end
10
+
11
+ def self.parse_details(details)
12
+ Marshal.load details
13
+ end
14
+
15
+ def args
16
+ details[:args]
17
+ end
18
+
19
+ def name
20
+ details[:name]
21
+ end
22
+
23
+ def to_s
24
+ "#{TYPE_CODE}#{sender}#{id}#{Marshal.dump details}"
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,20 @@
1
+ module Aggro
2
+ module Message
3
+ # Public: Unhandled operation message.
4
+ class UnhandledOperation
5
+ TYPE_CODE = '07'.freeze
6
+
7
+ def self.parse(_string)
8
+ new
9
+ end
10
+
11
+ def self.new
12
+ @singleton ||= super
13
+ end
14
+
15
+ def to_s
16
+ "#{TYPE_CODE}"
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ module Aggro
2
+ module Message
3
+ # Public: Unknown operation message.
4
+ class UnknownOperation
5
+ TYPE_CODE = '04'.freeze
6
+
7
+ def self.parse(_string)
8
+ new
9
+ end
10
+
11
+ def self.new
12
+ @singleton ||= super
13
+ end
14
+
15
+ def to_s
16
+ "#{TYPE_CODE}"
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,10 @@
1
+ module Aggro
2
+ # Public: Parses inter-node messages.
3
+ module MessageParser
4
+ module_function
5
+
6
+ def parse(message)
7
+ MESSAGE_TYPES[message[0..1]].parse message
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,26 @@
1
+ module Aggro
2
+ # Public: Routes inter-node messages to attached message handlers.
3
+ class MessageRouter
4
+ def initialize
5
+ @handlers = {}
6
+ end
7
+
8
+ def attach_handler(message_class, callable = nil, &block)
9
+ if callable
10
+ @handlers[message_class] = callable
11
+ elsif block_given?
12
+ @handlers[message_class] = block
13
+ else
14
+ fail ArgumentError
15
+ end
16
+ end
17
+
18
+ def handles?(message_class)
19
+ @handlers[message_class]
20
+ end
21
+
22
+ def route(message)
23
+ @handlers[message.class].call message if handles?(message.class)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,31 @@
1
+ require 'aggro/nanomsg_transport/client'
2
+ require 'aggro/nanomsg_transport/publisher'
3
+ require 'aggro/nanomsg_transport/server'
4
+ require 'aggro/nanomsg_transport/subscriber'
5
+
6
+ module Aggro
7
+ # Public: Transport layer over nanomsg sockets.
8
+ module NanomsgTransport
9
+ module_function
10
+
11
+ def client(endpoint)
12
+ Client.new endpoint
13
+ end
14
+
15
+ def publisher(endpoint)
16
+ Publisher.new endpoint
17
+ end
18
+
19
+ def server(endpoint, callable = nil, &block)
20
+ Server.new endpoint, callable, &block
21
+ end
22
+
23
+ def subscriber(endpoint, callable = nil, &block)
24
+ Subscriber.new endpoint, callable, &block
25
+ end
26
+
27
+ def teardown
28
+ NNCore::LibNanomsg.nn_term
29
+ end
30
+ end
31
+ end