em-zeromq 0.3.1 → 0.4.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.
- data/README.md +15 -40
- data/em-zeromq.gemspec +1 -1
- data/example/multi-part.rb +31 -0
- data/example/simple.rb +10 -14
- data/example/simpler.rb +23 -0
- data/example/terminating.rb +23 -0
- data/lib/em-zeromq.rb +4 -55
- data/lib/em-zeromq/context.rb +3 -12
- data/lib/em-zeromq/event_emitter.rb +31 -0
- data/lib/em-zeromq/socket.rb +19 -56
- data/lib/em-zeromq/version.rb +1 -1
- data/spec/pub_sub_spec.rb +15 -24
- data/spec/push_pull_spec.rb +12 -22
- data/spec/router_dealer_spec.rb +27 -49
- data/spec/spec_helper.rb +1 -1
- metadata +12 -8
data/README.md
CHANGED
@@ -53,50 +53,25 @@ flag api changes but be aware that small changes can still occur between release
|
|
53
53
|
|
54
54
|
## Example ##
|
55
55
|
```ruby
|
56
|
-
require 'rubygems'
|
57
56
|
require 'em-zeromq'
|
58
57
|
|
59
|
-
|
60
|
-
attr_reader :received
|
61
|
-
def on_readable(socket, parts)
|
62
|
-
parts.each do |m|
|
63
|
-
puts m.copy_out_string
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
58
|
+
zmq = EM::ZeroMQ::Context.new(1)
|
67
59
|
|
68
|
-
|
69
|
-
|
70
|
-
|
60
|
+
EM.run {
|
61
|
+
push = zmq.socket(ZMQ::PUSH)
|
62
|
+
push.connect("tcp://127.0.0.1:2091")
|
71
63
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
push_socket3.bind('inproc://simple_test')
|
84
|
-
|
85
|
-
# setup one pull sockets listening to all push sockets
|
86
|
-
pull_socket = ctx.socket(ZMQ::PULL, EMTestPullHandler.new)
|
87
|
-
pull_socket.connect('tcp://127.0.0.1:2091')
|
88
|
-
pull_socket.connect('ipc:///tmp/a')
|
89
|
-
pull_socket.connect('inproc://simple_test')
|
90
|
-
|
91
|
-
n = 0
|
92
|
-
|
93
|
-
EM::PeriodicTimer.new(0.1) do
|
94
|
-
puts '.'
|
95
|
-
push_socket1.send_msg("t#{n += 1}_")
|
96
|
-
push_socket2.send_msg("i#{n += 1}_")
|
97
|
-
push_socket3.send_msg("p#{n += 1}_")
|
98
|
-
end
|
99
|
-
end
|
64
|
+
pull = zmq.socket(ZMQ::PULL)
|
65
|
+
pull.bind("tcp://127.0.0.1:2091")
|
66
|
+
|
67
|
+
pull.on(:message) { |part|
|
68
|
+
puts part.copy_out_string
|
69
|
+
}
|
70
|
+
|
71
|
+
EM.add_periodic_timer(1) {
|
72
|
+
push.send_msg("Hello")
|
73
|
+
}
|
74
|
+
}
|
100
75
|
```
|
101
76
|
|
102
77
|
## License: ##
|
data/em-zeromq.gemspec
CHANGED
@@ -0,0 +1,31 @@
|
|
1
|
+
# This example shows how one might deal with sending and recieving multi-part
|
2
|
+
# messages
|
3
|
+
|
4
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
5
|
+
|
6
|
+
require 'em-zeromq'
|
7
|
+
|
8
|
+
zmq = EM::ZeroMQ::Context.new(1)
|
9
|
+
|
10
|
+
EM.run {
|
11
|
+
pull = zmq.socket(ZMQ::PULL)
|
12
|
+
pull.bind("ipc:///tmp/test")
|
13
|
+
|
14
|
+
pull.on(:message) { |part1, part2|
|
15
|
+
p [:part1, part1.copy_out_string, :part2, part2.copy_out_string]
|
16
|
+
}
|
17
|
+
|
18
|
+
pull.on(:message) { |*parts|
|
19
|
+
p [:parts, parts.map(&:copy_out_string)]
|
20
|
+
}
|
21
|
+
|
22
|
+
push = zmq.socket(ZMQ::PUSH)
|
23
|
+
push.connect("ipc:///tmp/test")
|
24
|
+
|
25
|
+
i = 0
|
26
|
+
EM.add_periodic_timer(1) {
|
27
|
+
puts "Sending 2-part message"
|
28
|
+
i += 1
|
29
|
+
push.send_msg("hello #{i}", "second part")
|
30
|
+
}
|
31
|
+
}
|
data/example/simple.rb
CHANGED
@@ -4,23 +4,14 @@ require 'em-zeromq'
|
|
4
4
|
|
5
5
|
Thread.abort_on_exception = true
|
6
6
|
|
7
|
-
class EMTestPullHandler
|
8
|
-
attr_reader :received
|
9
|
-
def on_readable(socket, parts)
|
10
|
-
parts.each do |m|
|
11
|
-
puts m.copy_out_string
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
7
|
trap('INT') do
|
17
8
|
EM::stop()
|
18
9
|
end
|
19
10
|
|
20
11
|
puts "Started (with zmq #{ZMQ::Util.version.join('.')})."
|
21
12
|
|
22
|
-
|
23
13
|
ctx = EM::ZeroMQ::Context.new(1)
|
14
|
+
|
24
15
|
EM.run do
|
25
16
|
# setup push sockets
|
26
17
|
push_socket1 = ctx.socket(ZMQ::PUSH)
|
@@ -30,19 +21,24 @@ EM.run do
|
|
30
21
|
|
31
22
|
push_socket1.bind('tcp://127.0.0.1:2091')
|
32
23
|
|
33
|
-
push_socket2 = ctx.socket(ZMQ::PUSH)
|
34
|
-
|
35
|
-
end
|
24
|
+
push_socket2 = ctx.socket(ZMQ::PUSH)
|
25
|
+
push_socket2.bind('ipc:///tmp/a')
|
36
26
|
|
37
27
|
push_socket3 = ctx.socket(ZMQ::PUSH)
|
38
28
|
push_socket3.bind('inproc://simple_test')
|
39
29
|
|
40
30
|
# setup one pull sockets listening to all push sockets
|
41
|
-
pull_socket = ctx.socket(ZMQ::PULL
|
31
|
+
pull_socket = ctx.socket(ZMQ::PULL)
|
42
32
|
pull_socket.connect('tcp://127.0.0.1:2091')
|
43
33
|
pull_socket.connect('ipc:///tmp/a')
|
44
34
|
pull_socket.connect('inproc://simple_test')
|
45
35
|
|
36
|
+
pull_socket.on(:message) { |*parts|
|
37
|
+
parts.each do |m|
|
38
|
+
puts m.copy_out_string
|
39
|
+
end
|
40
|
+
}
|
41
|
+
|
46
42
|
n = 0
|
47
43
|
|
48
44
|
EM::PeriodicTimer.new(0.1) do
|
data/example/simpler.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# Simpler than simple.rb ;)
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
4
|
+
|
5
|
+
require 'em-zeromq'
|
6
|
+
|
7
|
+
zmq = EM::ZeroMQ::Context.new(1)
|
8
|
+
|
9
|
+
EM.run {
|
10
|
+
push = zmq.socket(ZMQ::PUSH)
|
11
|
+
push.connect("tcp://127.0.0.1:2091")
|
12
|
+
|
13
|
+
pull = zmq.socket(ZMQ::PULL)
|
14
|
+
pull.bind("tcp://127.0.0.1:2091")
|
15
|
+
|
16
|
+
pull.on(:message) { |part|
|
17
|
+
puts part.copy_out_string
|
18
|
+
}
|
19
|
+
|
20
|
+
EM.add_periodic_timer(1) {
|
21
|
+
push.send_msg("Hello")
|
22
|
+
}
|
23
|
+
}
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# This example shows how to use setsockopt to set the linger period for socket
|
2
|
+
# shutdown. This is useful since by default pending meesages will block the
|
3
|
+
# termination of the ZMQ context.
|
4
|
+
|
5
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
6
|
+
|
7
|
+
require 'em-zeromq'
|
8
|
+
|
9
|
+
zmq = EM::ZeroMQ::Context.new(1)
|
10
|
+
|
11
|
+
EM.run {
|
12
|
+
push = zmq.socket(ZMQ::PUSH)
|
13
|
+
push.setsockopt(ZMQ::LINGER, 0)
|
14
|
+
|
15
|
+
push.connect("ipc:///tmp/foo")
|
16
|
+
|
17
|
+
push.send_msg('hello')
|
18
|
+
|
19
|
+
Signal.trap('INT') {
|
20
|
+
puts 'Trapped INT signal. Stopping eventmachine'
|
21
|
+
EM.stop
|
22
|
+
}
|
23
|
+
}
|
data/lib/em-zeromq.rb
CHANGED
@@ -3,59 +3,8 @@ require 'ffi-rzmq'
|
|
3
3
|
|
4
4
|
module EmZeromq
|
5
5
|
|
6
|
-
|
7
|
-
LIBPATH = ::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
|
8
|
-
PATH = ::File.dirname(LIBPATH) + ::File::SEPARATOR
|
9
|
-
# :startdoc:
|
10
|
-
|
11
|
-
# Returns the library path for the module. If any arguments are given,
|
12
|
-
# they will be joined to the end of the libray path using
|
13
|
-
# <tt>File.join</tt>.
|
14
|
-
#
|
15
|
-
def self.libpath( *args, &block )
|
16
|
-
rv = args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
|
17
|
-
if block
|
18
|
-
begin
|
19
|
-
$LOAD_PATH.unshift LIBPATH
|
20
|
-
rv = block.call
|
21
|
-
ensure
|
22
|
-
$LOAD_PATH.shift
|
23
|
-
end
|
24
|
-
end
|
25
|
-
return rv
|
26
|
-
end
|
27
|
-
|
28
|
-
# Returns the lpath for the module. If any arguments are given,
|
29
|
-
# they will be joined to the end of the path using
|
30
|
-
# <tt>File.join</tt>.
|
31
|
-
#
|
32
|
-
def self.path( *args, &block )
|
33
|
-
rv = args.empty? ? PATH : ::File.join(PATH, args.flatten)
|
34
|
-
if block
|
35
|
-
begin
|
36
|
-
$LOAD_PATH.unshift PATH
|
37
|
-
rv = block.call
|
38
|
-
ensure
|
39
|
-
$LOAD_PATH.shift
|
40
|
-
end
|
41
|
-
end
|
42
|
-
return rv
|
43
|
-
end
|
44
|
-
|
45
|
-
# Utility method used to require all files ending in .rb that lie in the
|
46
|
-
# directory below this file that has the same name as the filename passed
|
47
|
-
# in. Optionally, a specific _directory_ name can be passed in such that
|
48
|
-
# the _filename_ does not have to be equivalent to the directory.
|
49
|
-
#
|
50
|
-
def self.require_all_libs_relative_to( fname, dir = nil )
|
51
|
-
dir ||= ::File.basename(fname, '.*')
|
52
|
-
search_me = ::File.expand_path(
|
53
|
-
::File.join(::File.dirname(fname), dir, '**', '*.rb'))
|
54
|
-
|
55
|
-
Dir.glob(search_me).sort.each {|rb| require rb}
|
56
|
-
end
|
57
|
-
|
58
|
-
end # module EmZeromq
|
59
|
-
|
60
|
-
EmZeromq.require_all_libs_relative_to(__FILE__)
|
6
|
+
end
|
61
7
|
|
8
|
+
require 'em-zeromq/context'
|
9
|
+
require 'em-zeromq/event_emitter'
|
10
|
+
require 'em-zeromq/socket'
|
data/lib/em-zeromq/context.rb
CHANGED
@@ -7,8 +7,7 @@
|
|
7
7
|
module EventMachine
|
8
8
|
module ZeroMQ
|
9
9
|
class Context
|
10
|
-
|
11
|
-
WRITABLES = [ ZMQ::PUB, ZMQ::PUSH, ZMQ::ROUTER, ZMQ::DEALER, ZMQ::REP, ZMQ::REQ ]
|
10
|
+
|
12
11
|
|
13
12
|
def initialize(threads_or_context)
|
14
13
|
if threads_or_context.is_a?(ZMQ::Context)
|
@@ -24,10 +23,8 @@ module EventMachine
|
|
24
23
|
# @param [Integer] socket_type One of ZMQ::REQ, ZMQ::REP, ZMQ::PULL, ZMQ::PUSH,
|
25
24
|
# ZMQ::ROUTER, ZMQ::DEALER
|
26
25
|
#
|
27
|
-
# @param [Object] handler an object which respond to on_readable(socket, parts)
|
28
|
-
# and can respond to on_writeable(socket)
|
29
26
|
#
|
30
|
-
def socket(socket_type
|
27
|
+
def socket(socket_type)
|
31
28
|
zmq_socket = @context.socket(socket_type)
|
32
29
|
|
33
30
|
fd = []
|
@@ -35,13 +32,7 @@ module EventMachine
|
|
35
32
|
raise "Unable to get socket FD: #{ZMQ::Util.error_string}"
|
36
33
|
end
|
37
34
|
|
38
|
-
|
39
|
-
EM.watch(fd[0], EventMachine::ZeroMQ::Socket, zmq_socket, socket_type, handler).tap do |s|
|
40
|
-
s.register_readable if READABLES.include?(socket_type)
|
41
|
-
s.register_writable if WRITABLES.include?(socket_type)
|
42
|
-
|
43
|
-
yield(s) if block_given?
|
44
|
-
end
|
35
|
+
EM.watch(fd[0], EventMachine::ZeroMQ::Socket, zmq_socket, socket_type)
|
45
36
|
end
|
46
37
|
|
47
38
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module EventMachine
|
2
|
+
module ZeroMQ
|
3
|
+
module EventEmitter
|
4
|
+
def on(event, &listener)
|
5
|
+
_listeners[event] << listener
|
6
|
+
end
|
7
|
+
|
8
|
+
def emit(event, *args)
|
9
|
+
_listeners[event].each { |l| l.call(*args) }
|
10
|
+
end
|
11
|
+
|
12
|
+
def remove_listener(event, &listener)
|
13
|
+
_listeners[event].delete(listener)
|
14
|
+
end
|
15
|
+
|
16
|
+
def remove_all_listeners(event)
|
17
|
+
_listeners.delete(event)
|
18
|
+
end
|
19
|
+
|
20
|
+
def listeners(event)
|
21
|
+
_listeners[event]
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def _listeners
|
27
|
+
@_listeners ||= Hash.new { |h,k| h[k] = [] }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/em-zeromq/socket.rb
CHANGED
@@ -1,13 +1,19 @@
|
|
1
1
|
module EventMachine
|
2
2
|
module ZeroMQ
|
3
3
|
class Socket < EventMachine::Connection
|
4
|
-
|
4
|
+
READABLES = [ ZMQ::SUB, ZMQ::PULL, ZMQ::ROUTER, ZMQ::DEALER, ZMQ::REP, ZMQ::REQ, ZMQ::PAIR ]
|
5
|
+
WRITABLES = [ ZMQ::PUB, ZMQ::PUSH, ZMQ::ROUTER, ZMQ::DEALER, ZMQ::REP, ZMQ::REQ, ZMQ::PAIR ]
|
6
|
+
|
7
|
+
include EventEmitter
|
8
|
+
|
5
9
|
attr_reader :socket, :socket_type
|
6
10
|
|
7
|
-
def initialize(socket, socket_type
|
11
|
+
def initialize(socket, socket_type)
|
8
12
|
@socket = socket
|
9
13
|
@socket_type = socket_type
|
10
|
-
|
14
|
+
|
15
|
+
self.notify_readable = true if READABLES.include?(socket_type)
|
16
|
+
self.notify_writable = true if WRITABLES.include?(socket_type)
|
11
17
|
end
|
12
18
|
|
13
19
|
def self.map_sockopt(opt, name)
|
@@ -96,26 +102,10 @@ module EventMachine
|
|
96
102
|
def setsockopt(opt, value)
|
97
103
|
@socket.setsockopt(opt, value)
|
98
104
|
end
|
99
|
-
|
100
|
-
# cleanup when ending loop
|
101
|
-
def unbind
|
102
|
-
detach_and_close
|
103
|
-
end
|
104
|
-
|
105
|
-
# Make this socket available for reads
|
106
|
-
def register_readable
|
107
|
-
# Since ZMQ is event triggered I think this is necessary
|
108
|
-
if readable?
|
109
|
-
notify_readable
|
110
|
-
end
|
111
|
-
# Subscribe to EM read notifications
|
112
|
-
self.notify_readable = true
|
113
|
-
end
|
114
105
|
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
self.notify_writable = true
|
106
|
+
def unbind
|
107
|
+
detach
|
108
|
+
@socket.close
|
119
109
|
end
|
120
110
|
|
121
111
|
def notify_readable
|
@@ -124,25 +114,9 @@ module EventMachine
|
|
124
114
|
# I'm leaving this is because its in the docs, but it could probably
|
125
115
|
# be taken out.
|
126
116
|
return unless readable?
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
msg = get_message
|
131
|
-
if msg
|
132
|
-
msg_parts << msg
|
133
|
-
while @socket.more_parts?
|
134
|
-
msg = get_message
|
135
|
-
if msg
|
136
|
-
msg_parts << msg
|
137
|
-
else
|
138
|
-
raise "Multi-part message missing a message!"
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
@handler.on_readable(self, msg_parts)
|
143
|
-
else
|
144
|
-
break
|
145
|
-
end
|
117
|
+
|
118
|
+
while (message = get_message)
|
119
|
+
emit(:message, *message)
|
146
120
|
end
|
147
121
|
end
|
148
122
|
|
@@ -154,9 +128,7 @@ module EventMachine
|
|
154
128
|
# write events
|
155
129
|
self.notify_writable = false
|
156
130
|
|
157
|
-
|
158
|
-
@handler.on_writable(self)
|
159
|
-
end
|
131
|
+
emit(:writable)
|
160
132
|
end
|
161
133
|
def readable?
|
162
134
|
(getsockopt(ZMQ::EVENTS) & ZMQ::POLLIN) == ZMQ::POLLIN
|
@@ -169,20 +141,11 @@ module EventMachine
|
|
169
141
|
end
|
170
142
|
|
171
143
|
private
|
172
|
-
|
173
|
-
# internal methods
|
174
144
|
|
175
145
|
def get_message
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
end
|
180
|
-
|
181
|
-
# Detaches the socket from the EM loop,
|
182
|
-
# then closes the socket
|
183
|
-
def detach_and_close
|
184
|
-
detach
|
185
|
-
@socket.close
|
146
|
+
parts = []
|
147
|
+
rc = @socket.recvmsgs(parts, ZMQ::NOBLOCK)
|
148
|
+
rc >= 0 ? parts : nil
|
186
149
|
end
|
187
150
|
end
|
188
151
|
end
|
data/lib/em-zeromq/version.rb
CHANGED
data/spec/pub_sub_spec.rb
CHANGED
@@ -1,22 +1,12 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), %w[spec_helper])
|
2
2
|
|
3
3
|
describe EventMachine::ZeroMQ do
|
4
|
-
class EMTestSubHandler
|
5
|
-
attr_reader :received
|
6
|
-
def initialize
|
7
|
-
@received = []
|
8
|
-
end
|
9
|
-
def on_readable(socket, messages)
|
10
|
-
@received += messages
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
4
|
it "Should instantiate a connection given valid opts" do
|
15
5
|
sub_conn = nil
|
16
6
|
address = rand_addr
|
17
7
|
|
18
|
-
run_reactor
|
19
|
-
sub_conn = SPEC_CTX.socket(ZMQ::PUB
|
8
|
+
run_reactor do
|
9
|
+
sub_conn = SPEC_CTX.socket(ZMQ::PUB)
|
20
10
|
sub_conn.bind(address)
|
21
11
|
end
|
22
12
|
sub_conn.should be_a(EventMachine::ZeroMQ::Socket)
|
@@ -24,42 +14,43 @@ describe EventMachine::ZeroMQ do
|
|
24
14
|
|
25
15
|
describe "sending/receiving a single message via PUB/SUB" do
|
26
16
|
before(:all) do
|
27
|
-
results = {}
|
17
|
+
@results = {}
|
18
|
+
@received = []
|
28
19
|
@test_message = test_message = "TMsg#{rand(999)}"
|
29
20
|
|
30
|
-
run_reactor
|
21
|
+
run_reactor do
|
31
22
|
address = rand_addr
|
32
23
|
|
33
|
-
|
34
|
-
sub_conn = SPEC_CTX.socket(ZMQ::SUB, pull_hndlr)
|
24
|
+
sub_conn = SPEC_CTX.socket(ZMQ::SUB)
|
35
25
|
sub_conn.bind(address)
|
36
26
|
sub_conn.subscribe('')
|
27
|
+
sub_conn.on(:message) { |m|
|
28
|
+
@received << m
|
29
|
+
}
|
37
30
|
|
38
|
-
pub_conn = SPEC_CTX.socket(ZMQ::PUB
|
31
|
+
pub_conn = SPEC_CTX.socket(ZMQ::PUB)
|
39
32
|
pub_conn.connect(address)
|
40
33
|
|
41
34
|
pub_conn.socket.send_string test_message, ZMQ::NOBLOCK
|
42
35
|
|
43
|
-
EM::Timer.new(0.1) { results[:specs_ran] = true }
|
36
|
+
EM::Timer.new(0.1) { @results[:specs_ran] = true }
|
44
37
|
end
|
45
|
-
|
46
|
-
@results = results
|
47
38
|
end
|
48
39
|
|
49
40
|
it "should run completely" do
|
50
|
-
@
|
41
|
+
@received.should be_true
|
51
42
|
end
|
52
43
|
|
53
44
|
it "should receive one message" do
|
54
|
-
@
|
45
|
+
@received.length.should == 1
|
55
46
|
end
|
56
47
|
|
57
48
|
it "should receive the message as a ZMQ::Message" do
|
58
|
-
@
|
49
|
+
@received.first.should be_a(ZMQ::Message)
|
59
50
|
end
|
60
51
|
|
61
52
|
it "should receive the message intact" do
|
62
|
-
@
|
53
|
+
@received.first.copy_out_string.should == @test_message
|
63
54
|
end
|
64
55
|
end
|
65
56
|
end
|
data/spec/push_pull_spec.rb
CHANGED
@@ -1,20 +1,10 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), %w[spec_helper])
|
2
2
|
|
3
3
|
describe EventMachine::ZeroMQ do
|
4
|
-
class EMTestPullHandler
|
5
|
-
attr_reader :received
|
6
|
-
def initialize
|
7
|
-
@received = []
|
8
|
-
end
|
9
|
-
def on_readable(socket, messages)
|
10
|
-
@received += messages
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
4
|
it "Should instantiate a connection given valid opts" do
|
15
5
|
pull_conn = nil
|
16
6
|
run_reactor do
|
17
|
-
pull_conn = SPEC_CTX.socket(ZMQ::PULL
|
7
|
+
pull_conn = SPEC_CTX.socket(ZMQ::PULL)
|
18
8
|
pull_conn.bind(rand_addr)
|
19
9
|
end
|
20
10
|
pull_conn.should be_a(EventMachine::ZeroMQ::Socket)
|
@@ -22,26 +12,26 @@ describe EventMachine::ZeroMQ do
|
|
22
12
|
|
23
13
|
describe "sending/receiving a single message via PUB/SUB" do
|
24
14
|
before(:all) do
|
25
|
-
results = {}
|
15
|
+
@results = {}
|
16
|
+
@received = []
|
26
17
|
@test_message = test_message = "TMsg#{rand(999)}"
|
27
18
|
|
28
|
-
run_reactor(0.
|
29
|
-
|
19
|
+
run_reactor(0.2) do
|
30
20
|
address = rand_addr
|
31
21
|
|
32
|
-
|
33
|
-
pull_conn = SPEC_CTX.socket(ZMQ::PULL, pull_hndlr)
|
22
|
+
pull_conn = SPEC_CTX.socket(ZMQ::PULL)
|
34
23
|
pull_conn.bind(address)
|
24
|
+
pull_conn.on(:message) { |m|
|
25
|
+
@received << m
|
26
|
+
}
|
35
27
|
|
36
28
|
push_conn = SPEC_CTX.socket(ZMQ::PUSH)
|
37
29
|
push_conn.connect(address)
|
38
30
|
|
39
31
|
push_conn.socket.send_string test_message, ZMQ::NOBLOCK
|
40
32
|
|
41
|
-
EM::Timer.new(0.1) { results[:specs_ran] = true }
|
33
|
+
EM::Timer.new(0.1) { @results[:specs_ran] = true }
|
42
34
|
end
|
43
|
-
|
44
|
-
@results = results
|
45
35
|
end
|
46
36
|
|
47
37
|
it "should run completely" do
|
@@ -49,9 +39,9 @@ describe EventMachine::ZeroMQ do
|
|
49
39
|
end
|
50
40
|
|
51
41
|
it "should receive the message intact" do
|
52
|
-
@
|
53
|
-
@
|
54
|
-
@
|
42
|
+
@received.should_not be_empty
|
43
|
+
@received.first.should be_a(ZMQ::Message)
|
44
|
+
@received.first.copy_out_string.should == @test_message
|
55
45
|
end
|
56
46
|
end
|
57
47
|
end
|
data/spec/router_dealer_spec.rb
CHANGED
@@ -1,39 +1,10 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), %w[spec_helper])
|
2
2
|
|
3
3
|
describe EventMachine::ZeroMQ do
|
4
|
-
class EMTestRouterHandler
|
5
|
-
attr_reader :received
|
6
|
-
def initialize
|
7
|
-
@received = []
|
8
|
-
end
|
9
|
-
def on_writable(socket)
|
10
|
-
end
|
11
|
-
def on_readable(socket, messages)
|
12
|
-
@received += messages
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
class EMTestDealerHandler
|
17
|
-
attr_reader :received
|
18
|
-
def initialize(&block)
|
19
|
-
@received = []
|
20
|
-
@on_writable_callback = block
|
21
|
-
end
|
22
|
-
def on_writable(socket)
|
23
|
-
@on_writable_callback.call(socket) if @on_writable_callback
|
24
|
-
end
|
25
|
-
def on_readable(socket, messages)
|
26
|
-
_, message = messages.map(&:copy_out_string)
|
27
|
-
@received += [message].map {|s| ZMQ::Message.new(s)}
|
28
|
-
|
29
|
-
socket.send_msg('', "re:#{message}")
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
4
|
it "Should instantiate a connection given valid opts for Router/Dealer" do
|
34
5
|
router_conn = nil
|
35
|
-
run_reactor
|
36
|
-
router_conn = SPEC_CTX.socket(ZMQ::ROUTER
|
6
|
+
run_reactor do
|
7
|
+
router_conn = SPEC_CTX.socket(ZMQ::ROUTER)
|
37
8
|
router_conn.bind(rand_addr)
|
38
9
|
end
|
39
10
|
router_conn.should be_a(EventMachine::ZeroMQ::Socket)
|
@@ -41,32 +12,38 @@ describe EventMachine::ZeroMQ do
|
|
41
12
|
|
42
13
|
describe "sending/receiving a single message via Router/Dealer" do
|
43
14
|
before(:all) do
|
44
|
-
results = {}
|
15
|
+
@results = {}
|
16
|
+
@dealer_received, @router_received = [], []
|
45
17
|
@test_message = test_message = "M#{rand(999)}"
|
46
18
|
|
47
|
-
run_reactor(
|
48
|
-
results[:dealer_hndlr] = dealer_hndlr = EMTestDealerHandler.new
|
49
|
-
results[:router_hndlr] = router_hndlr = EMTestRouterHandler.new
|
50
|
-
|
19
|
+
run_reactor(0.3) do
|
51
20
|
addr = rand_addr
|
52
|
-
dealer_conn = SPEC_CTX.socket(ZMQ::DEALER
|
21
|
+
dealer_conn = SPEC_CTX.socket(ZMQ::DEALER)
|
53
22
|
dealer_conn.identity = "dealer1"
|
54
23
|
dealer_conn.bind(addr)
|
24
|
+
dealer_conn.on(:message) { |message|
|
25
|
+
# 2. Dealer receives messages, sends reply back to router
|
26
|
+
@dealer_received << message
|
27
|
+
dealer_conn.send_msg("re:#{message.copy_out_string}")
|
28
|
+
}
|
55
29
|
|
56
|
-
router_conn = SPEC_CTX.socket(ZMQ::ROUTER
|
30
|
+
router_conn = SPEC_CTX.socket(ZMQ::ROUTER)
|
57
31
|
router_conn.identity = "router1"
|
58
32
|
router_conn.connect(addr)
|
33
|
+
router_conn.on(:message) { |*parts|
|
34
|
+
# 3. Message received in router identifies the sending dealer
|
35
|
+
@router_received << parts
|
36
|
+
}
|
59
37
|
|
60
38
|
EM::add_timer(0.1) do
|
61
|
-
|
39
|
+
# 1. Send message to the dealer
|
40
|
+
router_conn.send_msg('dealer1', test_message)
|
62
41
|
end
|
63
42
|
|
64
43
|
EM::Timer.new(0.2) do
|
65
|
-
results[:specs_ran] = true
|
44
|
+
@results[:specs_ran] = true
|
66
45
|
end
|
67
46
|
end
|
68
|
-
|
69
|
-
@results = results
|
70
47
|
end
|
71
48
|
|
72
49
|
it "should run completely" do
|
@@ -74,15 +51,16 @@ describe EventMachine::ZeroMQ do
|
|
74
51
|
end
|
75
52
|
|
76
53
|
it "should receive the message intact on the dealer" do
|
77
|
-
@
|
78
|
-
@
|
79
|
-
@
|
54
|
+
@dealer_received.should_not be_empty
|
55
|
+
@dealer_received.last.should be_a(ZMQ::Message)
|
56
|
+
@dealer_received.last.copy_out_string.should == @test_message
|
80
57
|
end
|
81
58
|
|
82
|
-
it "the router should be echoed its original message" do
|
83
|
-
@
|
84
|
-
@
|
85
|
-
|
59
|
+
it "the router should be echoed its original message with the dealer identity" do
|
60
|
+
@router_received.size.should == 1
|
61
|
+
parts = @router_received[0]
|
62
|
+
parts[0].copy_out_string.should == "dealer1"
|
63
|
+
parts[1].copy_out_string.should == "re:#{@test_message}"
|
86
64
|
end
|
87
65
|
end
|
88
66
|
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: em-zeromq
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,24 +10,24 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-
|
13
|
+
date: 2012-11-15 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: eventmachine
|
17
17
|
requirement: !ruby/object:Gem::Requirement
|
18
18
|
none: false
|
19
19
|
requirements:
|
20
|
-
- - '
|
20
|
+
- - ! '>='
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: 1.0.0
|
22
|
+
version: 1.0.0
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
none: false
|
27
27
|
requirements:
|
28
|
-
- - '
|
28
|
+
- - ! '>='
|
29
29
|
- !ruby/object:Gem::Version
|
30
|
-
version: 1.0.0
|
30
|
+
version: 1.0.0
|
31
31
|
- !ruby/object:Gem::Dependency
|
32
32
|
name: ffi
|
33
33
|
requirement: !ruby/object:Gem::Requirement
|
@@ -122,9 +122,13 @@ files:
|
|
122
122
|
- README.md
|
123
123
|
- Rakefile
|
124
124
|
- em-zeromq.gemspec
|
125
|
+
- example/multi-part.rb
|
125
126
|
- example/simple.rb
|
127
|
+
- example/simpler.rb
|
128
|
+
- example/terminating.rb
|
126
129
|
- lib/em-zeromq.rb
|
127
130
|
- lib/em-zeromq/context.rb
|
131
|
+
- lib/em-zeromq/event_emitter.rb
|
128
132
|
- lib/em-zeromq/socket.rb
|
129
133
|
- lib/em-zeromq/version.rb
|
130
134
|
- spec/context_spec.rb
|
@@ -148,7 +152,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
148
152
|
version: '0'
|
149
153
|
segments:
|
150
154
|
- 0
|
151
|
-
hash:
|
155
|
+
hash: 4479496977537005722
|
152
156
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
153
157
|
none: false
|
154
158
|
requirements:
|
@@ -157,7 +161,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
157
161
|
version: '0'
|
158
162
|
segments:
|
159
163
|
- 0
|
160
|
-
hash:
|
164
|
+
hash: 4479496977537005722
|
161
165
|
requirements: []
|
162
166
|
rubyforge_project: em-zeromq
|
163
167
|
rubygems_version: 1.8.24
|