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
@@ -0,0 +1,136 @@
1
+ #ifndef RBCZMQ_SOCKET_H
2
+ #define RBCZMQ_SOCKET_H
3
+
4
+ #define ZMQ_SOCKET_DESTROYED 0x01
5
+
6
+ /* Connection states */
7
+
8
+ #define ZMQ_SOCKET_PENDING 0x01
9
+ #define ZMQ_SOCKET_BOUND 0x02
10
+ #define ZMQ_SOCKET_CONNECTED 0x04
11
+
12
+ typedef struct {
13
+ zctx_t *ctx;
14
+ void *socket;
15
+ int flags;
16
+ Bool verbose;
17
+ int state;
18
+ #ifndef HAVE_RB_THREAD_BLOCKING_REGION
19
+ zlist_t *str_buffer;
20
+ zlist_t *frame_buffer;
21
+ zlist_t *msg_buffer;
22
+ #endif
23
+ VALUE endpoint;
24
+ VALUE thread;
25
+ VALUE recv_timeout;
26
+ VALUE send_timeout;
27
+ } zmq_sock_wrapper;
28
+
29
+ #define ZMQ_SOCKET_DEFAULT_TIMEOUT Qnil
30
+
31
+ #define ZmqAssertSocket(obj) ZmqAssertType(obj, rb_cZmqSocket, "ZMQ::Socket")
32
+ #define GetZmqSocket(obj) \
33
+ ZmqAssertSocket(obj); \
34
+ Data_Get_Struct(obj, zmq_sock_wrapper, sock); \
35
+ if (!sock) rb_raise(rb_eTypeError, "uninitialized ZMQ socket!"); \
36
+ if (sock->flags & ZMQ_SOCKET_DESTROYED) rb_raise(rb_eZmqError, "ZMQ::Socket instance %p has been destroyed by the ZMQ framework", (void *)obj);
37
+
38
+ #define ZmqDumpFrame(method, frame) \
39
+ do { \
40
+ sprintf(print_prefix, "%sI: %s socket %p: %s", cur_time, zsocket_type_str(sock->socket), (void *)sock->socket, method); \
41
+ zframe_print((frame), print_prefix); \
42
+ xfree(cur_time); \
43
+ } while(0)
44
+
45
+ #define ZmqDumpMessage(method, message) \
46
+ do { \
47
+ zclock_log("I: %s socket %p: %s", zsocket_type_str(sock->socket), (void *)sock->socket, method); \
48
+ zmsg_dump((message)); \
49
+ } while(0)
50
+
51
+ #define ZmqSockGuardCrossThread(sock) \
52
+ if ((sock)->thread != rb_thread_current()) \
53
+ rb_raise(rb_eZmqError, "Cross thread violation for %s socket %p: created in thread %p, invoked on thread %p", zsocket_type_str((sock)->socket), (void *)(sock), (void *)(sock)->thread, (void *)rb_thread_current());
54
+
55
+ #define ZmqAssertSockOptFor(sock_type) \
56
+ if (zsockopt_type(sock->socket) != sock_type) \
57
+ rb_raise(rb_eZmqError, "Socket option not supported on a %s socket!", zsocket_type_str(sock->socket));
58
+
59
+ #define CheckBoolean(arg) \
60
+ if (TYPE((arg)) != T_TRUE && TYPE((arg)) != T_FALSE) \
61
+ rb_raise(rb_eTypeError, "wrong argument %s (expected true or false)", RSTRING_PTR(rb_obj_as_string((arg))));
62
+
63
+ #define ZmqSetSockOpt(obj, opt, desc, value) \
64
+ int val; \
65
+ GetZmqSocket(obj); \
66
+ ZmqSockGuardCrossThread(sock); \
67
+ Check_Type(value, T_FIXNUM); \
68
+ val = FIX2INT(value); \
69
+ (opt)(sock->socket, val); \
70
+ if (sock->verbose) \
71
+ zclock_log ("I: %s socket %p: set option \"%s\" %d", zsocket_type_str(sock->socket), (void *)obj, (desc), val); \
72
+ return Qnil;
73
+
74
+ #define ZmqSetStringSockOpt(obj, opt, desc, value, assertion) \
75
+ char *val; \
76
+ GetZmqSocket(obj); \
77
+ ZmqSockGuardCrossThread(sock); \
78
+ Check_Type(value, T_STRING); \
79
+ (assertion); \
80
+ val = StringValueCStr(value); \
81
+ (opt)(sock->socket, val); \
82
+ if (sock->verbose) \
83
+ zclock_log ("I: %s socket %p: set option \"%s\" \"%s\"", zsocket_type_str(sock->socket), (void *)obj, (desc), val); \
84
+ return Qnil;
85
+
86
+ #define ZmqSetBooleanSockOpt(obj, opt, desc, value) \
87
+ int val; \
88
+ GetZmqSocket(obj); \
89
+ ZmqSockGuardCrossThread(sock); \
90
+ CheckBoolean(value); \
91
+ val = (value == Qtrue) ? 1 : 0; \
92
+ (opt)(sock->socket, val); \
93
+ if (sock->verbose) \
94
+ zclock_log ("I: %s socket %p: set option \"%s\" %d", zsocket_type_str(sock->socket), (void *)obj, (desc), val); \
95
+ return Qnil;
96
+
97
+ #define ZmqAssertSocketNotPending(sock, msg) \
98
+ if (!((sock)->state & (ZMQ_SOCKET_BOUND | ZMQ_SOCKET_CONNECTED))) \
99
+ rb_raise(rb_eZmqError, msg);
100
+
101
+ void rb_czmq_free_sock(zmq_sock_wrapper *sock);
102
+
103
+ void rb_czmq_mark_sock(void *ptr);
104
+ void rb_czmq_free_sock_gc(void *ptr);
105
+
106
+ struct nogvl_send_args {
107
+ zmq_sock_wrapper *socket;
108
+ const char *msg;
109
+ Bool read;
110
+ };
111
+
112
+ struct nogvl_send_frame_args {
113
+ zmq_sock_wrapper *socket;
114
+ zframe_t *frame;
115
+ int flags;
116
+ Bool read;
117
+ };
118
+
119
+ struct nogvl_send_message_args {
120
+ zmq_sock_wrapper *socket;
121
+ zmsg_t *message;
122
+ Bool read;
123
+ };
124
+
125
+ struct nogvl_recv_args {
126
+ zmq_sock_wrapper *socket;
127
+ };
128
+
129
+ struct nogvl_conn_args {
130
+ zmq_sock_wrapper *socket;
131
+ char *endpoint;
132
+ };
133
+
134
+ void _init_rb_czmq_socket();
135
+
136
+ #endif
@@ -0,0 +1,110 @@
1
+ #include <rbczmq_ext.h>
2
+
3
+ static VALUE intern_call;
4
+
5
+ /*
6
+ * :nodoc:
7
+ * GC mark callback
8
+ *
9
+ */
10
+ static void rb_czmq_mark_timer(void *ptr)
11
+ {
12
+ zmq_timer_wrapper *timer = (zmq_timer_wrapper *)ptr;
13
+ rb_gc_mark(timer->callback);
14
+ }
15
+
16
+ /*
17
+ * :nodoc:
18
+ * GC free callback
19
+ *
20
+ */
21
+ static void rb_czmq_free_timer_gc(void *ptr)
22
+ {
23
+ zmq_timer_wrapper *timer = (zmq_timer_wrapper *)ptr;
24
+ if (timer) xfree(timer);
25
+ }
26
+
27
+ /*
28
+ * call-seq:
29
+ * ZMQ::Timer.new(1, 2){ :fired } => ZMQ::Timer
30
+ *
31
+ * Initializes a new ZMQ::Timer instance.
32
+ *
33
+ * === Examples
34
+ * ZMQ::Timer.new(1, 2){ :fired } => ZMQ::Timer
35
+ *
36
+ */
37
+
38
+ VALUE rb_czmq_timer_s_new(int argc, VALUE *argv, VALUE timer)
39
+ {
40
+ VALUE delay, times, proc, callback;
41
+ size_t timer_delay;
42
+ zmq_timer_wrapper *tr = NULL;
43
+ rb_scan_args(argc, argv, "21&", &delay, &times, &proc, &callback);
44
+ if (NIL_P(proc) && NIL_P(callback)) rb_raise(rb_eArgError, "no callback given!");
45
+ if (NIL_P(proc)) {
46
+ rb_need_block();
47
+ } else {
48
+ callback = proc;
49
+ }
50
+ if (TYPE(delay) != T_FIXNUM && TYPE(delay) != T_FLOAT) rb_raise(rb_eTypeError, "wrong delay type %s (expected Fixnum or Float)", RSTRING_PTR(rb_obj_as_string(delay)));
51
+ Check_Type(times, T_FIXNUM);
52
+ timer_delay = (size_t)(((TYPE(delay) == T_FIXNUM) ? FIX2LONG(delay) : RFLOAT_VALUE(delay)) * 1000);
53
+ timer = Data_Make_Struct(rb_cZmqTimer, zmq_timer_wrapper, rb_czmq_mark_timer, rb_czmq_free_timer_gc, tr);
54
+ tr->cancelled = FALSE;
55
+ tr->delay = timer_delay;
56
+ tr->times = FIX2INT(times);
57
+ tr->callback = callback;
58
+ rb_obj_call_init(timer, 0, NULL);
59
+ return timer;
60
+ }
61
+
62
+ /*
63
+ * call-seq:
64
+ * timer.fire => Object
65
+ *
66
+ * Fires a timer.
67
+ *
68
+ * === Examples
69
+ * timer = ZMQ::Timer.new(1, 2){|arg| :fired } => ZMQ::Timer
70
+ * timer.fire(arg)
71
+ *
72
+ */
73
+
74
+ static VALUE rb_czmq_timer_fire(VALUE obj, VALUE args)
75
+ {
76
+ ZmqGetTimer(obj);
77
+ if (timer->cancelled == TRUE) rb_raise(rb_eZmqError, "cannot fire timer, already cancelled!");
78
+ return rb_apply(timer->callback, intern_call, args);
79
+ }
80
+
81
+ /*
82
+ * call-seq:
83
+ * timer.cancel => nil
84
+ *
85
+ * Fires a timer.
86
+ *
87
+ * === Examples
88
+ * timer = ZMQ::Timer.new(1, 2){|arg| :fired } => ZMQ::Timer
89
+ * timer.cancel => nil
90
+ *
91
+ */
92
+
93
+ static VALUE rb_czmq_timer_cancel(VALUE obj)
94
+ {
95
+ ZmqGetTimer(obj);
96
+ timer->cancelled = TRUE;
97
+ return Qnil;
98
+ }
99
+
100
+ void _init_rb_czmq_timer()
101
+ {
102
+ intern_call = rb_intern("call");
103
+
104
+ rb_cZmqTimer = rb_define_class_under(rb_mZmq, "Timer", rb_cObject);
105
+
106
+ rb_define_singleton_method(rb_cZmqTimer, "new", rb_czmq_timer_s_new, -1);
107
+ rb_define_method(rb_cZmqTimer, "fire", rb_czmq_timer_fire, -2);
108
+ rb_define_alias(rb_cZmqTimer, "call", "fire");
109
+ rb_define_method(rb_cZmqTimer, "cancel", rb_czmq_timer_cancel, 0);
110
+ }
@@ -0,0 +1,23 @@
1
+ #ifndef RBCZMQ_TIMER_H
2
+ #define RBCZMQ_TIMER_H
3
+
4
+ typedef struct {
5
+ size_t delay;
6
+ size_t times;
7
+ Bool cancelled;
8
+ VALUE callback;
9
+ } zmq_timer_wrapper;
10
+
11
+ #define ZmqAssertTimer(obj) ZmqAssertType(obj, rb_cZmqTimer, "ZMQ::Timer")
12
+ #define ZmqGetTimer(obj) \
13
+ zmq_timer_wrapper *timer = NULL; \
14
+ ZmqAssertTimer(obj); \
15
+ Data_Get_Struct(obj, zmq_timer_wrapper, timer); \
16
+ if (!timer) rb_raise(rb_eTypeError, "uninitialized ZMQ timer!");
17
+
18
+ VALUE rb_czmq_timer_s_new(int argc, VALUE *argv, VALUE timer);
19
+
20
+ void _init_rb_czmq_timer();
21
+
22
+ #endif
23
+
data/ext/zeromq.tar.gz ADDED
Binary file
data/lib/rbczmq.rb ADDED
@@ -0,0 +1,3 @@
1
+ # encoding: utf-8
2
+
3
+ require File.join(File.dirname(__FILE__), 'zmq')
data/lib/zmq.rb ADDED
@@ -0,0 +1,77 @@
1
+ # encoding: utf-8
2
+
3
+ # Prefer compiled Rubinius bytecode in .rbx/
4
+ ENV["RBXOPT"] = "-Xrbc.db"
5
+
6
+ begin
7
+ require "zmq/rbczmq_ext"
8
+ rescue LoadError
9
+ require "rbczmq_ext"
10
+ end
11
+
12
+ require 'zmq/version' unless defined? ZMQ::VERSION
13
+ require 'socket'
14
+
15
+ module ZMQ
16
+ # Sugaring for creating new ZMQ frames
17
+ #
18
+ # ZMQ::Frame("frame") => ZMQ::Frame
19
+ #
20
+ def self.Frame(data = nil)
21
+ ZMQ::Frame.new(data)
22
+ end
23
+
24
+ # Sugaring for creating new ZMQ messages
25
+ #
26
+ # ZMQ::Message("one", "two", "three") => ZMQ::Message
27
+ #
28
+ def self.Message(*parts)
29
+ m = ZMQ::Message.new
30
+ parts.each{|p| m.addstr(p) }
31
+ m
32
+ end
33
+
34
+ # Sugaring for creating new poll items
35
+ #
36
+ # ZMQ::Pollitem(STDIN, ZMQ::POLLIN) => ZMQ::Pollitem
37
+ #
38
+ def self.Pollitem(pollable, events = nil)
39
+ ZMQ::Pollitem.new(pollable, events)
40
+ end
41
+
42
+ # Returns the ZMQ context for this process, if any
43
+ #
44
+ def self.context
45
+ @__zmq_ctx_process[Process.pid]
46
+ end
47
+
48
+ # Higher level loop API.
49
+ #
50
+ # XXX: Handle cases where context is nil
51
+ #
52
+ def self.loop
53
+ @loop ||= ZMQ::Loop.new(context)
54
+ end
55
+
56
+ # API sugaring: IO.select compatible API, but for ZMQ sockets.
57
+ #
58
+ def self.select(read = [], write = [], error = [], timeout = nil)
59
+ poller = ZMQ::Poller.new
60
+ read.each{|s| poller.register_readable(s) } if read
61
+ write.each{|s| poller.register_writable(s) } if write
62
+ ready = poller.poll(timeout)
63
+ [poller.readables, poller.writables, []] if ready
64
+ end
65
+
66
+ autoload :Handler, 'zmq/handler'
67
+ autoload :DefaultHandler, 'zmq/default_handler'
68
+ end
69
+
70
+ require "zmq/context"
71
+ require "zmq/socket"
72
+ require "zmq/loop"
73
+ require "zmq/timer"
74
+ require "zmq/frame"
75
+ require "zmq/message"
76
+ require "zmq/poller"
77
+ require "zmq/pollitem"
@@ -0,0 +1,50 @@
1
+ # encoding: utf-8
2
+
3
+ class ZMQ::Context
4
+
5
+ # Overload the libczmq handler installed for SIGINT and SIGTERM on context init. This ensures we fallback to the default
6
+ # Ruby signal handlers which is least likely to violate the principle of least surprise. As an alternative fallback, we
7
+ # expose ZMQ.interrupted! which reverts back to the libczmq default actions when called from a Ruby signal handler. The
8
+ # following restores the default libczmq behavior :
9
+ #
10
+ # def initialize(*args)
11
+ # super
12
+ # trap(:INT){ ZMQ.interrupted! }
13
+ # trap(:TERM){ ZMQ.interrupted! }
14
+ # end
15
+ #
16
+
17
+ def initialize(*args)
18
+ super
19
+ trap(:INT, "DEFAULT")
20
+ trap(:TERM, "DEFAULT")
21
+ end
22
+
23
+ # Before using any ØMQ library functions the caller must initialise a ØMQ context.
24
+ #
25
+ # The context manages open sockets and automatically closes these before termination. Other responsibilities include :
26
+ #
27
+ # * A simple way to set the linger timeout on sockets
28
+ # * C onfigure contexts for a number of I/O threads
29
+ # * Sets-up signal (interrrupt) handling for the process.
30
+
31
+ # Sugaring for spawning a new socket and bind to a given endpoint
32
+ #
33
+ # ctx.bind(:PUB, "tcp://127.0.0.1:5000")
34
+ #
35
+ def bind(sock_type, endpoint)
36
+ s = socket(sock_type)
37
+ s.bind(endpoint)
38
+ s
39
+ end
40
+
41
+ # Sugaring for spawning a new socket and connect to a given endpoint
42
+ #
43
+ # ctx.connect(:SUB, "tcp://127.0.0.1:5000")
44
+ #
45
+ def connect(sock_type, endpoint)
46
+ s = socket(sock_type)
47
+ s.connect(endpoint)
48
+ s
49
+ end
50
+ end
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+
3
+ class ZMQ::DefaultHandler < ZMQ::Handler
4
+
5
+ # A default / blanket pollitem callback handler for when a socket or IO is registered on a ZMQ::Loop instance.
6
+ #
7
+ # XXX: Likely a massive fail for some socket / IO pairs as a default - look into removing this.
8
+
9
+ def on_readable
10
+ p recv
11
+ end
12
+
13
+ def on_writable
14
+ send("")
15
+ end
16
+ end
data/lib/zmq/frame.rb ADDED
@@ -0,0 +1,11 @@
1
+ # encoding: utf-8
2
+
3
+ class ZMQ::Frame
4
+
5
+ # The ZMQ::Frame class provides methods to send and receive single message rames across 0MQ sockets. When reading a frame
6
+ # from a socket, the ZMQ::Frame#more? method indicates if the frame is part of an unfinished multipart message. The
7
+ # ZMQ::Socket#send_frame method normally destroys the frame, but with the ZFRAME_REUSE flag, you can send the same frame
8
+ # many times. Frames are binary, and this class has no special support for text data.
9
+
10
+ include Comparable
11
+ end
@@ -0,0 +1,76 @@
1
+ # encoding: utf-8
2
+
3
+ class ZMQ::Handler
4
+
5
+ # The ZMQ::Pollitem instance wrapped by this handler.
6
+ attr_reader :pollitem
7
+
8
+ # A ZMQ::Pollitem instance is compulsary on init, with support for optional arguments if a subclasses do require them.
9
+ #
10
+ # pub = ctx.bind(:PUB, "tcp://127.0.0.1:5000") # lower level API
11
+ # item = ZMQ::Pollitem.new(pub)
12
+ # item.handler = ZMQ::Handler.new(pub)
13
+ #
14
+ # class ProducerHandler < ZMQ::Handler
15
+ # def initialize(item, producer)
16
+ # super
17
+ # @producer = producer
18
+ # end
19
+ #
20
+ # def on_writable
21
+ # @producer.work
22
+ # end
23
+ # end
24
+ #
25
+ # ZMQ::Loop.bind(:PUB, "tcp://127.0.0.1:5000", ProducerHandler, producer) # higher level API
26
+ #
27
+ def initialize(pollitem, *args)
28
+ raise TypeError.new("#{pollitem.inspect} is not a valid ZMQ::Pollitem instance") unless ZMQ::Pollitem === pollitem
29
+ @pollitem = pollitem
30
+ end
31
+
32
+ # Callback invoked from ZMQ::Loop handlers when the pollable item is ready for reading. Subclasses are expected to implement
33
+ # this contract as the default just raises NotImplementedError. It's reccommended to read in a non-blocking manner
34
+ # from within this callback.
35
+ #
36
+ # def on_readable
37
+ # msgs << recv
38
+ # end
39
+ #
40
+ def on_readable
41
+ raise NotImplementedError, "ZMQ handlers are expected to implement an #on_readable contract"
42
+ end
43
+
44
+ # Callback invoked from ZMQ::Loop handlers when the pollable item is ready for writing. Subclasses are expected to implement
45
+ # this contract as the default just raises NotImplementedError. It's reccommended to write data out as fast as possible
46
+ # from within this callback.
47
+ #
48
+ # def on_writable
49
+ # send buffer.shift
50
+ # end
51
+ #
52
+ def on_writable
53
+ raise NotImplementedError, "ZMQ handlers are expected to implement an #on_writable contract"
54
+ end
55
+
56
+ # Callback for error conditions such as pollable item errors on poll and exceptions raised in callbacks. Receives an exception
57
+ # instance as argument and raises by default.
58
+ #
59
+ # handler.on_error(err) => raise
60
+ #
61
+ def on_error(exception)
62
+ raise exception
63
+ end
64
+
65
+ # API that allows handlers to send data regardless of the underlying pollable item type (ZMQ::Socket or IO).
66
+ #
67
+ def send(*args)
68
+ pollitem.send(*args)
69
+ end
70
+
71
+ # API that allows handlers to receive data regardless of the underlying pollable item type (ZMQ::Socket or IO).
72
+ #
73
+ def recv
74
+ pollitem.recv
75
+ end
76
+ end