zmqmachine 0.3.1 → 0.3.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.
data/History.txt CHANGED
@@ -1,7 +1,19 @@
1
+ == 0.3.2 / 2010-08-25
2
+ * Fixed a bug in Timers where the timers were never getting removed
3
+ after they fired. Bug was caused by a Ruby bug with #delete_if. While
4
+ deleting each fired timer, the delete_if loop was exited early via
5
+ a call to #break as an optimization. The #break caused all deletes to
6
+ be ignored.
7
+ See bug http://redmine.ruby-lang.org/issues/show/2545
8
+ * Minor fixes to the ping-pong examples. Was missing some calls to
9
+ register/deregister for read/write events. The socket semantics have
10
+ changed since earlier revisions; those changes didn't get caught until
11
+ now.
12
+
1
13
  == 0.3.1 / 2010-08-16
2
14
  * Forgot to load the xreq/xrep files during startup
3
15
  * Added support for resetting a timer's firing schedule. Useful for when
4
- the time source has been overridden; let's existing timers
16
+ the time source has been overridden; let's existing timers
5
17
  reschedule themselves using the new time source.
6
18
  * Fixed a logic bug with delivery of multi-part messages
7
19
 
@@ -19,7 +31,7 @@
19
31
  == 0.2.0 / 2010-06-06
20
32
  * Updated internals to conform to the 0mq api as of
21
33
  release 2.0.7.
22
-
34
+
23
35
  * Minor api enhancements.
24
36
 
25
37
  == 0.1.0 / 2010-06-02
@@ -35,7 +35,7 @@ class PingPongHandler
35
35
  def on_writable socket
36
36
  rc = socket.send_message_string "#{'a' * 2048}"
37
37
  @sent_count += 1
38
-
38
+
39
39
  # after sending the first message, deregister for future write events
40
40
  @context.deregister_writable socket
41
41
  end
@@ -71,7 +71,7 @@ ctx1 = ZM::Reactor.new(:test).run do |context|
71
71
  end
72
72
  end
73
73
 
74
- ctx1.join
74
+ ctx1.join 15_000
75
75
  #puts "Started at [#{Time.now}]"
76
76
  #puts "main thread will sleep [#{sleep_time}] seconds before aborting the context threads"
77
77
  #sleep sleep_time
@@ -3,7 +3,7 @@ require 'rubygems'
3
3
  require 'ffi-rzmq'
4
4
  require '../lib/zmqmachine'
5
5
 
6
- # This example illustrates how to write a simple set of
6
+ # This example illustrates how to write a simple set of
7
7
  # handlers for providing message ping-pong using
8
8
  # a REQ/REP socket pair. All activity is asynchronous and
9
9
  # relies on non-blocking I/O.
@@ -30,7 +30,7 @@ class PongHandler
30
30
  @received_count += 1
31
31
  socket.send_message messages.first
32
32
  @sent_count += 1
33
-
33
+
34
34
  @context.next_tick { @context.stop } if @sent_count == Allowed_pongs
35
35
  end
36
36
  end
@@ -45,6 +45,7 @@ class PingHandler
45
45
  end
46
46
 
47
47
  def on_attach socket
48
+ @context.register_readable socket
48
49
  address = ZM::Address.new '127.0.0.1', 5555, :tcp
49
50
  rc = socket.connect address
50
51
  rc = socket.send_message_string "#{'a' * 2048}"
@@ -81,6 +82,6 @@ end
81
82
  #end
82
83
 
83
84
 
84
- ctx1.join
85
+ ctx1.join 15_000
85
86
  #ctx2.join
86
87
  puts "received [#{@pong_handler.received_count}], sent [#{@pong_handler.sent_count}]"
