zmqmachine 0.6.0 → 0.7.1

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 (44) hide show
  1. data/.gitignore +15 -0
  2. data/AUTHORS.txt +3 -0
  3. data/History.txt +19 -0
  4. data/examples/fake_ftp.rb +9 -1
  5. data/examples/one_handed_ping_pong.rb +2 -1
  6. data/examples/ping_pong.rb +2 -2
  7. data/examples/pub_sub.rb +10 -4
  8. data/examples/pubsub_forwarder.rb +8 -3
  9. data/examples/throttled_ping_pong.rb +2 -2
  10. data/lib/zm/configuration.rb +129 -0
  11. data/lib/zm/device.rb +4 -0
  12. data/lib/zm/device/configuration.rb +24 -0
  13. data/lib/zm/{devices → device}/forwarder.rb +48 -46
  14. data/lib/zm/{devices → device}/queue.rb +63 -44
  15. data/lib/zm/log_client.rb +2 -2
  16. data/lib/zm/log_server.rb +68 -0
  17. data/lib/zm/reactor.rb +42 -29
  18. data/lib/zm/server.rb +4 -0
  19. data/lib/zm/server/base.rb +139 -0
  20. data/lib/zm/server/configuration.rb +53 -0
  21. data/lib/zm/server/pair.rb +23 -0
  22. data/lib/zm/server/pub.rb +23 -0
  23. data/lib/zm/server/pull.rb +24 -0
  24. data/lib/zm/server/push.rb +23 -0
  25. data/lib/zm/server/rep.rb +42 -0
  26. data/lib/zm/server/req.rb +41 -0
  27. data/lib/zm/server/routing_envelope.rb +26 -0
  28. data/lib/zm/server/sub.rb +40 -0
  29. data/lib/zm/sockets.rb +1 -1
  30. data/lib/zm/sockets/base.rb +3 -12
  31. data/lib/zm/sockets/envelope_help.rb +49 -0
  32. data/lib/zm/sockets/pair.rb +0 -1
  33. data/lib/zm/sockets/pub.rb +0 -1
  34. data/lib/zm/sockets/rep.rb +45 -0
  35. data/lib/zm/sockets/req.rb +46 -1
  36. data/lib/zm/sockets/sub.rb +0 -1
  37. data/lib/zm/timers.rb +26 -13
  38. data/lib/zmqmachine.rb +1 -1
  39. data/version.txt +1 -1
  40. data/zmqmachine.gemspec +6 -6
  41. metadata +90 -91
  42. data/lib/zm/devices.rb +0 -4
  43. data/lib/zm/sockets/xrep.rb +0 -86
  44. data/lib/zm/sockets/xreq.rb +0 -86
@@ -35,7 +35,6 @@
35
35
  #
36
36
 
37
37
  module ZMQMachine
38
-
39
38
  module Device
40
39
 
41
40
 
@@ -53,102 +52,122 @@ module ZMQMachine
53
52
  #
54
53
  # # the queue creates sockets and binds to both given addresses; all messages get
55
54
  # # routed between the two
56
- # queue = ZM::Device::Queue.new reactor, "tcp://192.168.0.100:5050", "tcp://192.168.0.100:5051"
55
+ # config = ZM::Device::Configuration.new
56
+ # config.reactor = reactor
57
+ # config.incoming_endpoint = "tcp://192.168.0.100:5050"
58
+ # config.outgoing_endpoint = "tcp://192.168.0.100:5051"
59
+ # config.verbose = false
60
+ # config.linger = 10 # ms
61
+ # config.hwm = 0
62
+ # queue = ZM::Device::Queue.new(config)
57
63
  #
58
64
  # # the +client_handler+ internally calls "connect" to the incoming address given above
59
- # client = reactor.req_socket client_handler
60
- # client2 = reactor.req_socket client_handler
65
+ # client = reactor.req_socket(client_handler)
66
+ # client2 = reactor.req_socket(client_handler)
61
67
  #
62
68
  # # the +server_handler+ internally calls "connect" to the outgoing address given above
63
- # server = reactor.rep_socket server_handler
69
+ # server = reactor.rep_socket(server_handler)
64
70
  #
65
71
  class Queue
66
72
 
67
- class Handler
73
+ class XReqHandler
68
74
  attr_accessor :socket_out
69
75
 
