rbczmq 0.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 (101) hide show
  1. data/.gitignore +23 -0
  2. data/.travis.yml +19 -0
  3. data/Gemfile +5 -0
  4. data/Gemfile.lock +19 -0
  5. data/MIT-LICENSE +20 -0
  6. data/README.rdoc +247 -0
  7. data/Rakefile +67 -0
  8. data/examples/loop.rb +109 -0
  9. data/examples/poller.rb +37 -0
  10. data/examples/pub_sub.rb +101 -0
  11. data/examples/push_pull.rb +104 -0
  12. data/examples/req_rep.rb +100 -0
  13. data/ext/czmq.tar.gz +0 -0
  14. data/ext/rbczmq/context.c +280 -0
  15. data/ext/rbczmq/context.h +26 -0
  16. data/ext/rbczmq/extconf.rb +138 -0
  17. data/ext/rbczmq/frame.c +401 -0
  18. data/ext/rbczmq/frame.h +24 -0
  19. data/ext/rbczmq/jruby.h +22 -0
  20. data/ext/rbczmq/loop.c +413 -0
  21. data/ext/rbczmq/loop.h +24 -0
  22. data/ext/rbczmq/message.c +620 -0
  23. data/ext/rbczmq/message.h +24 -0
  24. data/ext/rbczmq/poller.c +308 -0
  25. data/ext/rbczmq/poller.h +29 -0
  26. data/ext/rbczmq/pollitem.c +251 -0
  27. data/ext/rbczmq/pollitem.h +25 -0
  28. data/ext/rbczmq/rbczmq_ext.c +198 -0
  29. data/ext/rbczmq/rbczmq_ext.h +94 -0
  30. data/ext/rbczmq/rbczmq_prelude.h +22 -0
  31. data/ext/rbczmq/rubinius.h +24 -0
  32. data/ext/rbczmq/ruby18.h +43 -0
  33. data/ext/rbczmq/ruby19.h +15 -0
  34. data/ext/rbczmq/socket.c +1570 -0
  35. data/ext/rbczmq/socket.h +136 -0
  36. data/ext/rbczmq/timer.c +110 -0
  37. data/ext/rbczmq/timer.h +23 -0
  38. data/ext/zeromq.tar.gz +0 -0
  39. data/lib/rbczmq.rb +3 -0
  40. data/lib/zmq.rb +77 -0
  41. data/lib/zmq/context.rb +50 -0
  42. data/lib/zmq/default_handler.rb +16 -0
  43. data/lib/zmq/frame.rb +11 -0
  44. data/lib/zmq/handler.rb +76 -0
  45. data/lib/zmq/loop.rb +131 -0
  46. data/lib/zmq/message.rb +9 -0
  47. data/lib/zmq/poller.rb +22 -0
  48. data/lib/zmq/pollitem.rb +31 -0
  49. data/lib/zmq/socket.rb +125 -0
  50. data/lib/zmq/socket/dealer.rb +33 -0
  51. data/lib/zmq/socket/pair.rb +39 -0
  52. data/lib/zmq/socket/pub.rb +30 -0
  53. data/lib/zmq/socket/pull.rb +29 -0
  54. data/lib/zmq/socket/push.rb +32 -0
  55. data/lib/zmq/socket/rep.rb +37 -0
  56. data/lib/zmq/socket/req.rb +37 -0
  57. data/lib/zmq/socket/router.rb +38 -0
  58. data/lib/zmq/socket/sub.rb +27 -0
  59. data/lib/zmq/timer.rb +12 -0
  60. data/lib/zmq/version.rb +5 -0
  61. data/perf/pair.rb +7 -0
  62. data/perf/pair/local.rb +22 -0
  63. data/perf/pair/remote.rb +25 -0
  64. data/perf/pub_sub.rb +7 -0
  65. data/perf/pub_sub/local.rb +22 -0
  66. data/perf/pub_sub/remote.rb +25 -0
  67. data/perf/push_pull.rb +7 -0
  68. data/perf/push_pull/local.rb +21 -0
  69. data/perf/push_pull/remote.rb +25 -0
  70. data/perf/req_rep.rb +7 -0
  71. data/perf/req_rep/local.rb +35 -0
  72. data/perf/req_rep/remote.rb +28 -0
  73. data/perf/runner.rb +142 -0
  74. data/rbczmq.gemspec +22 -0
  75. data/test/helper.rb +21 -0
  76. data/test/socket/test_dealer_socket.rb +14 -0
  77. data/test/socket/test_pair_socket.rb +24 -0
  78. data/test/socket/test_pair_sockets.rb +74 -0
  79. data/test/socket/test_pub_socket.rb +17 -0
  80. data/test/socket/test_pub_sub_sockets.rb +87 -0
  81. data/test/socket/test_pull_socket.rb +17 -0
  82. data/test/socket/test_push_pull_sockets.rb +81 -0
  83. data/test/socket/test_push_socket.rb +17 -0
  84. data/test/socket/test_rep_socket.rb +25 -0
  85. data/test/socket/test_req_rep_sockets.rb +42 -0
  86. data/test/socket/test_req_socket.rb +27 -0
  87. data/test/socket/test_router_socket.rb +14 -0
  88. data/test/socket/test_routing.rb +66 -0
  89. data/test/socket/test_sub_socket.rb +17 -0
  90. data/test/test_context.rb +86 -0
  91. data/test/test_frame.rb +78 -0
  92. data/test/test_handler.rb +28 -0
  93. data/test/test_loop.rb +252 -0
  94. data/test/test_message.rb +201 -0
  95. data/test/test_poller.rb +154 -0
  96. data/test/test_pollitem.rb +78 -0
  97. data/test/test_socket.rb +403 -0
  98. data/test/test_threading.rb +34 -0
  99. data/test/test_timer.rb +37 -0
  100. data/test/test_zmq.rb +62 -0
  101. metadata +208 -0
