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.
- 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
|