rbczmq 0.1

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