zmqmachine 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
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
- *#*