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.
- checksums.yaml +4 -4
- data/.rubocop.yml +8 -0
- data/.travis.yml +15 -0
- data/Gemfile +9 -0
- data/README.md +5 -1
- data/Rakefile +10 -0
- data/aggro.gemspec +8 -1
- data/lib/aggro.rb +191 -7
- data/lib/aggro/abstract_store.rb +12 -0
- data/lib/aggro/aggregate.rb +98 -0
- data/lib/aggro/aggregate_ref.rb +68 -6
- data/lib/aggro/attribute_dsl.rb +96 -0
- data/lib/aggro/binding_dsl.rb +45 -0
- data/lib/aggro/block_helper.rb +14 -0
- data/lib/aggro/channel.rb +37 -0
- data/lib/aggro/client.rb +12 -0
- data/lib/aggro/cluster_config.rb +57 -0
- data/lib/aggro/command.rb +16 -0
- data/lib/aggro/concurrent_actor.rb +26 -0
- data/lib/aggro/event_bus.rb +94 -0
- data/lib/aggro/event_dsl.rb +53 -0
- data/lib/aggro/event_proxy.rb +23 -0
- data/lib/aggro/event_serializer.rb +14 -0
- data/lib/aggro/file_store.rb +97 -0
- data/lib/aggro/file_store/reader.rb +21 -0
- data/lib/aggro/file_store/writer.rb +27 -0
- data/lib/aggro/handler/command.rb +60 -0
- data/lib/aggro/handler/create_aggregate.rb +42 -0
- data/lib/aggro/handler/get_events.rb +30 -0
- data/lib/aggro/handler/query.rb +60 -0
- data/lib/aggro/handler/start_saga.rb +56 -0
- data/lib/aggro/local_node.rb +28 -0
- data/lib/aggro/locator.rb +32 -0
- data/lib/aggro/message/ask.rb +16 -0
- data/lib/aggro/message/command.rb +36 -0
- data/lib/aggro/message/create_aggregate.rb +16 -0
- data/lib/aggro/message/endpoint.rb +16 -0
- data/lib/aggro/message/events.rb +24 -0
- data/lib/aggro/message/get_events.rb +16 -0
- data/lib/aggro/message/heartbeat.rb +16 -0
- data/lib/aggro/message/invalid_target.rb +20 -0
- data/lib/aggro/message/ok.rb +20 -0
- data/lib/aggro/message/publisher_endpoint_inquiry.rb +16 -0
- data/lib/aggro/message/query.rb +36 -0
- data/lib/aggro/message/result.rb +16 -0
- data/lib/aggro/message/start_saga.rb +28 -0
- data/lib/aggro/message/unhandled_operation.rb +20 -0
- data/lib/aggro/message/unknown_operation.rb +20 -0
- data/lib/aggro/message_parser.rb +10 -0
- data/lib/aggro/message_router.rb +26 -0
- data/lib/aggro/nanomsg_transport.rb +31 -0
- data/lib/aggro/nanomsg_transport/client.rb +35 -0
- data/lib/aggro/nanomsg_transport/connection.rb +98 -0
- data/lib/aggro/nanomsg_transport/publish.rb +17 -0
- data/lib/aggro/nanomsg_transport/publisher.rb +37 -0
- data/lib/aggro/nanomsg_transport/raw_reply.rb +18 -0
- data/lib/aggro/nanomsg_transport/raw_request.rb +18 -0
- data/lib/aggro/nanomsg_transport/reply.rb +17 -0
- data/lib/aggro/nanomsg_transport/request.rb +17 -0
- data/lib/aggro/nanomsg_transport/server.rb +84 -0
- data/lib/aggro/nanomsg_transport/socket_error.rb +20 -0
- data/lib/aggro/nanomsg_transport/subscribe.rb +27 -0
- data/lib/aggro/nanomsg_transport/subscriber.rb +82 -0
- data/lib/aggro/node.rb +29 -0
- data/lib/aggro/node_list.rb +39 -0
- data/lib/aggro/projection.rb +13 -0
- data/lib/aggro/query.rb +11 -0
- data/lib/aggro/saga.rb +94 -0
- data/lib/aggro/saga_runner.rb +87 -0
- data/lib/aggro/saga_runner/start_saga.rb +12 -0
- data/lib/aggro/saga_status.rb +29 -0
- data/lib/aggro/server.rb +88 -0
- data/lib/aggro/subscriber.rb +48 -0
- data/lib/aggro/subscription.rb +41 -0
- data/lib/aggro/transform/boolean.rb +16 -0
- data/lib/aggro/transform/email.rb +26 -0
- data/lib/aggro/transform/id.rb +34 -0
- data/lib/aggro/transform/integer.rb +22 -0
- data/lib/aggro/transform/money.rb +22 -0
- data/lib/aggro/transform/noop.rb +16 -0
- data/lib/aggro/transform/string.rb +16 -0
- data/lib/aggro/transform/time_interval.rb +24 -0
- data/lib/aggro/version.rb +1 -1
- data/spec/lib/aggro/abstract_store_spec.rb +15 -0
- data/spec/lib/aggro/aggregate_ref_spec.rb +63 -12
- data/spec/lib/aggro/aggregate_spec.rb +207 -0
- data/spec/lib/aggro/channel_spec.rb +87 -0
- data/spec/lib/aggro/client_spec.rb +26 -0
- data/spec/lib/aggro/cluster_config_spec.rb +33 -0
- data/spec/lib/aggro/command_spec.rb +52 -0
- data/spec/lib/aggro/concurrent_actor_spec.rb +44 -0
- data/spec/lib/aggro/event_bus_spec.rb +20 -0
- data/spec/lib/aggro/event_serializer_spec.rb +28 -0
- data/spec/lib/aggro/file_store/reader_spec.rb +32 -0
- data/spec/lib/aggro/file_store/writer_spec.rb +67 -0
- data/spec/lib/aggro/file_store_spec.rb +51 -0
- data/spec/lib/aggro/handler/command_spec.rb +78 -0
- data/spec/lib/aggro/handler/create_aggregate_spec.rb +64 -0
- data/spec/lib/aggro/handler/get_events_handler_spec.rb +45 -0
- data/spec/lib/aggro/handler/query_spec.rb +78 -0
- data/spec/lib/aggro/handler/start_saga_spec.rb +64 -0
- data/spec/lib/aggro/local_node_spec.rb +52 -0
- data/spec/lib/aggro/locator_spec.rb +61 -0
- data/spec/lib/aggro/message/ask_spec.rb +23 -0
- data/spec/lib/aggro/message/command_spec.rb +50 -0
- data/spec/lib/aggro/message/create_aggregate_spec.rb +28 -0
- data/spec/lib/aggro/message/endpoint_spec.rb +23 -0
- data/spec/lib/aggro/message/events_spec.rb +37 -0
- data/spec/lib/aggro/message/get_events_spec.rb +33 -0
- data/spec/lib/aggro/message/heartbeat_spec.rb +23 -0
- data/spec/lib/aggro/message/invalid_target_spec.rb +28 -0
- data/spec/lib/aggro/message/ok_spec.rb +27 -0
- data/spec/lib/aggro/message/publisher_endpoint_inquiry_spec.rb +23 -0
- data/spec/lib/aggro/message/query_spec.rb +50 -0
- data/spec/lib/aggro/message/start_saga_spec.rb +37 -0
- data/spec/lib/aggro/message/unhandled_operation_spec.rb +28 -0
- data/spec/lib/aggro/message/unknown_operation_spec.rb +28 -0
- data/spec/lib/aggro/message_parser_spec.rb +16 -0
- data/spec/lib/aggro/message_router_spec.rb +35 -0
- data/spec/lib/aggro/nanomsg_transport/socket_error_spec.rb +21 -0
- data/spec/lib/aggro/nanomsg_transport_spec.rb +37 -0
- data/spec/lib/aggro/node_list_spec.rb +38 -0
- data/spec/lib/aggro/node_spec.rb +44 -0
- data/spec/lib/aggro/projection_spec.rb +22 -0
- data/spec/lib/aggro/query_spec.rb +47 -0
- data/spec/lib/aggro/saga_runner_spec.rb +84 -0
- data/spec/lib/aggro/saga_spec.rb +126 -0
- data/spec/lib/aggro/saga_status_spec.rb +56 -0
- data/spec/lib/aggro/server_spec.rb +118 -0
- data/spec/lib/aggro/subscriber_spec.rb +59 -0
- data/spec/lib/aggro/subscription_spec.rb +50 -0
- data/spec/lib/aggro/transform/boolean_spec.rb +23 -0
- data/spec/lib/aggro/transform/email_spec.rb +13 -0
- data/spec/lib/aggro/transform/id_spec.rb +70 -0
- data/spec/lib/aggro/transform/integer_spec.rb +30 -0
- data/spec/lib/aggro/transform/money_spec.rb +34 -0
- data/spec/lib/aggro/transform/string_spec.rb +15 -0
- data/spec/lib/aggro/transform/time_interval_spec.rb +29 -0
- data/spec/lib/aggro_spec.rb +63 -19
- data/spec/spec_helper.rb +21 -2
- metadata +283 -3
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'aggro/nanomsg_transport/request'
|
2
|
+
|
3
|
+
module Aggro
|
4
|
+
module NanomsgTransport
|
5
|
+
# Public: Client for making requests against a nanomsg server.
|
6
|
+
class Client
|
7
|
+
def initialize(endpoint)
|
8
|
+
ObjectSpace.define_finalizer self, method(:close_socket)
|
9
|
+
|
10
|
+
@endpoint = endpoint
|
11
|
+
end
|
12
|
+
|
13
|
+
def post(message)
|
14
|
+
request_socket.send_msg message
|
15
|
+
|
16
|
+
request_socket.recv_msg
|
17
|
+
end
|
18
|
+
|
19
|
+
def close_socket
|
20
|
+
request_socket.terminate if @open
|
21
|
+
@request_socket = nil
|
22
|
+
@open = false
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def request_socket
|
28
|
+
@request_socket ||= begin
|
29
|
+
@open = true
|
30
|
+
Request.new(@endpoint)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
require 'nn-core'
|
3
|
+
require 'aggro/nanomsg_transport/socket_error'
|
4
|
+
|
5
|
+
module Aggro
|
6
|
+
module NanomsgTransport
|
7
|
+
# Private: Base class for nanomsg socket wrappers.
|
8
|
+
class Connection
|
9
|
+
attr_reader :socket
|
10
|
+
|
11
|
+
def initialize(endpoint)
|
12
|
+
@endpoint = endpoint
|
13
|
+
@rcv_buffer = FFI::MemoryPointer.new(:pointer)
|
14
|
+
|
15
|
+
allocate_socket
|
16
|
+
setup_socket
|
17
|
+
set_endpoint
|
18
|
+
end
|
19
|
+
|
20
|
+
def setup_socket
|
21
|
+
set_socket_option NNCore::NN_LINGER, 100
|
22
|
+
set_socket_option NNCore::NN_SNDBUF, 131_072
|
23
|
+
set_socket_option NNCore::NN_RCVBUF, 131_072
|
24
|
+
end
|
25
|
+
|
26
|
+
def send_msg(stringable)
|
27
|
+
msg = stringable.to_s
|
28
|
+
nbytes = NNCore::LibNanomsg.nn_send(@socket, msg, msg.bytesize, 0)
|
29
|
+
assert(nbytes)
|
30
|
+
|
31
|
+
nbytes
|
32
|
+
end
|
33
|
+
|
34
|
+
def recv_fd
|
35
|
+
get_socket_option NNCore::NN_RCVFD
|
36
|
+
end
|
37
|
+
|
38
|
+
def recv_msg
|
39
|
+
nbytes = NNCore::LibNanomsg.nn_recv(@socket, @rcv_buffer,
|
40
|
+
NNCore::NN_MSG, 0)
|
41
|
+
|
42
|
+
assert(nbytes)
|
43
|
+
|
44
|
+
str = @rcv_buffer.read_pointer
|
45
|
+
response = str.read_string(nbytes)
|
46
|
+
NNCore::LibNanomsg.nn_freemsg str
|
47
|
+
|
48
|
+
response
|
49
|
+
rescue SocketError => e
|
50
|
+
raise e unless e.errno == NNCore::EAGAIN
|
51
|
+
|
52
|
+
nil
|
53
|
+
end
|
54
|
+
|
55
|
+
def terminate
|
56
|
+
assert NNCore::LibNanomsg.nn_close(@socket)
|
57
|
+
end
|
58
|
+
|
59
|
+
protected
|
60
|
+
|
61
|
+
def assert(rc)
|
62
|
+
fail SocketError.new NNCore::LibNanomsg.nn_errno unless rc >= 0
|
63
|
+
end
|
64
|
+
|
65
|
+
def get_socket_option(setting, level = NNCore::NN_SOL_SOCKET)
|
66
|
+
result = FFI::MemoryPointer.new(:int32)
|
67
|
+
size = FFI::MemoryPointer.new(:size_t)
|
68
|
+
size.write_int result.size
|
69
|
+
|
70
|
+
rc = NNCore::LibNanomsg.nn_getsockopt(@socket, level, setting,
|
71
|
+
result, size)
|
72
|
+
|
73
|
+
assert(rc)
|
74
|
+
|
75
|
+
result.read_int
|
76
|
+
end
|
77
|
+
|
78
|
+
def prepare_socket_option(value)
|
79
|
+
if value.is_a? String
|
80
|
+
[value, value.bytesize]
|
81
|
+
else
|
82
|
+
option = FFI::MemoryPointer.new(:int32)
|
83
|
+
option.write_int(value)
|
84
|
+
|
85
|
+
[option, 4]
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def set_socket_option(setting, value, level = NNCore::NN_SOL_SOCKET)
|
90
|
+
option, option_length = prepare_socket_option(value)
|
91
|
+
|
92
|
+
rc = NNCore::LibNanomsg.nn_setsockopt(@socket, level, setting,
|
93
|
+
option, option_length)
|
94
|
+
assert(rc)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'aggro/nanomsg_transport/connection'
|
2
|
+
|
3
|
+
module Aggro
|
4
|
+
module NanomsgTransport
|
5
|
+
# Private: Wrapper for a nanomsg PUB node.
|
6
|
+
class Publish < Connection
|
7
|
+
def allocate_socket
|
8
|
+
@socket = NNCore::LibNanomsg.nn_socket(NNCore::AF_SP, NNCore::NN_PUB)
|
9
|
+
assert @socket
|
10
|
+
end
|
11
|
+
|
12
|
+
def set_endpoint
|
13
|
+
assert NNCore::LibNanomsg.nn_bind(@socket, @endpoint)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'aggro/nanomsg_transport/publish'
|
2
|
+
|
3
|
+
module Aggro
|
4
|
+
module NanomsgTransport
|
5
|
+
# Public: Handles publishing messages on a given endpoint.
|
6
|
+
class Publisher
|
7
|
+
def initialize(endpoint)
|
8
|
+
ObjectSpace.define_finalizer self, method(:close_socket)
|
9
|
+
|
10
|
+
@endpoint = endpoint
|
11
|
+
end
|
12
|
+
|
13
|
+
def close_socket
|
14
|
+
pub_socket.terminate if @open
|
15
|
+
@pub_socket = nil
|
16
|
+
@open = false
|
17
|
+
end
|
18
|
+
|
19
|
+
def open_socket
|
20
|
+
return @pub_socket if @open
|
21
|
+
|
22
|
+
@open = true
|
23
|
+
@pub_socket = Publish.new(@endpoint)
|
24
|
+
end
|
25
|
+
|
26
|
+
def publish(message)
|
27
|
+
pub_socket.send_msg message
|
28
|
+
end
|
29
|
+
|
30
|
+
private
|
31
|
+
|
32
|
+
def pub_socket
|
33
|
+
@pub_socket || open_socket
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'aggro/nanomsg_transport/connection'
|
2
|
+
|
3
|
+
module Aggro
|
4
|
+
module NanomsgTransport
|
5
|
+
# Private: Wrapper for a nanomsg XREP node.
|
6
|
+
class RawReply < Connection
|
7
|
+
def allocate_socket
|
8
|
+
@socket = NNCore::LibNanomsg.nn_socket(NNCore::AF_SP_RAW,
|
9
|
+
NNCore::NN_REP)
|
10
|
+
assert @socket
|
11
|
+
end
|
12
|
+
|
13
|
+
def set_endpoint
|
14
|
+
assert NNCore::LibNanomsg.nn_bind(@socket, @endpoint)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'aggro/nanomsg_transport/connection'
|
2
|
+
|
3
|
+
module Aggro
|
4
|
+
module NanomsgTransport
|
5
|
+
# Private: Wrapper for a nanomsg XREQ node.
|
6
|
+
class RawRequest < Connection
|
7
|
+
def allocate_socket
|
8
|
+
@socket = NNCore::LibNanomsg.nn_socket(NNCore::AF_SP_RAW,
|
9
|
+
NNCore::NN_REQ)
|
10
|
+
assert @socket
|
11
|
+
end
|
12
|
+
|
13
|
+
def set_endpoint
|
14
|
+
assert NNCore::LibNanomsg.nn_bind(@socket, @endpoint)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'aggro/nanomsg_transport/connection'
|
2
|
+
|
3
|
+
module Aggro
|
4
|
+
module NanomsgTransport
|
5
|
+
# Private: Wrapper for a nanomsg REP node.
|
6
|
+
class Reply < Connection
|
7
|
+
def allocate_socket
|
8
|
+
@socket = NNCore::LibNanomsg.nn_socket(NNCore::AF_SP, NNCore::NN_REP)
|
9
|
+
assert @socket
|
10
|
+
end
|
11
|
+
|
12
|
+
def set_endpoint
|
13
|
+
assert NNCore::LibNanomsg.nn_connect(@socket, @endpoint)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'aggro/nanomsg_transport/connection'
|
2
|
+
|
3
|
+
module Aggro
|
4
|
+
module NanomsgTransport
|
5
|
+
# Private: Wrapper for a nanomsg REQ node.
|
6
|
+
class Request < Connection
|
7
|
+
def allocate_socket
|
8
|
+
@socket = NNCore::LibNanomsg.nn_socket(NNCore::AF_SP, NNCore::NN_REQ)
|
9
|
+
assert @socket
|
10
|
+
end
|
11
|
+
|
12
|
+
def set_endpoint
|
13
|
+
assert NNCore::LibNanomsg.nn_connect(@socket, @endpoint)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
require 'nio'
|
2
|
+
|
3
|
+
require 'aggro/nanomsg_transport/raw_reply'
|
4
|
+
require 'aggro/nanomsg_transport/raw_request'
|
5
|
+
require 'aggro/nanomsg_transport/reply'
|
6
|
+
|
7
|
+
module Aggro
|
8
|
+
module NanomsgTransport
|
9
|
+
# Public: Server to handle messages from nanomsg clients.
|
10
|
+
class Server
|
11
|
+
DEFAULT_WORKER_COUNT = 16
|
12
|
+
|
13
|
+
class ServerAlreadyRunning < RuntimeError; end
|
14
|
+
|
15
|
+
def initialize(endpoint, callable = nil, &block)
|
16
|
+
fail ArgumentError unless callable || block_given?
|
17
|
+
|
18
|
+
@callable = block_given? ? block : callable
|
19
|
+
@endpoint = endpoint
|
20
|
+
@selectors = DEFAULT_WORKER_COUNT.times.map { NIO::Selector.new }
|
21
|
+
@inproc_endpoint = "inproc://aggro-server-#{SecureRandom.hex}"
|
22
|
+
|
23
|
+
ObjectSpace.define_finalizer self, method(:stop)
|
24
|
+
end
|
25
|
+
|
26
|
+
def start
|
27
|
+
fail ServerAlreadyRunning if @running
|
28
|
+
|
29
|
+
@running = true
|
30
|
+
start_master
|
31
|
+
DEFAULT_WORKER_COUNT.times { |i| start_worker i }
|
32
|
+
|
33
|
+
sleep 0.01 while @selectors.any?(&:empty?)
|
34
|
+
|
35
|
+
self
|
36
|
+
end
|
37
|
+
|
38
|
+
def stop
|
39
|
+
return self unless @running
|
40
|
+
|
41
|
+
@running = false
|
42
|
+
@selectors.each(&:wakeup)
|
43
|
+
|
44
|
+
sleep 0.01 until @selectors.any?(&:empty?)
|
45
|
+
|
46
|
+
@raw_reply.terminate
|
47
|
+
@raw_request.terminate
|
48
|
+
|
49
|
+
self
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def handle_request(socket)
|
55
|
+
message = socket.recv_msg
|
56
|
+
socket.send_msg @callable.call(message) if @running
|
57
|
+
end
|
58
|
+
|
59
|
+
def start_master
|
60
|
+
@master_thread = Concurrent::SingleThreadExecutor.new.post do
|
61
|
+
@raw_reply = RawReply.new(@endpoint)
|
62
|
+
@raw_request = RawRequest.new(@inproc_endpoint)
|
63
|
+
|
64
|
+
NNCore::LibNanomsg.nn_device @raw_request.socket, @raw_reply.socket
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def start_worker(i)
|
69
|
+
Concurrent::SingleThreadExecutor.new.post do
|
70
|
+
reply = Reply.new(@inproc_endpoint)
|
71
|
+
io = IO.new(reply.recv_fd, 'rb', autoclose: false)
|
72
|
+
|
73
|
+
@selectors[i].register io, :r
|
74
|
+
|
75
|
+
@selectors[i].select { handle_request(reply) } while @running
|
76
|
+
|
77
|
+
@selectors[i].deregister io
|
78
|
+
io.close
|
79
|
+
reply.terminate
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Aggro
|
2
|
+
module NanomsgTransport
|
3
|
+
# Public: An error calling the nanomsg API.
|
4
|
+
class SocketError < RuntimeError
|
5
|
+
attr_reader :errno
|
6
|
+
|
7
|
+
def initialize(errno)
|
8
|
+
@errno = errno
|
9
|
+
end
|
10
|
+
|
11
|
+
def error_message
|
12
|
+
NNCore::LibNanomsg.nn_strerror(errno)
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
"Last nanomsg API call failed with '#{error_message}'"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'aggro/nanomsg_transport/connection'
|
2
|
+
|
3
|
+
module Aggro
|
4
|
+
module NanomsgTransport
|
5
|
+
# Private: Wrapper for a nanomsg SUB node.
|
6
|
+
class Subscribe < Connection
|
7
|
+
def add_subscription(topic)
|
8
|
+
set_socket_option NNCore::NN_SUB_SUBSCRIBE, topic, NNCore::NN_SUB
|
9
|
+
end
|
10
|
+
|
11
|
+
def allocate_socket
|
12
|
+
@socket = NNCore::LibNanomsg.nn_socket(NNCore::AF_SP, NNCore::NN_SUB)
|
13
|
+
assert @socket
|
14
|
+
end
|
15
|
+
|
16
|
+
def set_endpoint
|
17
|
+
assert NNCore::LibNanomsg.nn_connect(@socket, @endpoint)
|
18
|
+
end
|
19
|
+
|
20
|
+
def setup_socket
|
21
|
+
super
|
22
|
+
|
23
|
+
set_socket_option NNCore::NN_RCVTIMEO, 100
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'aggro/nanomsg_transport/subscribe'
|
2
|
+
|
3
|
+
module Aggro
|
4
|
+
module NanomsgTransport
|
5
|
+
# Public: Handles subscribing to messages on a given endpoint.
|
6
|
+
class Subscriber
|
7
|
+
class SubscriberAlreadyRunning < RuntimeError; end
|
8
|
+
|
9
|
+
def initialize(endpoint, callable = nil, &block)
|
10
|
+
fail ArgumentError unless callable || block_given?
|
11
|
+
|
12
|
+
@callable = block_given? ? block : callable
|
13
|
+
@endpoint = endpoint
|
14
|
+
@mutex = Mutex.new
|
15
|
+
@selector = NIO::Selector.new
|
16
|
+
|
17
|
+
ObjectSpace.define_finalizer self, method(:stop)
|
18
|
+
end
|
19
|
+
|
20
|
+
def add_subscription(topic)
|
21
|
+
start unless @running
|
22
|
+
|
23
|
+
@mutex.synchronize do
|
24
|
+
sub_socket.add_subscription(topic)
|
25
|
+
end
|
26
|
+
|
27
|
+
self
|
28
|
+
end
|
29
|
+
|
30
|
+
def start
|
31
|
+
@mutex.synchronize do
|
32
|
+
return self if @running
|
33
|
+
|
34
|
+
@running = true
|
35
|
+
start_on_thread
|
36
|
+
|
37
|
+
sleep 0.01 while @selector.empty?
|
38
|
+
end
|
39
|
+
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
def stop
|
44
|
+
@mutex.synchronize do
|
45
|
+
return self unless @running
|
46
|
+
|
47
|
+
@running = false
|
48
|
+
@selector.wakeup
|
49
|
+
|
50
|
+
sleep 0.01 until @selector.empty?
|
51
|
+
end
|
52
|
+
|
53
|
+
self
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
def handle_message
|
59
|
+
message = sub_socket.recv_msg
|
60
|
+
@callable.call(message) if message
|
61
|
+
end
|
62
|
+
|
63
|
+
def sub_socket
|
64
|
+
@sub_socket ||= Subscribe.new(@endpoint)
|
65
|
+
end
|
66
|
+
|
67
|
+
def start_on_thread
|
68
|
+
Concurrent::SingleThreadExecutor.new.post do
|
69
|
+
io = IO.new(sub_socket.recv_fd, 'rb', autoclose: false)
|
70
|
+
@selector.register io, :r
|
71
|
+
|
72
|
+
@selector.select { handle_message } while @running
|
73
|
+
|
74
|
+
@selector.deregister io
|
75
|
+
io.close
|
76
|
+
sub_socket.terminate
|
77
|
+
@sub_socket = nil
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|