@@ -0,0 +1,141 @@
1
+
2
+ require 'rubygems'
3
+ require 'ffi-rzmq'
4
+ require '../lib/zmqmachine'
5
+
6
+
7
+ # Shows how to publish from multiple PUB sockets to the same
8
+ # "bus" via a forwarder device.
9
+ #
10
+
11
+ class PublisherHandler
12
+ attr_reader :sent_count
13
+
14
+ def initialize context, port, topics
15
+ @context = context
16
+ @port = port
17
+ @topics = topics
18
+ @sent_count = 0
19
+ end
20
+
21
+ def on_attach socket
22
+ address = ZM::Address.new '127.0.0.1', @port, :tcp
23
+ rc = socket.connect address
24
+ # puts "publisher on_attach rc [#{rc}]"
25
+ end
26
+
27
+ def on_writable socket
28
+ # puts "publisher writing..."
29
+ topic = @topics[rand(@topics.size)]
30
+ symbol = topic.split('.').first
31
+
32
+ if 'es' == symbol
33
+ payload = "#{topic}|#{rand(1200) + 1}|#{rand(4400)}"
34
+ else
35
+ payload = "#{topic}|#{rand(300) + 1}|#{rand(8000)}"
36
+ end
37
+
38
+ message = ZMQ::Message.new payload
39
+ socket.send_message message
40
+ @sent_count += 1
41
+ end
42
+ end
43
+
44
+ class SubscriberHandler
45
+ attr_reader :received_count, :topics
46
+
47
+ def initialize context, ports, topic = nil, sleep = false
48
+ @context = context
49
+ @received_count = 0
50
+ @ports = ports
51
+ (@topics ||= []) << topic.to_s
52
+ @sleep = sleep
53
+ end
54
+
55
+ def on_attach socket
56
+ @ports.each do |port|
57
+ address = ZM::Address.new '127.0.0.1', port, :tcp
58
+ rc = socket.connect address
59
+ # puts "subscriber on_attach rc [#{rc}]"
60
+
61
+ @topics.each do |topic|
62
+ puts "subscribe to [#{topic}]"
63
+ socket.subscribe topic
64
+ end
65
+ end
66
+ end
67
+
68
+ def on_readable socket, messages
69
+ @received_count += 1
70
+ sleep 0.01 if @sleep
71
+ end
72
+ end
73
+
74
+ sleep_time = 5
75
+
76
+
77
+ # Run the forwarder device in a separate context. *Could* be run from
78
+ # the same context as the publishers and subscribers too.
79
+ #
80
+ ctx1 = ZM::Reactor.new(:A).run do |context|
81
+ incoming = ZM::Address.new '127.0.0.1', 5555, :tcp
82
+ outgoing = "tcp://127.0.0.1:5556"
83
+
84
+ forwarder = ZM::Device::Forwarder.new context, incoming, outgoing
85
+ puts "forwarder started"
86
+
87
+ # context.oneshot_timer(3000) do
88
+ # puts "reactor one shutting down..."
89
+ # context.stop
90
+ # puts "reactor one shut down"
91
+ # end
92
+ end
93
+
94
+ # Or, run each handler in separate contexts each with its
95
+ # own thread.
96
+ ctx2 = ZM::Reactor.new(:B).run do |context|
97
+ # start the publishers and subscribers after a 1 sec delay; give time
98
+ # to the forwarder device to start up and get ready
99
+ context.oneshot_timer(1000) do
100
+ @pub1_handler = PublisherHandler.new context, 5555, ['futures.us.es.m.10', 'futures.us.es.u.10']
101
+ context.pub_socket @pub1_handler
102
+
103
+ @pub2_handler = PublisherHandler.new context, 5555, ['futures.us.nq.m.10', 'futures.us.nq.u.10']
104
+ context.pub_socket @pub2_handler
105
+
106
+ @sub1_handler = SubscriberHandler.new context, [5556]
107
+ context.sub_socket @sub1_handler
108
+
109
+ @sub2_handler = SubscriberHandler.new context, [5556], 'futures.us.es.m'
110
+ context.sub_socket @sub2_handler
111
+
112
+ @sub3_handler = SubscriberHandler.new context, [5556], 'futures.us.es.u'
113
+ context.sub_socket @sub3_handler
114
+
115
+ @sub4_handler = SubscriberHandler.new context, [5556], 'futures.us.nq.m'
116
+ context.sub_socket @sub4_handler
117
+
118
+ @sub5_handler = SubscriberHandler.new context, [5556], 'futures.us.'
119
+ context.sub_socket @sub5_handler
120
+ end
121
+
122
+ # context.oneshot_timer(sleep_time * 1000) do
123
+ # puts "reactor two shutting down..."
124
+ # context.stop
125
+ # puts "reactor two shut down"
126
+ # end
127
+ end
128
+
129
+ # let's see how many messages we can publish in this many seconds
130
+ puts "Started at [#{Time.now}]"
131
+ puts "main thread will sleep [#{sleep_time}] seconds before aborting the reactor context threads"
132
+ sleep sleep_time
133
+
134
+ puts "done sleeping"
135
+ puts "sent [#{@pub1_handler.sent_count}]"
136
+ puts "sent [#{@pub2_handler.sent_count}]"
137
+ puts "* [#{@sub1_handler.received_count}]"
138
+ puts "futures.us.ep.m [#{@sub2_handler.received_count}]"
139
+ puts "futures.us.ep.u [#{@sub3_handler.received_count}]"
140
+ puts "futures.us.nq.m [#{@sub4_handler.received_count}]"
141
+ puts "futures.us.nq [#{@sub5_handler.received_count}]"
data/lib/zm/address.rb CHANGED
@@ -3,14 +3,14 @@
3
3
  # Author:: Chuck Remes
