em-zmq-tp10 0.1.7
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +237 -0
- data/Rakefile +9 -0
- data/em-zmq-tp10.gemspec +23 -0
- data/lib/em-zmq-tp10.rb +1 -0
- data/lib/em/protocols/zmq2.rb +25 -0
- data/lib/em/protocols/zmq2/connection.rb +37 -0
- data/lib/em/protocols/zmq2/dealer.rb +133 -0
- data/lib/em/protocols/zmq2/inproc.rb +147 -0
- data/lib/em/protocols/zmq2/pub_sub.rb +102 -0
- data/lib/em/protocols/zmq2/queue_per_peer.rb +57 -0
- data/lib/em/protocols/zmq2/rep.rb +64 -0
- data/lib/em/protocols/zmq2/req.rb +325 -0
- data/lib/em/protocols/zmq2/router.rb +69 -0
- data/lib/em/protocols/zmq2/socket.rb +236 -0
- data/lib/em/protocols/zmq2/socket_connection.rb +151 -0
- data/lib/em/protocols/zmq2/version.rb +7 -0
- data/lib/em/protocols/zmq_tp10.rb +2 -0
- data/tests/helper.rb +102 -0
- data/tests/run_all.rb +3 -0
- data/tests/test_dealer.rb +237 -0
- data/tests/test_inproc.rb +113 -0
- data/tests/test_pub_sub.rb +271 -0
- data/tests/test_reconnect.rb +64 -0
- data/tests/test_rep.rb +117 -0
- data/tests/test_req.rb +229 -0
- data/tests/test_router.rb +221 -0
- metadata +108 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Sokolov Yura 'funny-falcon'
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,237 @@
|
|
1
|
+
# EventMachine ZMTP1.0 protocol (ZMQ2.x protocol)
|
2
|
+
|
3
|
+
It is implementation of ZMTP 1.0 - ZMQ 2.x transport protocol using facilites provided by EventMachine.
|
4
|
+
There are implementations of ZMQ socket types which try to be similar to original, but not too hard. Moreover, you may create your own behaviour.
|
5
|
+
Library is tested against native ZMQ using ffi-rzmq.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
gem 'em-zmq-tp10'
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install em-zmq-tp10
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
Library provides callback oriented classes which tries to emulate behaviour of standard ZMQ classes, but already integrated with EventMachine eventloop.
|
24
|
+
|
25
|
+
Main difference in behaviour is in highwatermark handling and balancing:
|
26
|
+
For DEALER and REQ zmq provides roundrobin load balancing until HighWaterMark reached, then send operation blocks or returns error `EAGAIN`.
|
27
|
+
This implementation do roundrobin until fixed internal highwatermark (2048bytes) reached, and then pushes to common queue until userdefined watermark is reached.
|
28
|
+
|
29
|
+
This internal per connect buffer is handled by EventMachine itself, and there is no precise control over it, so that, if peer is disconnected, all pushed messages to this buffer are lost. So that, compared to raw ZMQ, you loose not only content of OS's internal socket buffer, but EventMachine buffer as well :(
|
30
|
+
|
31
|
+
But since ZMQ is never pretended on durability, it is not big issue (for me).
|
32
|
+
|
33
|
+
There is two strategy of highwatermark handling: `drop_first` and `drop_last`.
|
34
|
+
`drop_last` - is ignoring any try to send message if queue is full - this is default strategy for ZMQ if you use nonblocking sending.
|
35
|
+
`drop_first` - dropping earliest message in a queue, so that newly inserted message will have more chanches to be sent. You can react on such dropping by overriding `cancel_message` (or `cancel_request` for Req). I like this strategy more cause old request tends to be less usefull, but `drop_last` is still default for "compatibility".
|
36
|
+
|
37
|
+
There is also simplified classes without internal queue (`PreDealer`, `PreReq`, `PreRouter`, `PreRep`, `PrePub`), so that you can implement your own strategy of queueing.
|
38
|
+
|
39
|
+
And you could do any crazy thing using base `EM::Protocols::Zmq2::Socket` class
|
40
|
+
|
41
|
+
|
42
|
+
### Socket
|
43
|
+
|
44
|
+
Base class. It provides #connect and #bind methods for establishing endpoints.
|
45
|
+
This method could be called outside EM event loop (even before EM.run called), cause they use EM.schedule.
|
46
|
+
TCP and IPC endpoints are supported and fully interoperable with native ZMQ.
|
47
|
+
INPROC supported as well, but you should treat them as connections inside EventMachine's context, so that you could not connect to native ZMQ inproc endpoints.
|
48
|
+
|
49
|
+
### Dealer
|
50
|
+
|
51
|
+
class MyPreDealer < EM::Protocols::Zmq2::PreDealer
|
52
|
+
def receive_message(message)
|
53
|
+
puts "Message received: #{message.inspect}"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
dealer = MyPreDealer.new
|
57
|
+
dealer.connect('tcp://127.0.0.1:8000')
|
58
|
+
dealer.bind('unix://dealer.sock')
|
59
|
+
EM.schedule {
|
60
|
+
if !dealer.send_message(['asdf','fdas'])
|
61
|
+
puts "Could not send message (no free peers)"
|
62
|
+
end
|
63
|
+
}
|
64
|
+
|
65
|
+
class MyDealer < EM::Protocols::Zmq2::Dealer
|
66
|
+
def receive_message(message)
|
67
|
+
puts "Message received: #{message.inspect}"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
dealer = MyDealer.new(hwm: 1000, hwm_strategy: :drop_last)
|
71
|
+
dealer.connect('tcp://127.0.0.1:8000')
|
72
|
+
EM.schedule {
|
73
|
+
if !dealer.send_message(['asdf','fdas'])
|
74
|
+
puts "No free peers and outgoing queue is full"
|
75
|
+
end
|
76
|
+
}
|
77
|
+
|
78
|
+
dealer = EM::Protocols::Zmq2::DealerCb.new do |message|
|
79
|
+
puts "Receive message #{message.inspect}"
|
80
|
+
end
|
81
|
+
dealer.connect('ipc://rep')
|
82
|
+
EM.schedule {
|
83
|
+
dealer.send_message(['hello','world'])
|
84
|
+
}
|
85
|
+
|
86
|
+
### Req
|
87
|
+
|
88
|
+
class MyPreReq < EM::Protocols::Zmq2::PreReq
|
89
|
+
def receive_reply(message, data, request_id)
|
90
|
+
puts "Received message #{message} and stored data #{data}
|
91
|
+
end
|
92
|
+
end
|
93
|
+
req = MyPreReq.new
|
94
|
+
req.bind(...)
|
95
|
+
req.connect(...)
|
96
|
+
if request_id = req.send_request(['this is', 'message'], 'saved_data')
|
97
|
+
puts "Message sent"
|
98
|
+
else
|
99
|
+
puts "there is no free peer"
|
100
|
+
end
|
101
|
+
|
102
|
+
class MyReq < EM::Protocols::Zmq2::PreReq
|
103
|
+
def receive_reply(message, data, request_id)
|
104
|
+
puts "Received message #{message} and stored data #{data}
|
105
|
+
end
|
106
|
+
end
|
107
|
+
req = MyReq.new
|
108
|
+
req.bind(...)
|
109
|
+
req.connect(...)
|
110
|
+
if request_id = req.send_request(['hi'], 'ho')
|
111
|
+
puts "Message sent"
|
112
|
+
end
|
113
|
+
|
114
|
+
req = EM::Protocols::Zmq2::ReqCb.new
|
115
|
+
req.bind('ipc://req')
|
116
|
+
timer = nil
|
117
|
+
request_id = req.send_request(['hello', 'world']) do |message|
|
118
|
+
EM.cancel_timer(timer)
|
119
|
+
puts "Message #{message}"
|
120
|
+
end
|
121
|
+
if request_id
|
122
|
+
timer = EM.add_timer(1) {
|
123
|
+
req.cancel_request(request_id)
|
124
|
+
}
|
125
|
+
end
|
126
|
+
|
127
|
+
req = EM::Protocols::Zmq2::ReqDefer.new
|
128
|
+
req.bind('ipc://req')
|
129
|
+
data = {hi: 'ho'}
|
130
|
+
deferable = req.send_request(['hello', 'world'], data) do |reply, data|
|
131
|
+
puts "Reply received #{reply} #{data}"
|
132
|
+
end
|
133
|
+
deferable.timeout 1
|
134
|
+
deferable.errback do
|
135
|
+
puts "Message canceled"
|
136
|
+
end
|
137
|
+
deferable.callback do |reply, data|
|
138
|
+
puts "Another callback #{reply} #{data}"
|
139
|
+
end
|
140
|
+
|
141
|
+
### Router
|
142
|
+
|
143
|
+
Router stores peer identity in a message, as ZMQ router do.
|
144
|
+
And it sends message to a peer, which idenitity equals to first message string.
|
145
|
+
`PreRouter` does no any queue caching, `Router` saves message in queue per peer, controlled by highwatermark strategy.
|
146
|
+
|
147
|
+
class MyPreRouter < EM::Protocols::Zmq2::PreRouter
|
148
|
+
def receive_message(message)
|
149
|
+
puts "Received message #{message} (and it contains envelope)"
|
150
|
+
end
|
151
|
+
end
|
152
|
+
router = MyPreRouter.new
|
153
|
+
router.bind(...)
|
154
|
+
router.send_message(message)
|
155
|
+
|
156
|
+
class MyRouter < EM::Protocols::Zmq2::Router
|
157
|
+
def receive_message(message)
|
158
|
+
puts "Received message #{message}"
|
159
|
+
message[-1] = 'reply'
|
160
|
+
send_message(message)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
router = MyPreRouter.new(hwm: 1000, hwm_strategy: :drop_first)
|
164
|
+
router.bind(...)
|
165
|
+
router.send_message(message)
|
166
|
+
|
167
|
+
### Rep
|
168
|
+
|
169
|
+
REP differs from Router mainly in methods signature.
|
170
|
+
|
171
|
+
class EchoBangPreRep < EM::Protocols::Zmq2::PreRep
|
172
|
+
def receive_request(message, envelope)
|
173
|
+
message << "!"
|
174
|
+
if send_reply(message, envelope)
|
175
|
+
puts "reply sent successfuly"
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
rep = EchoBangPreRep.new
|
180
|
+
rep.bind('ipc://rep')
|
181
|
+
|
182
|
+
class EchoBangRep < EM::Protocols::Zmq2::Rep
|
183
|
+
def receive_request(message, envelope)
|
184
|
+
message << "!"
|
185
|
+
if send_reply(message, envelope)
|
186
|
+
puts "reply sent successfuly"
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
rep = EchoBangRep.new
|
191
|
+
rep.bind('ipc://rep')
|
192
|
+
|
193
|
+
### Sub
|
194
|
+
|
195
|
+
Unless ZMQ sub, this `Sub` accepts not only strings, but also RegExps and procs for subscribing.
|
196
|
+
Note that as in ZMQ 2.x filtering occurs on Sub side.
|
197
|
+
|
198
|
+
Since subscriptions could be defined with callback passed to `:subscribe` option, `subscribe` or `subscribe_many` methods, you could use this class without overloading.
|
199
|
+
|
200
|
+
class MySub < EM::Protocols::Zmq2::Sub
|
201
|
+
def receive_message(message)
|
202
|
+
puts "default handler"
|
203
|
+
end
|
204
|
+
end
|
205
|
+
sub = MySub.new(subscribe: ['this', 'that'])
|
206
|
+
sub.subscribe /^callback/i, do |message|
|
207
|
+
puts "Callback subscribe #{message}"
|
208
|
+
end
|
209
|
+
sub.subscribe_many(
|
210
|
+
proc{|s| s.end_with?("END")} => proc{|message| puts "TILL END #{message}"},
|
211
|
+
'' => nil # also to default
|
212
|
+
)
|
213
|
+
|
214
|
+
### Pub
|
215
|
+
|
216
|
+
`PrePub` sends messages only to connected and not busy peers. `send_message` returns true, if there is at least one peer with short EventMachine's outgoing queue, to which message is scheduled.
|
217
|
+
|
218
|
+
`Pub` tries to queue messages for all connected and for disconnected peers with explicit identity set.
|
219
|
+
|
220
|
+
Since there is no incoming data, there is no need to overload methods.
|
221
|
+
|
222
|
+
pub = EM::Protocols::Zmq2::PrePub.new
|
223
|
+
pub.bind(...)
|
224
|
+
pub.send_message(['hi', 'you'])
|
225
|
+
|
226
|
+
pub = EM::Protocols::Zmq2::Pub.new
|
227
|
+
pub.bind(...)
|
228
|
+
pub.send_message(['hi', 'you'])
|
229
|
+
|
230
|
+
|
231
|
+
## Contributing
|
232
|
+
|
233
|
+
1. Fork it
|
234
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
235
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
236
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
237
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/em-zmq-tp10.gemspec
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/em/protocols/zmq2/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Sokolov Yura 'funny-falcon'"]
|
6
|
+
gem.email = ["funny.falcon@gmail.com"]
|
7
|
+
gem.description = %q{Implementation of ZMQ2.x transport protocol - ZMTP1.0}
|
8
|
+
gem.summary = %q{
|
9
|
+
Implementation of ZMQ2.1 transport protocol and main socket types using EventMachine
|
10
|
+
for managing TCP/UNIX connections, doing nonblocking writes and calling callback on
|
11
|
+
incoming messages.}
|
12
|
+
gem.homepage = "https://github.com/funny-falcon/em-zmq-tp10"
|
13
|
+
|
14
|
+
gem.files = `git ls-files`.split($\)
|
15
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
16
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
17
|
+
gem.name = "em-zmq-tp10"
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
gem.version = EventMachine::Protocols::Zmq2::VERSION
|
20
|
+
gem.add_runtime_dependency 'eventmachine'
|
21
|
+
gem.add_development_dependency 'ffi-rzmq'
|
22
|
+
gem.required_ruby_version = '>= 1.9.2'
|
23
|
+
end
|
data/lib/em-zmq-tp10.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "em/protocols/zmq2"
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module EventMachine
|
2
|
+
module Protocols
|
3
|
+
module Zmq2
|
4
|
+
EMPTY = ''.freeze
|
5
|
+
SMALL_TIMEOUT = 0.03
|
6
|
+
HWM_INFINITY = 2**20
|
7
|
+
autoload :PreDealer, 'em/protocols/zmq2/dealer.rb'
|
8
|
+
autoload :Dealer, 'em/protocols/zmq2/dealer.rb'
|
9
|
+
autoload :DealerCb, 'em/protocols/zmq2/dealer.rb'
|
10
|
+
autoload :PreReq, 'em/protocols/zmq2/req.rb'
|
11
|
+
autoload :Req, 'em/protocols/zmq2/req.rb'
|
12
|
+
autoload :ReqCb, 'em/protocols/zmq2/req.rb'
|
13
|
+
autoload :ReqDefer, 'em/protocols/zmq2/req.rb'
|
14
|
+
autoload :PreRouter, 'em/protocols/zmq2/router.rb'
|
15
|
+
autoload :Router, 'em/protocols/zmq2/router.rb'
|
16
|
+
autoload :PreRep, 'em/protocols/zmq2/rep.rb'
|
17
|
+
autoload :Rep, 'em/protocols/zmq2/rep.rb'
|
18
|
+
autoload :Sub, 'em/protocols/zmq2/pub_sub.rb'
|
19
|
+
autoload :PrePub, 'em/protocols/zmq2/pub_sub.rb'
|
20
|
+
autoload :Pub, 'em/protocols/zmq2/pub_sub.rb'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
require 'em/protocols/zmq2/socket_connection'
|
25
|
+
require 'em/protocols/zmq2/socket'
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module EventMachine
|
2
|
+
module Protocols
|
3
|
+
module Zmq2
|
4
|
+
module ConnectionMixin
|
5
|
+
def sent_data
|
6
|
+
@socket.peer_free(@peer_identity, self) if not_too_busy?
|
7
|
+
end
|
8
|
+
|
9
|
+
def not_too_busy?
|
10
|
+
free = _not_too_busy?
|
11
|
+
self.notify_when_free = !free
|
12
|
+
free
|
13
|
+
end
|
14
|
+
|
15
|
+
def post_init
|
16
|
+
send_strings @socket.identity
|
17
|
+
end
|
18
|
+
|
19
|
+
def receive_strings(message)
|
20
|
+
unless @peer_identity
|
21
|
+
peer_identity = message.first
|
22
|
+
@peer_identity = @socket.register_peer(peer_identity, self)
|
23
|
+
else
|
24
|
+
@socket.receive_message_and_peer message, @peer_identity
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def unbind
|
29
|
+
if @peer_identity
|
30
|
+
@socket.unregister_peer(@peer_identity)
|
31
|
+
end
|
32
|
+
@socket.not_connected(self)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,133 @@
|
|
1
|
+
require 'em/protocols/zmq2/socket'
|
2
|
+
module EventMachine
|
3
|
+
module Protocols
|
4
|
+
module Zmq2
|
5
|
+
# ZMQ socket which acts like a Dealer, but without any message queueing
|
6
|
+
# (except for EventMachine write buffers). So that, it is up to you
|
7
|
+
# to react when message could not be send
|
8
|
+
#
|
9
|
+
# @example
|
10
|
+
# class MyDealer < EM::Protocols::Zmq2::PreDealer
|
11
|
+
# def receive_message(message)
|
12
|
+
# puts "Message received: #{message.inspect}"
|
13
|
+
# end
|
14
|
+
# end
|
15
|
+
# dealer = MyDealer.new
|
16
|
+
# dealer.connect('tcp://127.0.0.1:8000')
|
17
|
+
# if !dealer.send_message(['asdf','fdas'])
|
18
|
+
# puts "Could not send message (no free peers)"
|
19
|
+
# end
|
20
|
+
class PreDealer < Socket
|
21
|
+
# @private
|
22
|
+
def choose_peer(even_if_busy = false)
|
23
|
+
peers = even_if_busy ? @peers : @free_peers
|
24
|
+
i = peers.size
|
25
|
+
while i > 0
|
26
|
+
ident, connect = peers.shift
|
27
|
+
if even_if_busy || connect.not_too_busy?
|
28
|
+
peers[ident] = connect # use the fact, that hash is ordered in Ruby 1.9
|
29
|
+
return connect unless connect.error?
|
30
|
+
end
|
31
|
+
i -= 1
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# overrides default callback to call +#receive_message+
|
36
|
+
def receive_message_and_peer(message, peer_identity) # :nodoc:
|
37
|
+
receive_message(message)
|
38
|
+
end
|
39
|
+
|
40
|
+
# override to have desired reaction on message
|
41
|
+
def receive_message(message)
|
42
|
+
raise NoMethodError
|
43
|
+
end
|
44
|
+
|
45
|
+
# tries to send message.
|
46
|
+
# @param [Array] message - message to be sent (Array of Strings or String)
|
47
|
+
# @param [Boolean] even_if_busy - ignore busyness of connections
|
48
|
+
# @return [Boolean] whether message were sent
|
49
|
+
def send_message(message, even_if_busy = false)
|
50
|
+
if connect = choose_peer(even_if_busy)
|
51
|
+
connect.send_strings(message)
|
52
|
+
true
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# ZMQ socket which tries to be a lot like a Dealer. It stores messages into outgoing
|
58
|
+
# queue, it tries to balance on socket busyness (which is slightely more, than ZMQ do).
|
59
|
+
# The only visible change from PreDealer is less frequent +send_message+ false return.
|
60
|
+
#
|
61
|
+
# @example
|
62
|
+
# class MyDealer < EM::Protocols::Zmq2::Dealer
|
63
|
+
# def receive_message(message)
|
64
|
+
# puts "Message received: #{message.inspect}"
|
65
|
+
# end
|
66
|
+
# end
|
67
|
+
# dealer = MyDealer.new
|
68
|
+
# dealer.connect('tcp://127.0.0.1:8000')
|
69
|
+
# if !dealer.send_message(['asdf','fdas'])
|
70
|
+
# puts "No free peers and outgoing queue is full"
|
71
|
+
# end
|
72
|
+
class Dealer < PreDealer
|
73
|
+
# :stopdoc:
|
74
|
+
def initialize(opts = {})
|
75
|
+
super
|
76
|
+
@write_queue = []
|
77
|
+
end
|
78
|
+
|
79
|
+
alias raw_send_message send_message
|
80
|
+
def flush_queue(even_if_busy = false)
|
81
|
+
until @write_queue.empty?
|
82
|
+
return false unless raw_send_message(@write_queue.first, even_if_busy)
|
83
|
+
@write_queue.shift
|
84
|
+
end
|
85
|
+
true
|
86
|
+
end
|
87
|
+
|
88
|
+
def send_message(message)
|
89
|
+
flush_queue && super(message) || push_to_queue(@write_queue, message)
|
90
|
+
end
|
91
|
+
|
92
|
+
def peer_free(peer_identity, connection)
|
93
|
+
super
|
94
|
+
flush_queue
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
def flush_all_queue
|
99
|
+
flush_queue(true)
|
100
|
+
end
|
101
|
+
|
102
|
+
def react_on_hwm_decrease
|
103
|
+
push_to_queue(@write_queue)
|
104
|
+
end
|
105
|
+
# :startdoc:
|
106
|
+
end
|
107
|
+
|
108
|
+
# Convinient Dealer class which accepts callback in constructor, which will be called
|
109
|
+
# on every incoming message (instead of #receive_message)
|
110
|
+
#
|
111
|
+
# @example
|
112
|
+
# dealer = EM::Protocols::Zmq2::DealerCb.new do |message|
|
113
|
+
# puts "Receive message #{message.inspect}"
|
114
|
+
# end
|
115
|
+
# dealer.connect('ipc://rep')
|
116
|
+
# dealer.send_message(['hello','world'])
|
117
|
+
class DealerCb < Dealer
|
118
|
+
# Accepts callback as second parameter or block
|
119
|
+
# :callsec:
|
120
|
+
# new(opts) do |message| end
|
121
|
+
# new(opts, proc{|message| })
|
122
|
+
def initialize(opts = {}, cb = nil, &block)
|
123
|
+
super opts
|
124
|
+
@read_callback = cb || block
|
125
|
+
end
|
126
|
+
|
127
|
+
def receive_message(message) # :nodoc:
|
128
|
+
@read_callback.call message
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|