70
- def initialize reactor, address, dir, opts = {}
71
- @reactor = reactor
76
+ def initialize(config, address, direction)
77
+ @reactor = config.reactor
72
78
  @address = address
73
- @verbose = opts[:verbose] || false
74
- @opts = opts
75
- @dir = dir
79
+ @verbose = config.verbose
80
+ @config = config
81
+ @direction = direction
76
82
  end
77
83
 
78
- def on_attach socket
79
- set_options socket
80
- rc = socket.bind @address
84
+ def on_attach(socket)
85
+ set_options(socket)
86
+ rc = socket.bind(@address)
81
87
  error_check(rc)
82
- #FIXME: error handling!
83
88
  end
84
89
 
85
- def on_writable socket
86
- @reactor.deregister_writable socket
90
+ def on_writable(socket)
91
+ @reactor.deregister_writable(socket)
87
92
  end
88
93
 
89
- def on_readable socket, messages
90
- messages.each { |msg| @reactor.log(:device, "[Q#{@dir}] [#{msg.copy_out_string}]") } if @verbose
94
+ def on_readable(socket, messages, envelope)
95
+ all = (envelope + messages)
96
+ all.each { |msg| @reactor.log(:device, "[Q#{@direction}] [#{msg.copy_out_string}]") } if @verbose
91
97
 
92
98
  if @socket_out
93
99
  # FIXME: need to be able to handle EAGAIN/failed send
94
- rc = socket_out.send_messages messages
95
- messages.each { |message| message.close }
100
+ rc = socket_out.send_messages(all)
101
+ all.each { |message| message.close }
96
102
  end
97
103
  end
98
104
 
99
- if LibZMQ.version2?
105
+ if ZMQ::LibZMQ.version2?
100
106
 
101
- def set_options socket
102
- error_check(socket.raw_socket.setsockopt(ZMQ::HWM, (@opts[:hwm] || 1)))
103
- error_check(socket.raw_socket.setsockopt(ZMQ::LINGER, (@opts[:linger] || 0)))
107
+ def set_options(socket)
108
+ error_check(socket.raw_socket.setsockopt(ZMQ::HWM, @config.hwm))
109
+ error_check(socket.raw_socket.setsockopt(ZMQ::LINGER, @config.linger))
104
110
  end
105
111
 
106
- elsif LibZMQ.version3?
112
+ elsif ZMQ::LibZMQ.version3?
107
113
 
108
- def set_options socket
109
- error_check(socket.raw_socket.setsockopt(ZMQ::SNDHWM, (@opts[:hwm] || 1)))
110
- error_check(socket.raw_socket.setsockopt(ZMQ::RCVHWM, (@opts[:hwm] || 1)))
111
- error_check(socket.raw_socket.setsockopt(ZMQ::LINGER, (@opts[:linger] || 0)))
114
+ def set_options(socket)
115
+ error_check(socket.raw_socket.setsockopt(ZMQ::SNDHWM, @config.hwm))
116
+ error_check(socket.raw_socket.setsockopt(ZMQ::RCVHWM, @config.hwm))
117
+ error_check(socket.raw_socket.setsockopt(ZMQ::LINGER, @config.linger))
112
118
  end
113
119
 
114
120
  end
115
121
 
116
- def error_check rc
122
+ def error_check(rc)
117
123
  if ZMQ::Util.resultcode_ok?(rc)
118
124
  false
119
125
  else
120
- STDERR.puts "Operation failed, errno [#{ZMQ::Util.errno}] description [#{ZMQ::Util.error_string}]"
121
- caller(1).each { |callstack| STDERR.puts(callstack) }
126
+ @reactor.log(:error, "Operation failed, errno [#{ZMQ::Util.errno}] description [#{ZMQ::Util.error_string}]")
127
+ caller(1).each { |callstack| @reactor.log(:callstack, callstack) }
122
128
  true
123
129
  end
124
130
  end
125
131
 
126
- end # class Handler
132
+ end # class XReqHandler
133
+
134
+ class XRepHandler < XReqHandler
135
+
136
+ def on_readable(socket, messages, envelope)
137
+ all = envelope + messages
138
+ all.each { |msg| @reactor.log(:device, "[Q#{@direction}] [#{msg.copy_out_string}]") } if @verbose
127
139
 