4
4
  # Homepage:: http://github.com/chuckremes/zmqmachine
5
5
  # Date:: 20100602
6
- #
6
+ #
7
7
  #----------------------------------------------------------------------------
8
8
  #
9
9
  # Copyright (C) 2010 by Chuck Remes. All Rights Reserved.
10
10
  # Email: cremes at mac dot com
11
- #
11
+ #
12
12
  # (The MIT License)
13
- #
13
+ #
14
14
  # Permission is hereby granted, free of charge, to any person obtaining
15
15
  # a copy of this software and associated documentation files (the
16
16
  # 'Software'), to deal in the Software without restriction, including
@@ -18,10 +18,10 @@
18
18
  # distribute, sublicense, and/or sell copies of the Software, and to
19
19
  # permit persons to whom the Software is furnished to do so, subject to
20
20
  # the following conditions:
21
- #
21
+ #
22
22
  # The above copyright notice and this permission notice shall be
23
23
  # included in all copies or substantial portions of the Software.
24
- #
24
+ #
25
25
  # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
26
26
  # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27
27
  # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
@@ -32,7 +32,7 @@
32
32
  #
33
33
  #---------------------------------------------------------------------------
34
34
  #
35
- #
35
+ #
36
36
 
37
37
  module ZMQMachine
38
38
 
@@ -41,18 +41,34 @@ module ZMQMachine
41
41
  #
42
42
  class Address
43
43
  attr_reader :host, :port, :transport
44
-
44
+
45
45
  # +type+ : :tcp, :pgm or :inprocess
46
46
  def initialize host, port, type = :tcp
47
47
  @host = host
48
48
  @port = port
49
49
  @transport = determine_type type
50
50
  end
51
-
51
+
52
52
  def to_s
53
53
  "#{@transport}://#{@host}:#{@port}"
54
54
  end
55
55
 
56
+
57
+ # Converts strings with the format "type://host:port" into
58
+ # an Address instance.
59
+ #
60
+ def self.from_string string
61
+ #FIXME: needs error checking and ability to handle inproc/ipc types
62
+ #
63
+ # should also return nil or some other error indication when parsing fails
64
+ split = string.split(':')
65
+ type = split[0]
66
+ port = split[2]
67
+ host = split[1].sub('//', '')
68
+
69
+ Address.new host, port, type.to_sym
70
+ end
71
+
56
72
  private
57
73
 
58
74
  def determine_type type