data/lib/zmq/loop.rb ADDED
@@ -0,0 +1,131 @@
1
+ # encoding: utf-8
2
+
3
+ require "set"
4
+ require "forwardable"
5
+
6
+ class ZMQ::Loop
7
+
8
+ # The ZMQ::Loop class provides an event-driven reactor pattern. The reactor handles ZMQ::Socket or IO instances and
9
+ # once-off or repeated timers. Its resolution is 1 msec. It uses a tickless timer to reduce CPU interrupts in inactive
10
+ # processes.
11
+
12
+ class << self
13
+ extend Forwardable
14
+ def_delegators :instance, :context, :stop, :running?, :verbose=, :register_timer, :cancel_timer, :register, :remove
15
+ private
16
+ attr_accessor :instance
17
+ end
18
+
19
+ # Start the reactor. Takes control of the current thread and returns when :
20
+ #
21
+ # * the 0MQ context is terminated or
22
+ # * the process is interrupted or
23
+ # * any event handler raises an error
24
+ # * any event handler returns false
25
+ #
26
+ # ZMQ::Loop.run do # or ZMQ::Loop.run(&proc)
27
+ # ZL.add_oneshot_timer(0.2){ ZL.stop }
28
+ # end
29
+ #
30
+ def self.run(proc = nil, &blk)
31
+ self.instance = ZMQ::Loop.new
32
+ (proc || blk).call
33
+ instance.start
34
+ end
35
+
36
+ # A higher level API for ZMQ socket bind and loop registration.
37
+ #
38
+ # ZMQ::Loop.run do
39
+ # ZL.bind(pub, "inproc://fanout", Producer)
40
+ # end
41
+ #
42
+ def self.bind(socket, address, handler = ZMQ::DefaultHandler, *args)
43
+ attach(socket, :bind, address, handler, *args)
44
+ end
45
+
46
+ # A higher level API for ZMQ socket bind and loop registration.
47
+ #
48
+ # ZMQ::Loop.run do
49
+ # ZL.bind(pub, "inproc://fanout", Producer)
50
+ # ZL.connect(sub, "inproc://fanout", Consumer)
51
+ # end
52
+ #
53
+ def self.connect(socket, address, handler = ZMQ::DefaultHandler, *args)
54
+ attach(socket, :connect, address, handler, *args)
55
+ end
56
+
57
+ # Registers a given ZMQ::Socket or IO instance for readable events notification.
58
+ #
59
+ # ZMQ::Loop.run do
60
+ # ZL.register_readable(sub, "inproc://fanout", Consumer)
61
+ # end
62
+ #
63
+ def self.register_readable(pollable, handler = ZMQ::DefaultHandler, *args)
64
+ pollitem = ZMQ::Pollitem.new(pollable, ZMQ::POLLIN)
65
+ pollitem.handler = handler.new(pollitem, *args) if handler
66
+ assert_handler_for_event(pollitem, :on_readable)
67
+ instance.register(pollitem)
68
+ end
69
+
70
+ # Registers a given ZMQ::Socket or IO instance for writable events notification.
71
+ #
72
+ # ZMQ::Loop.run do
73
+ # ZL.register_writable(pub, "inproc://fanout", Producer)
74
+ # end
75
+ #
76
+ def self.register_writable(pollable, handler = ZMQ::DefaultHandler, *args)
77
+ pollitem = ZMQ::Pollitem.new(pollable, ZMQ::POLLOUT)
78
+ pollitem.handler = handler.new(pollitem, *args) if handler
79
+ assert_handler_for_event(pollitem, :on_writable)
80
+ instance.register(pollitem)
81
+ end
82
+
83
+ # Registers a oneshot timer with the event loop.
84
+ #
85
+ # ZMQ::Loop.run do
86
+ # ZL.add_oneshot_timer(0.2){ :work } # Fires once after 0.2s
87
+ # end
88
+ #
89
+ def self.add_oneshot_timer(delay, p = nil, &blk)
90
+ add_timer(delay, 1, p, &blk)
91
+ end
92
+
93
+ # Registers a periodic timer with the event loop.
94
+ #
95
+ # ZMQ::Loop.run do
96
+ # ZL.add_oneshot_timer(0.2){ :work } # Fires every 0.2s
97
+ # end
98
+ #
99
+ def self.add_periodic_timer(delay, p = nil, &blk)
100
+ add_timer(delay, 0, p, &blk)
101
+ end
102
+
103
+ # Lower level interface for timer registration
104
+ #
105
+ # ZMQ::Loop.run do
106
+ # timer = ZL.add_timer(0.1, 5){ :work } # Fires 5 times at 0.1s intervals
107
+ # end
108
+ #
109
+ def self.add_timer(delay, times, p = nil, &blk)
110
+ timer = ZMQ::Timer.new(delay, times, p, &blk)
111
+ instance.register_timer(timer)
112
+ timer
113
+ end
114
+
115
+ private
116
+ def self.attach(socket, action, address, handler, *args)
117
+ ret = socket.__send__(action, address)
118
+ register_readable(socket, handler, args) if socket.poll_readable?
119
+ register_writable(socket, handler, args) if socket.poll_writable?
120
+ ret
121
+ end
122
+
123
+ def self.assert_handler_for_event(pollitem, cb)
124
+ unless pollitem.handler.respond_to?(cb)
125
+ pollitem.handler = nil
126
+ raise ZMQ::Error, "Pollable entity #{pollitem.pollable}'s handler #{pollitem.handler.class} expected to implement an #{cb} callback!"
127
+ end
128
+ end
129
+ end
130
+
131
+ ZL = ZMQ::Loop
@@ -0,0 +1,9 @@
1
+ # encoding: utf-8
2
+
3
+ class ZMQ::Message
4
+
5
+ # The ZMQ::Message class provides methods to send and receive multipart messages across 0MQ sockets. This class provides
6
+ # a list-like container interface, with methods to work with the overall container.
7
+
8
+ include Comparable
9
+ end
data/lib/zmq/poller.rb ADDED
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+
3
+ class ZMQ::Poller
4
+
5
+ # API sugar to poll non-blocking. Returns immediately if there's no items in a ready state.
6
+ #
7
+ def poll_nonblock
8
+ poll(0)
9
+ end
10
+
11
+ # API sugar for registering a ZMQ::Socket or IO for readability
12
+ #
13
+ def register_readable(pollable)
14
+ register ZMQ::Pollitem.new(pollable, ZMQ::POLLIN)
15
+ end
16
+
17
+ # API sugar for registering a ZMQ::Socket or IO for writability
18
+ #
19
+ def register_writable(pollable)
20
+ register ZMQ::Pollitem.new(pollable, ZMQ::POLLOUT)
21
+ end
22
+ end
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+
3
+ class ZMQ::Pollitem
4
+ # API that allows poll items to send data regardless of the underlying pollable item type (ZMQ::Socket or IO).
5
+ #
6
+ def send(*args)
7
+ case pollable
8
+ when BasicSocket
9
+ pollable.send(args.shift, 0)
10
+ when IO
11
+ pollable.write_nonblock(*args)
12
+ when ZMQ::Socket
13
+ pollable.send(*args)
14
+ end
15
+ end
16
+
17
+ # API that allows poll items to recv data regardless of the underlying pollable item type (ZMQ::Socket or IO).
18
+ #
19
+ def recv
20
+ case pollable
21
+ when BasicSocket
22
+ # XXX assumed page size
23
+ pollable.recv_nonblock(4096)
24
+ when IO
25
+ # XXX assumed page size
26
+ pollable.read_nonblock(4096)
27
+ when ZMQ::Socket
28
+ pollable.recv_nonblock
29
+ end
30
+ end
31
+ end
data/lib/zmq/socket.rb ADDED
@@ -0,0 +1,125 @@
1
+ # encoding: utf-8
2
+
3
+ class ZMQ::Socket
4
+ def self.unsupported_api(*methods)
5
+ methods.each do |m|
6
+ class_eval <<-"evl", __FILE__, __LINE__
7
+ def #{m}(*args); raise(ZMQ::Error, "API #{m} not supported for #{const_get(:TYPE_STR)} sockets!"); end
8
+ evl
9
+ end
10
+ end
11
+
12
+ def self.handle_fsm_errors(error, *methods)
13
+ methods.each do |m|
14
+ class_eval <<-"evl", __FILE__, __LINE__
15
+ def #{m}(*args);
16
+ super
17
+ rescue SystemCallError => e
18
+ raise(ZMQ::Error, "#{error} Please assert that you're not sending / receiving out of band data when using the REQ / REP socket pairs.") if e.errno == ZMQ::EFSM
19
+ raise
20
+ end
21
+ evl
22
+ end
23
+ end
24
+
25
+ # Determines if there are one or more messages to read from this socket. Should be used in conjunction with the
26
+ # ZMQ_FD socket option for edge-triggered notifications.
27
+ #
28
+ # socket.readable? => true
29
+ #
30
+ def readable?
31
+ (events & ZMQ::POLLIN) == ZMQ::POLLIN
32
+ end
33
+
34
+ # Determines if this socket is in a writable state. Should be used in conjunction with the ZMQ_FD socket option for
35
+ # edge-triggered notifications.
36
+ #
37
+ # socket.writable? => true
38
+ #
39
+ def writable?
40
+ (events & ZMQ::POLLOUT) == ZMQ::POLLOUT
41
+ end
42
+
43
+ # Generates a string representation of this socket type
44
+ #
45
+ # socket = ctx.socket(:PUB)
46
+ # socket.type_str => "PUB"
47
+ #
48
+ def type_str
49
+ self.class.const_get(:TYPE_STR)
50
+ end
51
+
52
+ # Generates a string representation of the current socket state
53
+ #
54
+ # socket = ctx.bind(:PUB, "tcp://127.0.0.1:5000")
55
+ # socket.to_s => "PUB socket bound to tcp://127.0.0.1:5000"
56
+ #
57
+ def to_s
58
+ case state
59
+ when BOUND
60
+ "#{type_str} socket bound to #{endpoint}"
61
+ when CONNECTED
62
+ "#{type_str} socket connected to #{endpoint}"
63
+ else
64
+ "#{type_str} socket"
65
+ end
66
+ end
67
+
68
+ # Poll all sockets for readbable states by default
69
+ def poll_readable?
70
+ true
71
+ end
72
+
73
+ # Poll all sockets for writable states by default
74
+ def poll_writable?
75
+ true
76
+ end
77
+ end
78
+
79
+ module ZMQ::DownstreamSocket
80
+ # An interface for sockets that can only receive (read) data
81
+ #
82
+ # === Behavior
83
+ #
84
+ # [Disabled methods] ZMQ::Socket#bind, ZMQ::Socket#send, ZMQ::Socket#sendm, ZMQ::Socket#send_frame,
85
+ # ZMQ::Socket#send_message
86
+ # [Socket types] ZMQ::Socket::Pull, ZMQ::Socket::Sub
87
+
88
+ def self.included(sock)
89
+ sock.unsupported_api :send, :sendm, :send_frame, :send_message
90
+ end
91
+
92
+ # Upstream sockets should never be polled for writable states
93
+ def poll_writable?
94
+ false
95
+ end
96
+ end
97
+
98
+ module ZMQ::UpstreamSocket
99
+ # An interface for sockets that can only send (write) data
100
+ #
101
+ # === Behavior
102
+ #
103
+ # [Disabled methods] ZMQ::Socket#connect, ZMQ::Socket#recv, ZMQ::Socket#recv_nonblock, ZMQ::Socket#recv_frame,
104
+ # ZMQ::Socket#recv_frame_nonblock, ZMQ::Socket#recv_message
105
+ # [Socket types] ZMQ::Socket::Push, ZMQ::Socket::Pub
106
+
107
+ def self.included(sock)
108
+ sock.unsupported_api :recv, :recv_nonblock, :recv_frame, :recv_frame_nonblock, :recv_message
109
+ end
110
+
111
+ # Upstream sockets should never be polled for readable states
112
+ def poll_readable?
113
+ false
114
+ end
115
+ end
116
+
117
+ require "zmq/socket/pub"
118
+ require "zmq/socket/sub"
119
+ require "zmq/socket/push"
120
+ require "zmq/socket/pull"
121
+ require "zmq/socket/pair"
122
+ require "zmq/socket/req"
123
+ require "zmq/socket/rep"
124
+ require "zmq/socket/router"
125
+ require "zmq/socket/dealer"
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+
3
+ class ZMQ::Socket::Dealer
4
+
5
+ # == ZMQ::Socket::Dealer
6
+ #
7
+ # A socket of type ZMQ::Socket::Dealer is an advanced pattern used for extending request/reply sockets. Each message sent is
8
+ # load-balanced among all connected peers, and each message received is fair-queued from all connected peers.
9
+ #
10
+ # Previously this socket was called ZMQ_XREQ and that name remains available for backwards compatibility.
11
+ #
12
+ # When a ZMQ::Socket::Dealer socket enters an exceptional state due to having reached the high water mark for all peers, or if
13
+ # there are no peers at all, then any ZMQ::Socket#send operations on the socket shall block until the exceptional state ends
14
+ # or at least one peer becomes available for sending; messages are not discarded.
15
+ #
16
+ # When a ZMQ::Socket::Dealer socket is connected to a ZMQ::Socket::Rep socket each message sent must consist of an empty message part,
17
+ # the delimiter, followed by one or more body parts.
18
+ #
19
+ # === Summary of ZMQ::Socket::Dealer characteristics
20
+ #
21
+ # [Compatible peer sockets] ZMQ::Socket::Router, ZMQ::Socket::Request, ZMQ::Socket::Reply
22
+ # [Direction] Bidirectional
23
+ # [Send/receive pattern] Unrestricted
24
+ # [Outgoing routing strategy] Load-balanced
25
+ # [Incoming routing strategy] Fair-queued
26
+ # [ZMQ_HWM option action] Block
27
+
28
+ TYPE_STR = "DEALER"
29
+
30
+ def type
31
+ ZMQ::DEALER
32
+ end
33
+ end
@@ -0,0 +1,39 @@
1
+ # encoding: utf-8
2
+
3
+ class ZMQ::Socket::Pair
4
+
5
+ # == ZMQ::Socket::Pair
6
+ #
7
+ # A socket of type ZMQ::Socket::Pair can only be connected to a single peer at any one time. No message routing or filtering
8
+ # is performed on messages sent over a ZMQ::Socket::Pair socket.
9
+ #
10
+ # When a ZMQ::Socket::Pair socket enters an exceptional state due to having reached the high water mark for the connected
11
+ # peer, or if no peer is connected, then any ZMQ::Socket#send operations on the socket shall block until the peer becomes
12
+ # available for sending; messages are not discarded.
13
+ #
14
+ # === Summary of ZMQ::Socket::Pair characteristics
15
+ #
16
+ # [Compatible peer sockets] ZMQ::Socket::Pair
17
+ # [Direction] Bidirectional
18
+ # [Send/receive pattern] Unrestricted
19
+ # [Incoming routing strategy] N/A
20
+ # [Outgoing routing strategy] N/A
21
+ # [ZMQ::Socket#hwm option action] Block
22
+
23
+ TYPE_STR = "PAIR"
24
+ REXP_INPROC = /inproc:\/\//
25
+
26
+ def bind(endpoint)
27
+ raise(ZMQ::Error, "PAIR sockets can only listen using the inproc:// transport") unless endpoint =~ REXP_INPROC
28
+ super
29
+ end
30
+
31
+ def connect(endpoint)
32
+ raise(ZMQ::Error, "PAIR sockets can only connect using the inproc:// transport") unless endpoint =~ REXP_INPROC
33
+ super
34
+ end
35
+
36
+ def type
37
+ ZMQ::PAIR
38
+ end
39
+ end
@@ -0,0 +1,30 @@
1
+ # encoding: utf-8
2
+
3
+ class ZMQ::Socket::Pub
4
+
5
+ # == ZMQ::Socket::Pub
6
+ #
7
+ # A socket of type ZMQ::Socket::Pub is used by a publisher to distribute data. Messages sent are distributed in a fan out fashion
8
+ # to all connected peers. The ZMQ::Socket#recv function is not implemented for this socket type.
9
+ #
10
+ # When a ZMQ::Socket::Pub socket enters an exceptional state due to having reached the high water mark for a subscriber, then
11
+ # any messages that would be sent to the subscriber in question shall instead be dropped until the exceptional state ends. The
12
+ # ZMQ::Socket#send function shall never block for this socket type.
13
+ #
14
+ # === Summary of ZMQ::Socket::Pub characteristics
15
+ #
16
+ # [Compatible peer sockets] ZMQ::Socket::Sub
17
+ # [Direction] Unidirectional
18
+ # [Send/receive pattern] Send only
19
+ # [Incoming routing strategy] N/A
20
+ # [Outgoing routing strategy] Fan out
21
+ # [ZMQ::Socket#hwm option action] Drop
22
+
23
+ TYPE_STR = "PUB"
24
+
25
+ def type
26
+ ZMQ::PUB
27
+ end
28
+
29
+ include ZMQ::UpstreamSocket
30
+ end
@@ -0,0 +1,29 @@
1
+ # encoding: utf-8
2
+
3
+ class ZMQ::Socket::Pull
4
+
5
+ # == ZMQ::Socket::Pull
6
+ #
7
+ # A socket of type ZMQ::Socket::Pull is used by a pipeline node to receive messages from upstream pipeline nodes. Messages
8
+ # are fair-queued from among all connected upstream nodes. The ZMQ::Socket#send function is not implemented for this
9
+ # socket type.
10
+ #
11
+ # Deprecated alias: ZMQ_UPSTREAM.
12
+ #
13
+ # === Summary of ZMQ::Socket::Pull characteristics
14
+ #
15
+ # [Compatible peer sockets] ZMQ::Socket::Push
16
+ # [Direction] Unidirectional
17
+ # [Send/receive pattern] Receive only
18
+ # [Incoming routing strategy] Fair-queued
19
+ # [Outgoing routing strategy] N/A
20
+ # [ZMQ::Socket#hwm option action] N/A
21
+
22
+ TYPE_STR = "PULL"
23
+
24
+ def type
25
+ ZMQ::PULL
26
+ end
27
+
28
+ include ZMQ::DownstreamSocket
29
+ end