140
+ if @socket_out
141
+ # FIXME: need to be able to handle EAGAIN/failed send
142
+ rc = socket_out.send_messages(all)
143
+ all.each { |message| message.close }
144
+ end
145
+ end
146
+ end
128
147
 
129
148
  # Takes either a properly formatted string that can be converted into a ZM::Address
130
149
  # or takes a ZM::Address directly.
131
150
  #
132
151
  # Routes all messages received by either address to the other address.
133
152
  #
134
- def initialize reactor, incoming, outgoing, opts = {}
135
- incoming = Address.from_string incoming if incoming.kind_of? String
136
- outgoing = Address.from_string outgoing if outgoing.kind_of? String
153
+ def initialize(config)
154
+ @reactor = config.reactor
155
+ incoming = Address.from_string(config.incoming_endpoint.to_s)
156
+ outgoing = Address.from_string(config.outgoing_endpoint.to_s)
137
157
 
138
158
  # setup the handlers for processing messages
139
- @handler_in = Handler.new reactor, incoming, :in, opts
140
- @handler_out = Handler.new reactor, outgoing, :out, opts
159
+ @handler_in = XRepHandler.new(config, incoming, :in)
160
+ @handler_out = XReqHandler.new(config, outgoing, :out)
141
161
 
142
162
  # create each socket and pass in the appropriate handler
143
- @incoming = reactor.xrep_socket @handler_in
144
- @outgoing = reactor.xreq_socket @handler_out
163
+ @incoming_sock = @reactor.xrep_socket(@handler_in)
164
+ @outgoing_sock = @reactor.xreq_socket(@handler_out)
145
165
 
146
166
  # set each handler's outgoing socket
147
- @handler_in.socket_out = @outgoing
148
- @handler_out.socket_out = @incoming
167
+ @handler_in.socket_out = @outgoing_sock
168
+ @handler_out.socket_out = @incoming_sock
149
169
  end
150
170
  end # class Queue
151
171
 
152
172
  end # module Device
153
-
154
173
  end # module ZMQMachine
@@ -109,14 +109,14 @@ module ZMQMachine
109
109
  @reactor.deregister_writable socket
110
110
  end
111
111
 
112
- if LibZMQ.version2?
112
+ if ZMQ::LibZMQ.version2?
113
113
 
114
114
  def set_options socket
115
115
  socket.raw_socket.setsockopt ZMQ::HWM, 0
116
116
  socket.raw_socket.setsockopt ZMQ::LINGER, 0
117
117
  end
118
118
 
119
- elsif LibZMQ.version3?
119
+ elsif ZMQ::LibZMQ.version3?
120
120
 
121
121
  def set_options socket
122
122
  socket.raw_socket.setsockopt ZMQ::SNDHWM, 0
@@ -0,0 +1,68 @@
1
+ #--
2
+ #
3
+ # Author:: Chuck Remes
4
+ # Homepage:: http://github.com/chuckremes/zmqmachine
5
+ # Date:: 20111101
6
+ #
7
+ #----------------------------------------------------------------------------
8
+ #
9
+ # Copyright (C) 2011 by Chuck Remes. All Rights Reserved.
10
+ # Email: cremes at mac dot com
11
+ #
12
+ # (The MIT License)
13
+ #
14
+ # Permission is hereby granted, free of charge, to any person obtaining
15
+ # a copy of this software and associated documentation files (the
16
+ # 'Software'), to deal in the Software without restriction, including
17
+ # without limitation the rights to use, copy, modify, merge, publish,
18
+ # distribute, sublicense, and/or sell copies of the Software, and to
19
+ # permit persons to whom the Software is furnished to do so, subject to
20
+ # the following conditions:
21
+ #
22
+ # The above copyright notice and this permission notice shall be
23
+ # included in all copies or substantial portions of the Software.
24
+ #
25
+ # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
26
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
28
+ # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
29
+ # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
30
+ # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
31
+ # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32
+ #
33
+ #---------------------------------------------------------------------------
34
+ #
35
+ #
36
+
37
+ module ZMQMachine
38
+
39
+ class LogServer
40
+ include Server::SUB
41
+
42
+ def initialize(configuration)
43
+ configuration.on_read = method(:on_read)
44
+ super
45
+
46
+ @file = configuration.extra[:file] || STDOUT
47
+ end
48
+
49
+ # Writes all messages to the file.
50
+ #
51
+ def on_read socket, messages
52
+ string = ''
53
+ messages.each_with_index do |message, index|
54
+ string << '|' if index > 0
55
+ string << "#{message.copy_out_string}"
56
+ end
57
+
58
+ @file.print "#{string}\n"
59
+ @file.flush
60
+ end
61
+
62
+ def write messages
63
+ # no op
64
+ end
65
+
66
+ end # class LogServer
67
+
68
+ end
@@ -39,46 +39,58 @@ module ZMQMachine
39
39
  class Reactor