@@ -0,0 +1,119 @@
1
+ #--
2
+ #
3
+ # Author:: Chuck Remes
4
+ # Homepage:: http://github.com/chuckremes/zmqmachine
5
+ # Date:: 20100823
6
+ #
7
+ #----------------------------------------------------------------------------
8
+ #
9
+ # Copyright (C) 2010 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
+ module Device
40
+
41
+
42
+ # Used in conjunction with PUB/SUB sockets to allow multiple publishers to
43
+ # all publish to the same "bus."
44
+ #
45
+ # The basic mechanics are that the program contains 1 (or more) publishers that
46
+ # broadcast to the same bus. Connecting to
47
+ # an intermediate queue device allows for the publishers to have all of their
48
+ # traffic aggregated to a single port.
49
+ #
50
+ # Example:
51
+ #
52
+ # # the queue creates sockets and binds to both given addresses; all messages get
53
+ # # republished from +incoming+ to +outgoing+
54
+ # forwarder = ZM::Device::Forwarder.new reactor, "tcp://192.168.0.100:5050", "tcp://192.168.0.100:5051"
55
+ #
56
+ # # the +pub_handler+ internally calls "connect" to the incoming address given above
57
+ # pub1 = reactor.pub_socket pub_handler
58
+ # pub2 = reactor.pub_socket pub_handler
59
+ #
60
+ # # the +sub_handler+ internally calls "connect" to the outgoing address given above
61
+ # subscriber = reactor.sub_socket sub_handler
62
+ #
63
+ class Forwarder
64
+
65
+ class Handler
66
+ attr_accessor :socket_out
67
+
68
+ def initialize reactor, address, debug = false
69
+ @reactor = reactor
70
+ @address = address
71
+ @debug = debug
72
+ end
73
+
74
+ def on_attach socket
75
+ socket.identity = "forwarder.#{Kernel.rand(999_999_999)}"
76
+ rc = socket.bind @address
77
+ #FIXME: error handling!
78
+
79
+ socket.subscribe_all if :sub == socket.kind
80
+ end
81
+
82
+ def on_writable socket
83
+ @reactor.deregister_writable socket
84
+ end
85
+
86
+ def on_readable socket, messages
87
+ messages.each { |msg| p msg.copy_out_string } if @debug
88
+
89
+ socket_out.send_messages messages if @socket_out
90
+ end
91
+ end # class Handler
92
+
93
+
94
+ # Takes either a properly formatted string that can be converted into a ZM::Address
95
+ # or takes a ZM::Address directly.
96
+ #
97
+ # Forwards all messages received by the +incoming+ address to the +outgoing+ address.
98
+ #
99
+ def initialize reactor, incoming, outgoing, debug = false
100
+ incoming = Address.from_string incoming if incoming.kind_of? String
101
+ outgoing = Address.from_string outgoing if outgoing.kind_of? String
102
+
103
+ # setup the handlers for processing messages
104
+ @handler_in = Handler.new reactor, incoming, debug
105
+ @handler_out = Handler.new reactor, outgoing, debug
106
+
107
+ # create each socket and pass in the appropriate handler
108
+ @incoming = reactor.sub_socket @handler_in
109
+ @outgoing = reactor.pub_socket @handler_out
110
+
111
+ # set each handler's outgoing socket
112
+ @handler_in.socket_out = @outgoing
113
+ @handler_out.socket_out = @incoming
114
+ end
115
+ end # class Forwarder
116
+
117
+ end # module Device
118
+
119
+ end # module ZMQMachine
@@ -0,0 +1,122 @@
1
+ #--
2
+ #
3
+ # Author:: Chuck Remes
4
+ # Homepage:: http://github.com/chuckremes/zmqmachine
5
+ # Date:: 20100823
6
+ #
7
+ #----------------------------------------------------------------------------
8
+ #
9
+ # Copyright (C) 2010 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
+ module Device
40
+
41
+
42
+ # Used in conjunction with REQ/REP sockets to load balance the requests and
43
+ # replies over (potentially) multiple backends.
44
+ #
45
+ # The basic mechanics are that the program contains 1 (or more) clients that
46
+ # talk to 1 (or more) backends that all perform the same work. Connecting to
47
+ # an intermediate queue device allows for the client requests to be fair-balanced
48
+ # among the available backend servers. The hidden identities passed along by
49
+ # REQ/REP sockets are used by the queue device's internal XREQ/XREP sockets to
50
+ # route the messages back to the appropriate client.
51
+ #
52
+ # Example:
53
+ #
54
+ # # the queue creates sockets and binds to both given addresses; all messages get
55
+ # # routed between the two
56
+ # queue = ZM::Device::Queue.new reactor, "tcp://192.168.0.100:5050", "tcp://192.168.0.100:5051"
57
+ #
58
+ # # 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
61
+ #
62
+ # # the +server_handler+ internally calls "connect" to the outgoing address given above
63
+ # server = reactor.rep_socket server_handler
64
+ #
65
+ class Queue
66
+
67
+ class Handler
68
+ attr_accessor :socket_out
69
+
70
+ def initialize reactor, address, debug = false, dir = 0
71
+ @reactor = reactor
72
+ @address = address
73
+ @debug = debug
74
+ @dir = dir
75
+ end
76
+
77
+ def on_attach socket
78
+ socket.identity = "queue.#{Kernel.rand(999_999_999)}"
79
+ rc = socket.bind @address
80
+ #FIXME: error handling!
81
+ end
82
+
83
+ def on_writable socket
84
+ @reactor.deregister_writable socket
85
+ end
86
+
87
+ def on_readable socket, messages
88
+ messages.each { |msg| puts "[#{@dir}] [#{msg.copy_out_string}]" } if @debug
89
+
90
+ if @socket_out
91
+ socket_out.send_messages messages
92
+ end
93
+ end
94
+ end # class Handler
95
+
96
+
97
+ # Takes either a properly formatted string that can be converted into a ZM::Address
98
+ # or takes a ZM::Address directly.
99
+ #
100
+ # Routes all messages received by either address to the other address.
101
+ #
102
+ def initialize reactor, incoming, outgoing, debug = false
103
+ incoming = Address.from_string incoming if incoming.kind_of? String
104
+ outgoing = Address.from_string outgoing if outgoing.kind_of? String
105
+
106
+ # setup the handlers for processing messages
107
+ @handler_in = Handler.new reactor, incoming, debug, :in
108
+ @handler_out = Handler.new reactor, outgoing, debug, :out
109
+
110
+ # create each socket and pass in the appropriate handler
111
+ @incoming = reactor.xrep_socket @handler_in
112
+ @outgoing = reactor.xreq_socket @handler_out
113
+
114
+ # set each handler's outgoing socket
115
+ @handler_in.socket_out = @outgoing
116
+ @handler_out.socket_out = @incoming
117
+ end
118
+ end # class Queue
119
+
120
+ end # module Device
121
+
122
+ end # module ZMQMachine
data/lib/zm/devices.rb ADDED
@@ -0,0 +1,4 @@
1
+
2
+ %w( forwarder queue ).each do |rb_file|
3
+ require File.join(File.dirname(__FILE__), 'devices', rb_file)
4
+ end
data/lib/zm/reactor.rb CHANGED
@@ -332,7 +332,7 @@ module ZMQMachine
332
332
  def cancel_timer timer
