rbczmq 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +23 -0
- data/.travis.yml +19 -0
- data/Gemfile +5 -0
- data/Gemfile.lock +19 -0
- data/MIT-LICENSE +20 -0
- data/README.rdoc +247 -0
- data/Rakefile +67 -0
- data/examples/loop.rb +109 -0
- data/examples/poller.rb +37 -0
- data/examples/pub_sub.rb +101 -0
- data/examples/push_pull.rb +104 -0
- data/examples/req_rep.rb +100 -0
- data/ext/czmq.tar.gz +0 -0
- data/ext/rbczmq/context.c +280 -0
- data/ext/rbczmq/context.h +26 -0
- data/ext/rbczmq/extconf.rb +138 -0
- data/ext/rbczmq/frame.c +401 -0
- data/ext/rbczmq/frame.h +24 -0
- data/ext/rbczmq/jruby.h +22 -0
- data/ext/rbczmq/loop.c +413 -0
- data/ext/rbczmq/loop.h +24 -0
- data/ext/rbczmq/message.c +620 -0
- data/ext/rbczmq/message.h +24 -0
- data/ext/rbczmq/poller.c +308 -0
- data/ext/rbczmq/poller.h +29 -0
- data/ext/rbczmq/pollitem.c +251 -0
- data/ext/rbczmq/pollitem.h +25 -0
- data/ext/rbczmq/rbczmq_ext.c +198 -0
- data/ext/rbczmq/rbczmq_ext.h +94 -0
- data/ext/rbczmq/rbczmq_prelude.h +22 -0
- data/ext/rbczmq/rubinius.h +24 -0
- data/ext/rbczmq/ruby18.h +43 -0
- data/ext/rbczmq/ruby19.h +15 -0
- data/ext/rbczmq/socket.c +1570 -0
- data/ext/rbczmq/socket.h +136 -0
- data/ext/rbczmq/timer.c +110 -0
- data/ext/rbczmq/timer.h +23 -0
- data/ext/zeromq.tar.gz +0 -0
- data/lib/rbczmq.rb +3 -0
- data/lib/zmq.rb +77 -0
- data/lib/zmq/context.rb +50 -0
- data/lib/zmq/default_handler.rb +16 -0
- data/lib/zmq/frame.rb +11 -0
- data/lib/zmq/handler.rb +76 -0
- data/lib/zmq/loop.rb +131 -0
- data/lib/zmq/message.rb +9 -0
- data/lib/zmq/poller.rb +22 -0
- data/lib/zmq/pollitem.rb +31 -0
- data/lib/zmq/socket.rb +125 -0
- data/lib/zmq/socket/dealer.rb +33 -0
- data/lib/zmq/socket/pair.rb +39 -0
- data/lib/zmq/socket/pub.rb +30 -0
- data/lib/zmq/socket/pull.rb +29 -0
- data/lib/zmq/socket/push.rb +32 -0
- data/lib/zmq/socket/rep.rb +37 -0
- data/lib/zmq/socket/req.rb +37 -0
- data/lib/zmq/socket/router.rb +38 -0
- data/lib/zmq/socket/sub.rb +27 -0
- data/lib/zmq/timer.rb +12 -0
- data/lib/zmq/version.rb +5 -0
- data/perf/pair.rb +7 -0
- data/perf/pair/local.rb +22 -0
- data/perf/pair/remote.rb +25 -0
- data/perf/pub_sub.rb +7 -0
- data/perf/pub_sub/local.rb +22 -0
- data/perf/pub_sub/remote.rb +25 -0
- data/perf/push_pull.rb +7 -0
- data/perf/push_pull/local.rb +21 -0
- data/perf/push_pull/remote.rb +25 -0
- data/perf/req_rep.rb +7 -0
- data/perf/req_rep/local.rb +35 -0
- data/perf/req_rep/remote.rb +28 -0
- data/perf/runner.rb +142 -0
- data/rbczmq.gemspec +22 -0
- data/test/helper.rb +21 -0
- data/test/socket/test_dealer_socket.rb +14 -0
- data/test/socket/test_pair_socket.rb +24 -0
- data/test/socket/test_pair_sockets.rb +74 -0
- data/test/socket/test_pub_socket.rb +17 -0
- data/test/socket/test_pub_sub_sockets.rb +87 -0
- data/test/socket/test_pull_socket.rb +17 -0
- data/test/socket/test_push_pull_sockets.rb +81 -0
- data/test/socket/test_push_socket.rb +17 -0
- data/test/socket/test_rep_socket.rb +25 -0
- data/test/socket/test_req_rep_sockets.rb +42 -0
- data/test/socket/test_req_socket.rb +27 -0
- data/test/socket/test_router_socket.rb +14 -0
- data/test/socket/test_routing.rb +66 -0
- data/test/socket/test_sub_socket.rb +17 -0
- data/test/test_context.rb +86 -0
- data/test/test_frame.rb +78 -0
- data/test/test_handler.rb +28 -0
- data/test/test_loop.rb +252 -0
- data/test/test_message.rb +201 -0
- data/test/test_poller.rb +154 -0
- data/test/test_pollitem.rb +78 -0
- data/test/test_socket.rb +403 -0
- data/test/test_threading.rb +34 -0
- data/test/test_timer.rb +37 -0
- data/test/test_zmq.rb +62 -0
- metadata +208 -0
data/ext/rbczmq/socket.h
ADDED
@@ -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
|
data/ext/rbczmq/timer.c
ADDED
@@ -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, ×, &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
|
+
}
|
data/ext/rbczmq/timer.h
ADDED
@@ -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
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"
|
data/lib/zmq/context.rb
ADDED
@@ -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
|
data/lib/zmq/handler.rb
ADDED
@@ -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
|