40
40
  attr_reader :name, :context, :logger, :exception_handler
41
41
 
42
+ # Takes a ZMQ::Configuration instance to initialize itself.
43
+ #
42
44
  # +name+ provides a name for this reactor instance. It's unused
43
45
  # at present but may be used in the future for allowing multiple
44
- # reactors to communicate amongst each other.
46
+ # reactors to communicate amongst each other. Defaults to 'unnamed'
47
+ # if it isn't set.
45
48
  #
46
49
  # +poll_interval+ is the number of milliseconds to block while
47
- # waiting for new 0mq socket events; default is 10
50
+ # waiting for new 0mq socket events; default is 10 ms.
48
51
  #
49
- # +opts+ may contain a key +:zeromq_context+. When this
50
- # hash is provided, the value for :zeromq_context should be a
52
+ # +context+ should be a
51
53
  # 0mq context as created by ZMQ::Context.new. The purpose of
52
54
  # providing a context to the reactor is so that multiple
53
55
  # reactors can share a single context. Doing so allows for sockets
54
56
  # within each reactor to communicate with each other via an
55
57
  # :inproc transport (:inproc is misnamed, it should be :incontext).
56
58
  # By not supplying this hash, the reactor will create and use
57
- # its own 0mq context.
59
+ # its own 0mq context. Default is nil.
58
60
  #
59
- # +opts+ may also include a +:log_transport+ key. This should be
61
+ # +log_endpoint+ is a
60
62
  # a transport string for an endpoint that a logger client may connect
61
63
  # to for publishing log messages. when this key is defined, the
62
64
  # client is automatically created and connected to the indicated
63
- # endpoint.
64
- #
65
- # Lastly, +opts+ may include a +exception_handler+ key. The exception
66
- # handler should respond to #call and take a single argument.
67
- #
68
- def initialize name, poll_interval = 10, opts = {}
69
- @name = name
65
+ # endpoint. Default is nil.
66
+ #
67
+ # +exception_handler+ is called for all exceptions. The
68
+ # handler should respond to #call and take a single argument. Default
69
+ # is to just raise the exception and exit.
70
+ #
71
+ # config = ZM::Configuration.new
72
+ # config.context = master_context
73
+ # config.log_endpoint = endpoint
74
+ # config.name = :test_rig
75
+ # config.poll_interval = 100 # defaults to 10 if unset
76
+ # Reactor.new(config).run do |reactor|
77
+ # reactor.oneshot_timer(50) { print("At least 50ms have elapsed\n")}
78
+ # end
79
+ #
80
+ def initialize configuration = nil
81
+ configuration ||= Configuration.new
82
+ @name = configuration.name || 'unnamed'
70
83
  @running = false
71
84
  @thread = nil
72
- @poll_interval = determine_interval poll_interval
73
- @timers = ZMQMachine::Timers.new
85
+ @poll_interval = determine_interval(configuration.poll_interval || 10)
74
86
 
75
87
  @proc_queue = []
76
88
  @proc_queue_mutex = Mutex.new
77
89
 
78
90
  # could raise if it fails to allocate a Context
79
- @context = if opts[:zeromq_context]
91
+ @context = if configuration.context
80
92
  @shared_context = true
81
- opts[:zeromq_context]
93
+ configuration.context
82
94
  else
83
95
  @shared_context = false
84
96
  ZMQ::Context.new
@@ -89,14 +101,13 @@ module ZMQMachine
89
101
  @raw_to_socket = {}
90
102
  Thread.abort_on_exception = true
91
103
 
92
- if opts[:log_transport]
93
- @logger = LogClient.new self, opts[:log_transport]
104
+ if configuration.log_endpoint
105
+ @logger = LogClient.new self, configuration.log_endpoint
94
106
  @logging_enabled = true
95
107
  end
96
108
 