333
333
  @timers.cancel timer
334
334
  end
335
-
335
+
336
336
  # Asks all timers to reschedule themselves starting from Timers.now.
337
337
  # Typically called when the underlying time source for the ZM::Timers
338
338
  # class has been replaced; existing timers may not fire as expected, so
@@ -117,9 +117,9 @@ module ZMQMachine
117
117
  queued = @raw_socket.send_string message, ZMQ::NOBLOCK | (multipart ? ZMQ::SNDMORE : 0)
118
118
  queued
119
119
  end
120
-
120
+
121
121
  # Convenience method for sending a multi-part message. The
122
- # +messages+ argument must respond to :size and :at (like
122
+ # +messages+ argument must respond to :size, :at and :last (like
123
123
  # an Array).
124
124
  #
125
125
  # May raise a ZMQ::SocketError.
@@ -128,16 +128,16 @@ module ZMQMachine
128
128
  rc = false
129
129
  i = 0
130
130
  size = messages.size
131
-
131
+
132
132
  # loop through all messages but the last
133
133
  while size > 1 && i < size - 1 do
134
134
  rc = send_message messages.at(i), true
135
135
  i += 1
136
136
  end
137
-
137
+
138
138
  # send the last message without the multipart arg to flush
139
139
  # the message to the 0mq queue
140
- rc = send_messages.last if size > 0
140
+ rc = send_message messages.last if size > 0
141
141
  rc
142
142
  end
143
143
 
@@ -3,14 +3,14 @@
3
3
  # Author:: Chuck Remes
4
4
  # Homepage:: http://github.com/chuckremes/zmqmachine
5
5
  # Date:: 20100602
6
- #
6
+ #
7
7
  #----------------------------------------------------------------------------
8
8
  #
9
9
  # Copyright (C) 2010 by Chuck Remes. All Rights Reserved.
