em-zeromq 0.3.1 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|