97
- if opts[:exception_handler]
98
- @exception_handler = opts[:exception_handler]
99
- end
109
+ @exception_handler = configuration.exception_handler if configuration.exception_handler
110
+ @timers = ZMQMachine::Timers.new(@exception_handler)
100
111
  end
101
112
 
102
113
  def shared_context?
@@ -249,6 +260,7 @@ module ZMQMachine
249
260
  def xreq_socket handler_instance
250
261
  create_socket handler_instance, ZMQMachine::Socket::XReq
251
262
  end
263
+ alias :dealer_socket :xreq_socket
252
264
 
253
265
  # Creates a XREP socket and attaches +handler_instance+ to the
254
266
  # resulting socket. Should only be paired with one other
@@ -264,6 +276,7 @@ module ZMQMachine
264
276
  def xrep_socket handler_instance
265
277
  create_socket handler_instance, ZMQMachine::Socket::XRep
266
278
  end
279
+ alias :router_socket :xrep_socket
267
280
 
268
281
  # Creates a PAIR socket and attaches +handler_instance+ to the
269
282
  # resulting socket. Works only with other #pair_socket instances
@@ -437,16 +450,16 @@ module ZMQMachine
437
450
  end
438
451
 
439
452
  # Publishes log messages to an existing transport passed in to the Reactor
440
- # constructor using the :log_transport key.
453
+ # constructor using the :log_endpoint key.
441
454
  #
442
- # Reactor.new :log_transport => 'inproc://reactor_log'
455
+ # Reactor.new :log_endpoint => 'inproc://reactor_log'
443
456
  #
444
457
  # +level+ parameter refers to a key to indicate severity level, e.g. :warn,
445
458
  # :debug, level0, level9, etc.
446
459
  #
447
460
  # +message+ is a plain string that will be written out in its entirety.
448
461
  #
449
- # When no :log_transport was defined when creating the Reactor, all calls
462
+ # When no :log_endpoint was defined when creating the Reactor, all calls
450
463
  # just discard the messages.
451
464
  #
452
465
  # reactor.log(:info, "some message")
@@ -518,11 +531,11 @@ module ZMQMachine
518
531
  sleep(@poll_interval / 1000.0)
519
532
  else
520
533
  rc = @poller.poll @poll_interval
521
- end
522
534
 
523
- if ZMQ::Util.resultcode_ok?(rc)
524
- @poller.readables.each { |sock| @raw_to_socket[sock].resume_read }
525
- @poller.writables.each { |sock| @raw_to_socket[sock].resume_write }
535
+ if ZMQ::Util.resultcode_ok?(rc)
536
+ @poller.readables.each { |sock| @raw_to_socket[sock].resume_read }
537
+ @poller.writables.each { |sock| @raw_to_socket[sock].resume_write }
538
+ end
526
539
  end
527
540
 
528
541
  rc