10
10
  # Email: cremes at mac dot com
11
- #
11
+ #
12
12
  # (The MIT License)
13
- #
13
+ #
14
14
  # Permission is hereby granted, free of charge, to any person obtaining
15
15
  # a copy of this software and associated documentation files (the
16
16
  # 'Software'), to deal in the Software without restriction, including
@@ -18,10 +18,10 @@
18
18
  # distribute, sublicense, and/or sell copies of the Software, and to
19
19
  # permit persons to whom the Software is furnished to do so, subject to
20
20
  # the following conditions:
21
- #
21
+ #
22
22
  # The above copyright notice and this permission notice shall be
23
23
  # included in all copies or substantial portions of the Software.
24
- #
24
+ #
25
25
  # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
26
26
  # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27
27
  # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
@@ -32,7 +32,7 @@
32
32
  #
33
33
  #---------------------------------------------------------------------------
34
34
  #
35
- #
35
+ #
36
36
 
37
37
  module ZMQMachine
38
38
 
@@ -71,6 +71,10 @@ module ZMQMachine
71
71
  @raw_socket.setsockopt ZMQ::SUBSCRIBE, topic
72
72
  end
73
73
 
74
+ def subscribe_all
75
+ subscribe ''
76
+ end
77
+
74
78
  private
75
79
 
76
80
  def allocate_socket context
data/lib/zm/timers.rb CHANGED
@@ -3,14 +3,14 @@
3
3
  # Author:: Chuck Remes
4
4
  # Homepage:: http://github.com/chuckremes/zmqmachine
5
5
  # Date:: 20100602
6
- #
6
+ #
7
7
  #----------------------------------------------------------------------------
8
8
  #
9
9
  # Copyright (C) 2010 by Chuck Remes. All Rights Reserved.
10
10
  # Email: cremes at mac dot com
11
- #
11
+ #
12
12
  # (The MIT License)
13
- #
13
+ #
14
14
  # Permission is hereby granted, free of charge, to any person obtaining
15
15
  # a copy of this software and associated documentation files (the
16
16
  # 'Software'), to deal in the Software without restriction, including
@@ -18,10 +18,10 @@
18
18
  # distribute, sublicense, and/or sell copies of the Software, and to
19
19
  # permit persons to whom the Software is furnished to do so, subject to
20
20
  # the following conditions:
21
- #
21
+ #
22
22
  # The above copyright notice and this permission notice shall be
23
23
  # included in all copies or substantial portions of the Software.
24
- #
24
+ #
25
25
  # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
26
26
  # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27
27
  # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
@@ -32,12 +32,12 @@
32
32
  #
33
33
  #---------------------------------------------------------------------------
34
34
  #
35
- #
35
+ #
36
36
 
37
37
  module ZMQMachine
38
38
 
39
39
  # Manages the addition and cancellation of all timers. Each #Reactor
40
- # maintains its own set of timers; the timer belongs to the
40
+ # maintains its own set of timers; the timer belongs to the
41
41
  # reactor context.
42
42
  #
43
43
  # This should never be instantiated directly
@@ -83,7 +83,7 @@ module ZMQMachine
83
83
  timer
84
84
  end
85
85
 
86
- # Cancel the +timer+.
86
+ # Cancel the +timer+.
87
87
  #
88
88
  # Returns +true+ when cancellation succeeds.
89
89
  # Returns +false+ when it fails to find the
@@ -94,7 +94,7 @@ module ZMQMachine
94
94
  end
95
95
 
96
96
  # A convenience method that loops through all known timers
97
- # and fires all of the expired timers.
97
+ # and fires all of the expired timers.
98
98
  #
99
99
  #--
100
100
  # Internally the list is sorted whenever a timer is added or
@@ -106,35 +106,42 @@ module ZMQMachine
106
106
  # all time is expected as milliseconds
107
107
  now = Timers.now
108
108
  save = []
109
+ delete = []
109
110
 
110
111
  # timers should be sorted by expiration time
111
- @timers.delete_if do |timer|
112
+ # NOTE: was using #delete_if here, but it does *not* delete any
113
+ # items when the break executes before iterating through the entire
114
+ # set; that's unacceptable so I save each timer for deletion and
115
+ # do that in a separate loop
116
+ @timers.each do |timer|
112
117
  break unless timer.expired?(now)
113
118
  timer.fire
114
119
  save << timer if timer.periodical?
115
- true
120
+ delete << timer
116
121
  end
117
122
 
123
+ delete.each { |timer| @timers.delete timer }
124
+
118
125
  # reinstate the periodicals; necessary to do in two steps
119
126
  # since changing the timer.fire_time inside the loop would
120
127
  # not retain proper ordering in the sorted set; re-adding it
121
- # ensures the timer is in sorted order
128
+ # ensures the timers are in sorted order
122
129
  save.each { |timer| @timers.add timer }
123
130
  end
124
-
131
+
125
132
  # Runs through all timers and asks each one to reschedule itself
126
133
  # from Timers.now + whatever delay was originally recorded.
127
134
  #
128
135
  def reschedule
129
136
  timers = @timers.dup
130
137
  @timers.clear
131
-
138
+
132
139
  timers.each do |timer|
133
140
  timer.reschedule
134
141
  @timers.add timer
135
142
  end
136
143
  end
137
-
144
+
138
145
  # Returns the current time using the following algo:
139
146
  #
140
147
  # (Time.now.to_f * 1000).to_i
@@ -147,7 +154,7 @@ module ZMQMachine
147
154
  def self.now
148
155
  (Time.now.to_f * 1000).to_i
149
156
  end
150
-
157
+
151
158
  # Convert Timers.now to a number usable by the Time class.
152
159
  #
153
160
  def self.now_converted
@@ -157,7 +164,7 @@ module ZMQMachine
157
164
 
158
165
 
159
166
  # Used to track the specific expiration time and execution
160
- # code for each timer.
167
+ # code for each timer.
161
168
  #
162
169
  # This should never be instantiated directly
163
170
  # by user code. A timer must be known to the #Reactor in which it
@@ -214,7 +221,7 @@ module ZMQMachine
214
221
  def periodical?
215
222
  @periodical
216
223
  end
217
-
224
+
218
225
  def reschedule
219
226
  schedule_firing_time
220
227
  end
@@ -234,7 +241,7 @@ module ZMQMachine
234
241
  # had it not been late, it would fire at 20
235
242
  def schedule_firing_time
236
243
  @initiated = Timers.now
237
-
244
+
238
245
  @fire_time = @initiated + @delay
239
246
  end
240
247
 
data/lib/zmqmachine.rb CHANGED
@@ -66,7 +66,7 @@ require 'set'
66
66
  require 'ffi-rzmq'
67
67
 
68
68
  # the order of files is important
69
- %w(address exceptions timers deferrable reactor message sockets).each do |file|
69
+ %w(address exceptions timers deferrable reactor message sockets devices).each do |file|
70
70
  require ZMQMachine.libpath(['zm', file])
71
71
  end
72
72
 