@@ -0,0 +1,4 @@
1
+
2
+ %w( base routing_envelope req rep pair pub sub push pull configuration ).each do |rb_file|
3
+ require File.join(File.dirname(__FILE__), 'server', rb_file)
4
+ end
@@ -0,0 +1,139 @@
1
+
2
+ module ZMQMachine
3
+
4
+ module Server
5
+
6
+ module Base
7
+ def initialize configuration
8
+ @reactor = configuration.reactor
9
+ @configuration = configuration
10
+
11
+ @on_read = @configuration.on_read
12
+ allocate_socket
13
+
14
+ @message_queue = []
15
+ end
16
+
17
+ def shutdown
18
+ @reactor.log :debug, "#{self.class}#shutdown_socket, closing reactor socket"
19
+ @on_read = nil
20
+ @reactor.close_socket @socket
21
+ end
22
+
23
+ def on_attach socket
24
+ # socket options *must* be set before we bind/connect otherwise they are ignored
25
+ set_options socket
26
+ rc = -1
27
+
28
+ if @configuration.bind
29
+ rc = socket.bind @configuration.endpoint
30
+ @reactor.log :debug, "#{self.class}#on_attach, bind rc [#{rc}], endpoint #{@configuration.endpoint}"
31
+ raise "#{self.class}#on_attach, failed to bind to endpoint [#{@configuration.endpoint}]" unless ZMQ::Util.resultcode_ok?(rc)
32
+ elsif @configuration.connect
33
+ rc = socket.connect @configuration.endpoint
34
+ @reactor.log :debug, "#{self.class}#on_attach, connect rc [#{rc}], endpoint #{@configuration.endpoint}"
35
+ raise "#{self.class}#on_attach, failed to connect to endpoint [#{@configuration.endpoint}]" unless ZMQ::Util.resultcode_ok?(rc)
36
+ end
37
+
38
+
39
+ register_for_events socket
40
+ end
41
+
42
+ # Takes an array of ZM::Message instances and writes them out to the socket. If any
43
+ # socket write fails, the message is saved. We will attempt to write it again in
44
+ # 10 milliseconds or when another message array is sent, whichever comes first.
45
+ #
46
+ # All messages passed here are guaranteed to be written in the *order they were
47
+ # received*.
48
+ #
49
+ def write messages, verbose = false
50
+ @verbose = verbose
51
+ @message_queue << messages
52
+ write_queue_to_socket
53
+ end
54
+
55
+ # Prints each message when global debugging is enabled.
56
+ #
57
+ # Forwards +messages+ on to the :on_read callback given in the constructor.
58
+ #
59
+ def on_readable socket, messages
60
+ @on_read.call socket, messages
61
+ close_messages messages
62
+ end
63
+
64
+ # Just deregisters from receiving any further write *events*
65
+ #
66
+ def on_writable socket
67
+ #@reactor.log :debug, "#{self.class}#on_writable, deregister for writes on sid [#{@session_id}]"
68
+ @reactor.deregister_writable socket
69
+ end
70
+
71
+ def on_readable_error socket, return_code
72
+ STDERR.puts "#{self.class}#on_readable_error, rc [#{return_code}], errno [#{ZMQ::Util.errno}], description [#{ZMQ::Util.error_string}], sock #{socket.inspect}"
73
+ end
74
+
75
+ def on_writable_error socket, return_code
76
+ STDERR.puts "#{self.class}#on_writable_error, rc [#{return_code}], errno [#{ZMQ::Util.errno}], description [#{ZMQ::Util.error_string}], sock #{socket.inspect}"
77
+ end
78
+
79
+
80
+ private
81
+
82
+
83
+ def register_for_events socket
84
+ @reactor.register_readable socket
85
+ @reactor.deregister_writable socket
86
+ end
87
+
88
+ if ZMQ::LibZMQ.version2?
89
+
90
+ def set_options socket
91
+ socket.raw_socket.setsockopt ZMQ::HWM, (@configuration.hwm || 0)
92
+ socket.raw_socket.setsockopt ZMQ::LINGER, (@configuration.linger || 1)
93
+ end
94
+
95
+ elsif ZMQ::LibZMQ.version3?
96
+
97
+ def set_options socket
98
+ socket.raw_socket.setsockopt ZMQ::RCVHWM, (@configuration.hwm || 0)
99
+ socket.raw_socket.setsockopt ZMQ::SNDHWM, (@configuration.hwm || 0)
100
+ socket.raw_socket.setsockopt ZMQ::LINGER, (@configuration.linger || 1)
101
+ end
102
+
103
+ end
104
+
105
+ def write_queue_to_socket
106
+ until @message_queue.empty?
107
+ messages = get_next_message_array
108
+
109
+ rc = @socket.send_messages messages
110
+
111
+ if ZMQ::Util.resultcode_ok?(rc) # succeeded, so remove the message from the queue
112
+ @message_queue.shift
113
+ close_messages messages
114
+ elsif ZMQ::Util.errno == ZMQ::EAGAIN
115
+ # schedule another write attempt in 10 ms; break out of the loop
116
+ @reactor.log :debug, "#{self.class}#write_queue_to_socket, failed to write messages; scheduling next attempt"
117
+ @reactor.oneshot_timer 10, method(:write_queue_to_socket)
118
+ break
119
+ end
120
+ end
121
+ end
122
+
123
+ def get_next_message_array
124
+ messages = @message_queue.at(0)
125
+ messages.each { |message| @reactor.log :write, message.copy_out_string } if @verbose
126
+ messages
127
+ end
128
+
129
+ def close_messages messages
130
+ messages.each { |message| message.close }
131
+ end
132
+
133
+ def allocate_socket() nil; end
134
+
135
+ end # module Base
136
+
137
+ end # module Server
138
+
139
+ end # ZMQMachine