data/version.txt CHANGED
@@ -1 +1 @@
1
- 0.3.1
1
+ 0.3.2
data/zmqmachine.gemspec CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{zmqmachine}
5
- s.version = "0.3.1"
5
+ s.version = "0.3.2"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Chuck Remes"]
9
- s.date = %q{2010-08-16}
9
+ s.date = %q{2010-08-25}
10
10
  s.description = %q{ZMQMachine is another Ruby implementation of the reactor pattern but this
11
11
  time using 0mq sockets rather than POSIX sockets.
12
12
 
@@ -22,19 +22,19 @@ It is possible to extend the 0mq library to "poll" normal file
22
22
  descriptors. This isn't on my roadmap but patches are accepted.}
23
23
  s.email = %q{cremes@mac.com}
24
24
  s.extra_rdoc_files = ["History.txt", "README.rdoc", "version.txt"]
25
- s.files = [".bnsignore", ".gitignore", "History.txt", "README.rdoc", "Rakefile", "examples/fake_ftp.rb", "examples/one_handed_ping_pong.rb", "examples/ping_pong.rb", "examples/pub_sub.rb", "examples/throttled_ping_pong.rb", "lib/zm/address.rb", "lib/zm/deferrable.rb", "lib/zm/exceptions.rb", "lib/zm/message.rb", "lib/zm/reactor.rb", "lib/zm/sockets.rb", "lib/zm/sockets/base.rb", "lib/zm/sockets/pair.rb", "lib/zm/sockets/pub.rb", "lib/zm/sockets/rep.rb", "lib/zm/sockets/req.rb", "lib/zm/sockets/sub.rb", "lib/zm/sockets/xrep.rb", "lib/zm/sockets/xreq.rb", "lib/zm/timers.rb", "lib/zmqmachine.rb", "spec/spec_helper.rb", "spec/zmqmachine_spec.rb", "version.txt", "zmqmachine.gemspec"]
25
+ s.files = [".bnsignore", "History.txt", "README.rdoc", "Rakefile", "examples/fake_ftp.rb", "examples/one_handed_ping_pong.rb", "examples/ping_pong.rb", "examples/pub_sub.rb", "examples/pubsub_forwarder.rb", "examples/throttled_ping_pong.rb", "lib/zm/address.rb", "lib/zm/deferrable.rb", "lib/zm/devices.rb", "lib/zm/devices/forwarder.rb", "lib/zm/devices/queue.rb", "lib/zm/exceptions.rb", "lib/zm/message.rb", "lib/zm/reactor.rb", "lib/zm/sockets.rb", "lib/zm/sockets/base.rb", "lib/zm/sockets/pair.rb", "lib/zm/sockets/pub.rb", "lib/zm/sockets/rep.rb", "lib/zm/sockets/req.rb", "lib/zm/sockets/sub.rb", "lib/zm/sockets/xrep.rb", "lib/zm/sockets/xreq.rb", "lib/zm/timers.rb", "lib/zmqmachine.rb", "spec/spec_helper.rb", "spec/zmqmachine_spec.rb", "version.txt", "zmqmachine.gemspec"]
26
26
  s.homepage = %q{http://github.com/chuckremes/zmqmachine}
27
27
  s.rdoc_options = ["--main", "README.rdoc"]
28
28
  s.require_paths = ["lib"]
29
29
  s.rubyforge_project = %q{zmqmachine}
30
- s.rubygems_version = %q{1.3.6}
30
+ s.rubygems_version = %q{1.3.7}
31
31
  s.summary = %q{ZMQMachine is another Ruby implementation of the reactor pattern but this time using 0mq sockets rather than POSIX sockets}
32
32
 
33
33
  if s.respond_to? :specification_version then
34
34
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
35
35
  s.specification_version = 3
36
36
 
37
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
37
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
38
38
  s.add_runtime_dependency(%q<ffi-rzmq>, [">= 0.5.0"])
39
39
  s.add_development_dependency(%q<bones>, [">= 3.4.7"])
40
40
  else
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 3
8
- - 1
9
- version: 0.3.1
8
+ - 2
9
+ version: 0.3.2
10
10
  platform: ruby
11
11
  authors:
12
12
  - Chuck Remes
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-08-16 00:00:00 -05:00
17
+ date: 2010-08-25 00:00:00 -05:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -70,7 +70,6 @@ extra_rdoc_files:
70
70
  - version.txt
71
71
  files:
72
72
  - .bnsignore
73
- - .gitignore
74
73
  - History.txt
75
74
  - README.rdoc
76
75
  - Rakefile
@@ -78,9 +77,13 @@ files:
78
77
  - examples/one_handed_ping_pong.rb
79
78
  - examples/ping_pong.rb
80
79
  - examples/pub_sub.rb
80
+ - examples/pubsub_forwarder.rb
81
81
  - examples/throttled_ping_pong.rb
82
82
  - lib/zm/address.rb
83
83
  - lib/zm/deferrable.rb
84
+ - lib/zm/devices.rb
85
+ - lib/zm/devices/forwarder.rb
86
+ - lib/zm/devices/queue.rb
84
87
  - lib/zm/exceptions.rb
85
88
  - lib/zm/message.rb
86
89
  - lib/zm/reactor.rb
data/.gitignore DELETED
@@ -1,14 +0,0 @@
1
- html
2
- pkg
3
- doc
4
- *.gem
5
- *.rbc
6
- *.tmproj
7
- nbproject
8
- *.bundle
9
- *.o
10
- .DS_Store
11
- examples/work
12
- benchmark
13
- *~
14
- *#*