rbczmq 1.6.4 → 1.7.0
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.
- checksums.yaml +15 -0
- data/CHANGELOG.rdoc +7 -0
- data/Gemfile.lock +1 -1
- data/ext/rbczmq/beacon.c +1 -1
- data/ext/rbczmq/beacon.h +1 -1
- data/ext/rbczmq/frame.c +63 -50
- data/ext/rbczmq/frame.h +41 -9
- data/ext/rbczmq/message.c +186 -56
- data/ext/rbczmq/message.h +18 -2
- data/ext/rbczmq/pollitem.c +1 -1
- data/ext/rbczmq/rbczmq_ext.c +0 -4
- data/ext/rbczmq/rbczmq_ext.h +0 -2
- data/ext/rbczmq/socket.c +11 -5
- data/lib/zmq.rb +2 -1
- data/lib/zmq/logger.rb +58 -0
- data/lib/zmq/version.rb +2 -2
- data/test/test_frame.rb +2 -3
- data/test/test_logger.rb +41 -0
- data/test/test_message.rb +98 -5
- metadata +8 -10
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
NTIyYzk0ZmFkOTc4Y2YwMmRlYzc3ZGE0NmQyZTBhOGRlODQyMDcxMA==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
NTI4NzQyMDhkNGRjNGE5NDgxMDE3ZDg5MjU2YTViZWZiMWNjYzQxZA==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
ZmQ5NzExNWFhM2ZiODBlZmY4ZDZkMmM5YjBjMDQxODNkZDFlNTUxZmZlMjIz
|
10
|
+
N2JkZGU0Mjg4NzJlZTM2ZTEzYjI5ZDdkMGExNDU5MGMzMDE1ZjM2OTUxOTk4
|
11
|
+
ZDAyYjcwNTcyOGUzYjNhOTFkYzYyZTM5NTBkNjgyNDgyN2Q0ZDg=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
NDJmOGNmNmMwNGM3YjY5NmUwYTZmOTYzNzAyNGU5YzFmMTc0NGRhYTUzYjIw
|
14
|
+
YzI0YjJiODBlMjliMGQyYThjNjFhMWE1MWExZTJhNjAzNTMyNjQzZTM2YWZk
|
15
|
+
M2NiYzc5Mzc0NGE0NjlkMmQ1YzBmYTMyYjdiZjkxNmFkMGE5ZTI=
|
data/CHANGELOG.rdoc
CHANGED
@@ -1,5 +1,12 @@
|
|
1
1
|
= Changelog
|
2
2
|
|
3
|
+
== 1.7.0 (July 21, 2013)
|
4
|
+
|
5
|
+
* ZMQ::Frame - Implemented an interal wrapper around the underlying czmq frame objects to better manage memory and object ownership. (Matt Connolly)
|
6
|
+
* ZMQ::Frame#gone? and ZMQ::Message#gone? - new methods, return true when the frame/message has been sent and is no longer available for accessing. Methods may return nil for read operations or raise ZMQ::Error if the frame/message would be changed by that method. (Matt Connolly)
|
7
|
+
* ZMQ::Message - iterators (#first, #next, #last and #to_a) return consistent frame objects (not duplicates as in previous versions) that can be used with #remove. (Matt Connolly)
|
8
|
+
* Sending a message or frame marks it as "gone". The underlying data objects will be released by ZeroMQ as the frames/messages are sent over the socket. (Matt Connolly)
|
9
|
+
|
3
10
|
== 1.6.4 (July 10, 2013)
|
4
11
|
* Depend on a checkout task for vendored submodule init (Matt Connolly)
|
5
12
|
|
data/Gemfile.lock
CHANGED
data/ext/rbczmq/beacon.c
CHANGED
@@ -315,4 +315,4 @@ void _init_rb_czmq_beacon()
|
|
315
315
|
rb_define_method(rb_cZmqBeacon, "subscribe", rb_czmq_beacon_subscribe, 1);
|
316
316
|
rb_define_method(rb_cZmqBeacon, "unsubscribe", rb_czmq_beacon_unsubscribe, 0);
|
317
317
|
rb_define_method(rb_cZmqBeacon, "pipe", rb_czmq_beacon_pipe, 0);
|
318
|
-
}
|
318
|
+
}
|
data/ext/rbczmq/beacon.h
CHANGED
data/ext/rbczmq/frame.c
CHANGED
@@ -1,18 +1,6 @@
|
|
1
1
|
#include "rbczmq_ext.h"
|
2
2
|
static VALUE intern_data;
|
3
3
|
|
4
|
-
/*
|
5
|
-
* :nodoc:
|
6
|
-
* Callback invoked by zframe_destroy in libczmq. We track all frames coerced to native objects in a symbol table
|
7
|
-
* to guard against a mismatch between allocated frames and the Ruby object space as zframe_destroy is invoked
|
8
|
-
* throughout libczmq (zmsg.c) where the Ruby GC can't easily track it. Ruby MRI Object finalizers are a real
|
9
|
-
* pita to deal with.
|
10
|
-
*
|
11
|
-
*/
|
12
|
-
void rb_czmq_frame_freed(zframe_t *frame)
|
13
|
-
{
|
14
|
-
st_delete(frames_map, (st_data_t*)&frame, 0);
|
15
|
-
}
|
16
4
|
|
17
5
|
/*
|
18
6
|
* :nodoc:
|
@@ -22,8 +10,11 @@ void rb_czmq_frame_freed(zframe_t *frame)
|
|
22
10
|
VALUE rb_czmq_alloc_frame(zframe_t *frame)
|
23
11
|
{
|
24
12
|
VALUE frame_obj;
|
25
|
-
|
26
|
-
frame_obj =
|
13
|
+
zmq_frame_wrapper* f;
|
14
|
+
frame_obj = Data_Make_Struct(rb_cZmqFrame, zmq_frame_wrapper, 0, rb_czmq_free_frame_gc, f);
|
15
|
+
f->frame = frame;
|
16
|
+
f->flags = ZMQ_FRAME_OWNED;
|
17
|
+
f->message = NULL;
|
27
18
|
rb_obj_call_init(frame_obj, 0, NULL);
|
28
19
|
return frame_obj;
|
29
20
|
}
|
@@ -35,13 +26,11 @@ VALUE rb_czmq_alloc_frame(zframe_t *frame)
|
|
35
26
|
* libczmq.
|
36
27
|
*
|
37
28
|
*/
|
38
|
-
void rb_czmq_free_frame(
|
29
|
+
void rb_czmq_free_frame(zmq_frame_wrapper *frame)
|
39
30
|
{
|
40
|
-
if (frame) {
|
41
|
-
|
42
|
-
|
43
|
-
zframe_destroy(&frame);
|
44
|
-
}
|
31
|
+
if (frame && frame->frame && (frame->flags & ZMQ_FRAME_OWNED) != 0) {
|
32
|
+
zframe_destroy(&frame->frame);
|
33
|
+
frame->flags &= ~ZMQ_FRAME_OWNED;
|
45
34
|
}
|
46
35
|
}
|
47
36
|
|
@@ -52,7 +41,7 @@ void rb_czmq_free_frame(zframe_t *frame)
|
|
52
41
|
*/
|
53
42
|
void rb_czmq_free_frame_gc(void *ptr)
|
54
43
|
{
|
55
|
-
|
44
|
+
zmq_frame_wrapper *frame = (zmq_frame_wrapper *)ptr;
|
56
45
|
rb_czmq_free_frame(frame);
|
57
46
|
}
|
58
47
|
|
@@ -85,10 +74,7 @@ static VALUE rb_czmq_frame_s_new(int argc, VALUE *argv, VALUE frame)
|
|
85
74
|
ZmqAssertSysError();
|
86
75
|
rb_memerror();
|
87
76
|
}
|
88
|
-
|
89
|
-
frame = Data_Wrap_Struct(rb_cZmqFrame, 0, rb_czmq_free_frame_gc, fr);
|
90
|
-
rb_obj_call_init(frame, 0, NULL);
|
91
|
-
return frame;
|
77
|
+
return rb_czmq_alloc_frame(fr);
|
92
78
|
}
|
93
79
|
|
94
80
|
/*
|
@@ -108,6 +94,7 @@ static VALUE rb_czmq_frame_s_new(int argc, VALUE *argv, VALUE frame)
|
|
108
94
|
static VALUE rb_czmq_frame_destroy(VALUE obj)
|
109
95
|
{
|
110
96
|
ZmqGetFrame(obj);
|
97
|
+
ZmqAssertFrameOwned(frame);
|
111
98
|
rb_czmq_free_frame(frame);
|
112
99
|
return Qnil;
|
113
100
|
}
|
@@ -128,7 +115,8 @@ static VALUE rb_czmq_frame_size(VALUE obj)
|
|
128
115
|
{
|
129
116
|
size_t size;
|
130
117
|
ZmqGetFrame(obj);
|
131
|
-
|
118
|
+
ZmqReturnNilUnlessFrameOwned(frame);
|
119
|
+
size = zframe_size(frame->frame);
|
132
120
|
return LONG2FIX(size);
|
133
121
|
}
|
134
122
|
|
@@ -148,8 +136,9 @@ static VALUE rb_czmq_frame_data(VALUE obj)
|
|
148
136
|
{
|
149
137
|
size_t size;
|
150
138
|
ZmqGetFrame(obj);
|
151
|
-
|
152
|
-
|
139
|
+
ZmqReturnNilUnlessFrameOwned(frame);
|
140
|
+
size = zframe_size(frame->frame);
|
141
|
+
return ZmqEncode(rb_str_new((char *)zframe_data(frame->frame), (long)size));
|
153
142
|
}
|
154
143
|
|
155
144
|
/*
|
@@ -184,7 +173,8 @@ static VALUE rb_czmq_frame_to_s(VALUE obj)
|
|
184
173
|
static VALUE rb_czmq_frame_strhex(VALUE obj)
|
185
174
|
{
|
186
175
|
ZmqGetFrame(obj);
|
187
|
-
|
176
|
+
ZmqReturnNilUnlessFrameOwned(frame);
|
177
|
+
return rb_str_new2(zframe_strhex(frame->frame));
|
188
178
|
}
|
189
179
|
|
190
180
|
/*
|
@@ -201,19 +191,15 @@ static VALUE rb_czmq_frame_strhex(VALUE obj)
|
|
201
191
|
|
202
192
|
static VALUE rb_czmq_frame_dup(VALUE obj)
|
203
193
|
{
|
204
|
-
VALUE dup;
|
205
194
|
zframe_t *dup_fr = NULL;
|
206
|
-
errno = 0;
|
207
195
|
ZmqGetFrame(obj);
|
208
|
-
|
196
|
+
ZmqAssertFrameOwned(frame);
|
197
|
+
dup_fr = zframe_dup(frame->frame);
|
209
198
|
if (dup_fr == NULL) {
|
210
199
|
ZmqAssertSysError();
|
211
200
|
rb_memerror();
|
212
201
|
}
|
213
|
-
|
214
|
-
dup = Data_Wrap_Struct(rb_cZmqFrame, 0, rb_czmq_free_frame_gc, dup_fr);
|
215
|
-
rb_obj_call_init(dup, 0, NULL);
|
216
|
-
return dup;
|
202
|
+
return rb_czmq_alloc_frame(dup_fr);
|
217
203
|
}
|
218
204
|
|
219
205
|
/*
|
@@ -231,8 +217,9 @@ static VALUE rb_czmq_frame_dup(VALUE obj)
|
|
231
217
|
static VALUE rb_czmq_frame_data_equals_p(VALUE obj, VALUE data)
|
232
218
|
{
|
233
219
|
ZmqGetFrame(obj);
|
220
|
+
ZmqAssertFrameOwned(frame);
|
234
221
|
Check_Type(data, T_STRING);
|
235
|
-
return (zframe_streq(frame, RSTRING_PTR(data)) == true) ? Qtrue : Qfalse;
|
222
|
+
return (zframe_streq(frame->frame, RSTRING_PTR(data)) == true) ? Qtrue : Qfalse;
|
236
223
|
}
|
237
224
|
|
238
225
|
/*
|
@@ -250,7 +237,8 @@ static VALUE rb_czmq_frame_data_equals_p(VALUE obj, VALUE data)
|
|
250
237
|
static VALUE rb_czmq_frame_more_p(VALUE obj)
|
251
238
|
{
|
252
239
|
ZmqGetFrame(obj);
|
253
|
-
|
240
|
+
ZmqReturnNilUnlessFrameOwned(frame);
|
241
|
+
return (zframe_more(frame->frame) == ZFRAME_MORE) ? Qtrue : Qfalse;
|
254
242
|
}
|
255
243
|
|
256
244
|
/*
|
@@ -268,13 +256,14 @@ static VALUE rb_czmq_frame_more_p(VALUE obj)
|
|
268
256
|
|
269
257
|
static VALUE rb_czmq_frame_eql_p(VALUE obj, VALUE other_frame)
|
270
258
|
{
|
271
|
-
|
259
|
+
zmq_frame_wrapper *other = NULL;
|
272
260
|
ZmqGetFrame(obj);
|
261
|
+
ZmqAssertFrameOwned(frame);
|
273
262
|
ZmqAssertFrame(other_frame);
|
274
|
-
Data_Get_Struct(other_frame,
|
275
|
-
if (!other) rb_raise(rb_eTypeError, "uninitialized ZMQ frame!"); \
|
276
|
-
|
277
|
-
return (zframe_eq(frame, other)) ? Qtrue : Qfalse;
|
263
|
+
Data_Get_Struct(other_frame, zmq_frame_wrapper, other);
|
264
|
+
if (!other || !other->frame) rb_raise(rb_eTypeError, "uninitialized ZMQ frame!"); \
|
265
|
+
ZmqAssertFrameOwned(other);
|
266
|
+
return (zframe_eq(frame->frame, other->frame)) ? Qtrue : Qfalse;
|
278
267
|
}
|
279
268
|
|
280
269
|
/*
|
@@ -313,14 +302,15 @@ static VALUE rb_czmq_frame_equals(VALUE obj, VALUE other_frame)
|
|
313
302
|
static VALUE rb_czmq_frame_cmp(VALUE obj, VALUE other_frame)
|
314
303
|
{
|
315
304
|
long diff;
|
316
|
-
|
305
|
+
zmq_frame_wrapper *other = NULL;
|
317
306
|
if (obj == other_frame) return INT2NUM(0);
|
318
307
|
ZmqGetFrame(obj);
|
308
|
+
ZmqAssertFrameOwned(frame);
|
319
309
|
ZmqAssertFrame(other_frame);
|
320
|
-
Data_Get_Struct(other_frame,
|
321
|
-
if (!other) rb_raise(rb_eTypeError, "uninitialized ZMQ frame!");
|
322
|
-
|
323
|
-
diff = (zframe_size(frame) - zframe_size(other));
|
310
|
+
Data_Get_Struct(other_frame, zmq_frame_wrapper, other);
|
311
|
+
if (!other || !other->frame) rb_raise(rb_eTypeError, "uninitialized ZMQ frame!");
|
312
|
+
ZmqAssertFrameOwned(frame);
|
313
|
+
diff = (zframe_size(frame->frame) - zframe_size(other->frame));
|
324
314
|
if (diff == 0) return INT2NUM(0);
|
325
315
|
if (diff > 0) return INT2NUM(1);
|
326
316
|
return INT2NUM(-1);
|
@@ -343,6 +333,7 @@ static VALUE rb_czmq_frame_print(int argc, VALUE *argv, VALUE obj)
|
|
343
333
|
VALUE prefix;
|
344
334
|
const char *print_prefix = NULL;
|
345
335
|
ZmqGetFrame(obj);
|
336
|
+
ZmqAssertFrameOwned(frame);
|
346
337
|
rb_scan_args(argc, argv, "01", &prefix);
|
347
338
|
if (NIL_P(prefix)) {
|
348
339
|
print_prefix = "";
|
@@ -350,7 +341,7 @@ static VALUE rb_czmq_frame_print(int argc, VALUE *argv, VALUE obj)
|
|
350
341
|
Check_Type(prefix, T_STRING);
|
351
342
|
print_prefix = RSTRING_PTR(prefix);
|
352
343
|
}
|
353
|
-
zframe_print(frame, (char *)print_prefix);
|
344
|
+
zframe_print(frame->frame, (char *)print_prefix);
|
354
345
|
return Qnil;
|
355
346
|
}
|
356
347
|
|
@@ -371,12 +362,33 @@ static VALUE rb_czmq_frame_reset(VALUE obj, VALUE data)
|
|
371
362
|
{
|
372
363
|
errno = 0;
|
373
364
|
ZmqGetFrame(obj);
|
365
|
+
ZmqAssertFrameOwned(frame);
|
374
366
|
Check_Type(data, T_STRING);
|
375
|
-
zframe_reset(frame, (char *)RSTRING_PTR(data), (size_t)RSTRING_LEN(data));
|
367
|
+
zframe_reset(frame->frame, (char *)RSTRING_PTR(data), (size_t)RSTRING_LEN(data));
|
376
368
|
ZmqAssertSysError();
|
377
369
|
return Qnil;
|
378
370
|
}
|
379
371
|
|
372
|
+
/*
|
373
|
+
* call-seq:
|
374
|
+
* frame.gone? #=> false
|
375
|
+
* frame.destroy # or send
|
376
|
+
* frame.gone? #=> true
|
377
|
+
*
|
378
|
+
* Return boolean indicating if the ZMQ::Frame is gone (sent or destroyed). If the message is
|
379
|
+
* gone, accessor methods will return nil and methods requiring data or methods that mutate
|
380
|
+
* the message will raise an exception.
|
381
|
+
*/
|
382
|
+
|
383
|
+
static VALUE rb_czmq_frame_gone(VALUE obj)
|
384
|
+
{
|
385
|
+
ZmqGetFrame(obj);
|
386
|
+
return (frame->flags & ZMQ_FRAME_OWNED) ||
|
387
|
+
(frame->message != NULL && (frame->message->flags & ZMQ_MESSAGE_OWNED))
|
388
|
+
? Qfalse : Qtrue;
|
389
|
+
}
|
390
|
+
|
391
|
+
|
380
392
|
void _init_rb_czmq_frame()
|
381
393
|
{
|
382
394
|
intern_data = rb_intern("data");
|
@@ -403,4 +415,5 @@ void _init_rb_czmq_frame()
|
|
403
415
|
rb_define_method(rb_cZmqFrame, "print", rb_czmq_frame_print, -1);
|
404
416
|
rb_define_alias(rb_cZmqFrame, "dump", "print");
|
405
417
|
rb_define_method(rb_cZmqFrame, "reset", rb_czmq_frame_reset, 1);
|
418
|
+
rb_define_method(rb_cZmqFrame, "gone?", rb_czmq_frame_gone, 0);
|
406
419
|
}
|
data/ext/rbczmq/frame.h
CHANGED
@@ -1,21 +1,53 @@
|
|
1
1
|
#ifndef RBCZMQ_FRAME_H
|
2
2
|
#define RBCZMQ_FRAME_H
|
3
3
|
|
4
|
+
#include "message.h"
|
5
|
+
|
6
|
+
/* This flag indicates that the wrapped zframe_t is owned by ruby
|
7
|
+
and can be freed when the ZMQ::Frame object is garbage collected */
|
8
|
+
#define ZMQ_FRAME_OWNED 0x01
|
9
|
+
|
10
|
+
typedef struct {
|
11
|
+
/* The czmq frame object. This is only valid if the frame is owned
|
12
|
+
by ruby, or the frame has been added to a message and the message
|
13
|
+
is owned by ruby. */
|
14
|
+
zframe_t *frame;
|
15
|
+
|
16
|
+
/* The ruby ZMQ::Message object this frame is attached to, or NULL */
|
17
|
+
zmq_message_wrapper* message;
|
18
|
+
|
19
|
+
int flags;
|
20
|
+
} zmq_frame_wrapper;
|
21
|
+
|
4
22
|
#define ZmqAssertFrame(obj) ZmqAssertType(obj, rb_cZmqFrame, "ZMQ::Frame")
|
5
23
|
#define ZmqGetFrame(obj) \
|
6
|
-
|
24
|
+
zmq_frame_wrapper *frame = NULL; \
|
7
25
|
ZmqAssertFrame(obj); \
|
8
|
-
Data_Get_Struct(obj,
|
9
|
-
if (!frame) rb_raise(rb_eTypeError, "uninitialized ZMQ frame!");
|
10
|
-
|
26
|
+
Data_Get_Struct(obj, zmq_frame_wrapper, frame); \
|
27
|
+
if (!frame) rb_raise(rb_eTypeError, "uninitialized ZMQ frame!");
|
28
|
+
|
29
|
+
#define ZmqAssertFrameOwned(wrapper) if (!(\
|
30
|
+
(wrapper->flags & ZMQ_FRAME_OWNED) != 0 || \
|
31
|
+
(wrapper->message != NULL && (wrapper->message->flags & ZMQ_MESSAGE_OWNED) != 0 ) \
|
32
|
+
)) { \
|
33
|
+
rb_raise(rb_eZmqError, "Cannot access frame that belongs to another message or is gone."); \
|
34
|
+
}
|
35
|
+
|
36
|
+
#define ZmqAssertFrameOwnedNoMessage(wrapper) if (!(\
|
37
|
+
(wrapper->flags & ZMQ_FRAME_OWNED) != 0 \
|
38
|
+
)) { \
|
39
|
+
rb_raise(rb_eZmqError, "Cannot access frame that belongs to another message or is gone."); \
|
40
|
+
}
|
11
41
|
|
12
|
-
#define
|
13
|
-
|
14
|
-
|
42
|
+
#define ZmqReturnNilUnlessFrameOwned(wrapper) if (!(\
|
43
|
+
(wrapper->flags & ZMQ_FRAME_OWNED) != 0 || \
|
44
|
+
(wrapper->message != NULL && (wrapper->message->flags & ZMQ_MESSAGE_OWNED) != 0 ) \
|
45
|
+
)) { \
|
46
|
+
return Qnil; \
|
47
|
+
}
|
15
48
|
|
16
|
-
void rb_czmq_free_frame(
|
49
|
+
void rb_czmq_free_frame(zmq_frame_wrapper *frame);
|
17
50
|
void rb_czmq_free_frame_gc(void *ptr);
|
18
|
-
void rb_czmq_frame_freed(zframe_t *frame);
|
19
51
|
|
20
52
|
VALUE rb_czmq_alloc_frame(zframe_t *frame);
|
21
53
|
|
data/ext/rbczmq/message.c
CHANGED
@@ -8,9 +8,12 @@
|
|
8
8
|
void rb_czmq_free_message(zmq_message_wrapper *message)
|
9
9
|
{
|
10
10
|
errno = 0;
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
if (message != NULL && message->message != NULL && message->flags & ZMQ_MESSAGE_OWNED) {
|
12
|
+
zmsg_destroy(&message->message);
|
13
|
+
message->message = NULL;
|
14
|
+
message->flags &= ~ZMQ_MESSAGE_OWNED;
|
15
|
+
zlist_destroy(&message->frames);
|
16
|
+
}
|
14
17
|
}
|
15
18
|
|
16
19
|
/*
|
@@ -22,11 +25,24 @@ static void rb_czmq_free_message_gc(void *ptr)
|
|
22
25
|
{
|
23
26
|
zmq_message_wrapper *msg = (zmq_message_wrapper *)ptr;
|
24
27
|
if (msg) {
|
25
|
-
|
28
|
+
rb_czmq_free_message(msg);
|
26
29
|
xfree(msg);
|
27
30
|
}
|
28
31
|
}
|
29
32
|
|
33
|
+
/*
|
34
|
+
* :nodoc:
|
35
|
+
* mark the owned ZMQ::Frame objects so that they are not collected.
|
36
|
+
*/
|
37
|
+
void rb_czmq_mark_message(zmq_message_wrapper *message)
|
38
|
+
{
|
39
|
+
VALUE frame = (VALUE)zlist_first(message->frames);
|
40
|
+
while (frame) {
|
41
|
+
rb_gc_mark(frame);
|
42
|
+
frame = (VALUE)zlist_next(message->frames);
|
43
|
+
}
|
44
|
+
}
|
45
|
+
|
30
46
|
/*
|
31
47
|
* :nodoc:
|
32
48
|
* Coerce a zmsg instance to a native Ruby object.
|
@@ -40,7 +56,22 @@ VALUE rb_czmq_alloc_message(zmsg_t *message)
|
|
40
56
|
message_obj = Data_Make_Struct(rb_cZmqMessage, zmq_message_wrapper, 0, rb_czmq_free_message_gc, m);
|
41
57
|
m->message = message;
|
42
58
|
ZmqAssertObjOnAlloc(m->message, m);
|
43
|
-
m->flags =
|
59
|
+
m->flags = ZMQ_MESSAGE_OWNED;
|
60
|
+
m->frames = zlist_new();
|
61
|
+
|
62
|
+
/* create ZMQ::Frame objects for all frames in the message and
|
63
|
+
link the ruby objects to this message. */
|
64
|
+
zframe_t* zframe = zmsg_first(message);
|
65
|
+
while (zframe) {
|
66
|
+
VALUE frame_object = rb_czmq_alloc_frame(zframe);
|
67
|
+
ZmqGetFrame(frame_object);
|
68
|
+
frame->flags &= ~ZMQ_FRAME_OWNED;
|
69
|
+
frame->message = m;
|
70
|
+
zlist_append(m->frames, (void*)frame_object);
|
71
|
+
|
72
|
+
zframe = zmsg_next(message);
|
73
|
+
}
|
74
|
+
|
44
75
|
rb_obj_call_init(message_obj, 0, NULL);
|
45
76
|
return message_obj;
|
46
77
|
}
|
@@ -58,14 +89,11 @@ VALUE rb_czmq_alloc_message(zmsg_t *message)
|
|
58
89
|
|
59
90
|
static VALUE rb_czmq_message_new(VALUE message)
|
60
91
|
{
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
msg->flags = 0;
|
67
|
-
rb_obj_call_init(message, 0, NULL);
|
68
|
-
return message;
|
92
|
+
zmsg_t* msg = zmsg_new();
|
93
|
+
if (msg == NULL) {
|
94
|
+
rb_raise(rb_eZmqError, "Failed to allocate message object (zmsg_new).");
|
95
|
+
}
|
96
|
+
return rb_czmq_alloc_message(msg);
|
69
97
|
}
|
70
98
|
|
71
99
|
/*
|
@@ -85,6 +113,7 @@ static VALUE rb_czmq_message_new(VALUE message)
|
|
85
113
|
static VALUE rb_czmq_message_size(VALUE obj)
|
86
114
|
{
|
87
115
|
ZmqGetMessage(obj);
|
116
|
+
ZmqReturnNilUnlessOwned(message);
|
88
117
|
return INT2NUM(zmsg_size(message->message));
|
89
118
|
}
|
90
119
|
|
@@ -105,6 +134,7 @@ static VALUE rb_czmq_message_size(VALUE obj)
|
|
105
134
|
static VALUE rb_czmq_message_content_size(VALUE obj)
|
106
135
|
{
|
107
136
|
ZmqGetMessage(obj);
|
137
|
+
ZmqReturnNilUnlessOwned(message);
|
108
138
|
return INT2NUM(zmsg_content_size(message->message));
|
109
139
|
}
|
110
140
|
|
@@ -127,10 +157,15 @@ static VALUE rb_czmq_message_push(VALUE obj, VALUE frame_obj)
|
|
127
157
|
int rc = 0;
|
128
158
|
errno = 0;
|
129
159
|
ZmqGetMessage(obj);
|
160
|
+
ZmqAssertMessageOwned(message);
|
130
161
|
ZmqGetFrame(frame_obj);
|
131
|
-
|
162
|
+
ZmqAssertFrameOwnedNoMessage(frame);
|
163
|
+
|
164
|
+
rc = zmsg_push(message->message, frame->frame);
|
132
165
|
ZmqAssert(rc);
|
133
|
-
|
166
|
+
frame->message = message;
|
167
|
+
frame->flags &= ~ZMQ_FRAME_OWNED;
|
168
|
+
zlist_push(message->frames, (void*)frame_obj);
|
134
169
|
return Qtrue;
|
135
170
|
}
|
136
171
|
|
@@ -153,10 +188,15 @@ static VALUE rb_czmq_message_add(VALUE obj, VALUE frame_obj)
|
|
153
188
|
int rc = 0;
|
154
189
|
errno = 0;
|
155
190
|
ZmqGetMessage(obj);
|
191
|
+
ZmqAssertMessageOwned(message);
|
156
192
|
ZmqGetFrame(frame_obj);
|
157
|
-
|
193
|
+
ZmqAssertFrameOwnedNoMessage(frame);
|
194
|
+
|
195
|
+
rc = zmsg_add(message->message, frame->frame);
|
158
196
|
ZmqAssert(rc);
|
159
|
-
|
197
|
+
frame->message = message;
|
198
|
+
frame->flags &= ~ZMQ_FRAME_OWNED;
|
199
|
+
zlist_append(message->frames, (void*)frame_obj);
|
160
200
|
return Qtrue;
|
161
201
|
}
|
162
202
|
|
@@ -179,9 +219,11 @@ static VALUE rb_czmq_message_pop(VALUE obj)
|
|
179
219
|
{
|
180
220
|
zframe_t *frame = NULL;
|
181
221
|
ZmqGetMessage(obj);
|
182
|
-
|
222
|
+
ZmqAssertMessageOwned(message);
|
223
|
+
frame = zmsg_pop(message->message); /* we now own the frame */
|
183
224
|
if (frame == NULL) return Qnil;
|
184
|
-
|
225
|
+
VALUE frame_obj = (VALUE)zlist_pop(message->frames);
|
226
|
+
return frame_obj ? frame_obj : Qnil;
|
185
227
|
}
|
186
228
|
|
187
229
|
/*
|
@@ -200,6 +242,7 @@ static VALUE rb_czmq_message_pop(VALUE obj)
|
|
200
242
|
static VALUE rb_czmq_message_print(VALUE obj)
|
201
243
|
{
|
202
244
|
ZmqGetMessage(obj);
|
245
|
+
ZmqReturnNilUnlessOwned(message);
|
203
246
|
zmsg_dump(message->message);
|
204
247
|
return Qnil;
|
205
248
|
}
|
@@ -220,11 +263,10 @@ static VALUE rb_czmq_message_print(VALUE obj)
|
|
220
263
|
|
221
264
|
static VALUE rb_czmq_message_first(VALUE obj)
|
222
265
|
{
|
223
|
-
zframe_t *frame = NULL;
|
224
266
|
ZmqGetMessage(obj);
|
225
|
-
|
226
|
-
|
227
|
-
return
|
267
|
+
ZmqReturnNilUnlessOwned(message);
|
268
|
+
VALUE frame_obj = (VALUE)zlist_first(message->frames);
|
269
|
+
return frame_obj ? frame_obj : Qnil;
|
228
270
|
}
|
229
271
|
|
230
272
|
/*
|
@@ -244,11 +286,10 @@ static VALUE rb_czmq_message_first(VALUE obj)
|
|
244
286
|
|
245
287
|
static VALUE rb_czmq_message_next(VALUE obj)
|
246
288
|
{
|
247
|
-
zframe_t *frame = NULL;
|
248
289
|
ZmqGetMessage(obj);
|
249
|
-
|
250
|
-
|
251
|
-
return
|
290
|
+
ZmqReturnNilUnlessOwned(message);
|
291
|
+
VALUE frame_obj = (VALUE)zlist_next(message->frames);
|
292
|
+
return frame_obj ? frame_obj : Qnil;
|
252
293
|
}
|
253
294
|
|
254
295
|
/*
|
@@ -267,11 +308,10 @@ static VALUE rb_czmq_message_next(VALUE obj)
|
|
267
308
|
|
268
309
|
static VALUE rb_czmq_message_last(VALUE obj)
|
269
310
|
{
|
270
|
-
zframe_t *frame = NULL;
|
271
311
|
ZmqGetMessage(obj);
|
272
|
-
|
273
|
-
|
274
|
-
return
|
312
|
+
ZmqReturnNilUnlessOwned(message);
|
313
|
+
VALUE frame_obj = (VALUE)zlist_last(message->frames);
|
314
|
+
return frame_obj ? frame_obj : Qnil;
|
275
315
|
}
|
276
316
|
|
277
317
|
/*
|
@@ -293,10 +333,18 @@ static VALUE rb_czmq_message_last(VALUE obj)
|
|
293
333
|
static VALUE rb_czmq_message_remove(VALUE obj, VALUE frame_obj)
|
294
334
|
{
|
295
335
|
ZmqGetMessage(obj);
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
336
|
+
ZmqAssertMessageOwned(message);
|
337
|
+
ZmqGetFrame(frame_obj);
|
338
|
+
|
339
|
+
/* remove from message and our list of frame objects */
|
340
|
+
zmsg_remove(message->message, frame->frame);
|
341
|
+
zlist_remove(message->frames, (void*)frame_obj);
|
342
|
+
|
343
|
+
/* removing from message does not destroy the frame,
|
344
|
+
therefore, we take ownership of the frame at this point */
|
345
|
+
frame->message = NULL;
|
346
|
+
frame->flags |= ZMQ_FRAME_OWNED;
|
347
|
+
|
300
348
|
return Qnil;
|
301
349
|
}
|
302
350
|
|
@@ -317,9 +365,19 @@ static VALUE rb_czmq_message_pushstr(VALUE obj, VALUE str)
|
|
317
365
|
int rc = 0;
|
318
366
|
errno = 0;
|
319
367
|
ZmqGetMessage(obj);
|
368
|
+
ZmqAssertMessageOwned(message);
|
320
369
|
Check_Type(str, T_STRING);
|
321
370
|
rc = zmsg_pushmem(message->message, StringValueCStr(str), RSTRING_LEN(str));
|
322
371
|
ZmqAssert(rc);
|
372
|
+
|
373
|
+
/* keep zlist of frame ruby objects in sync with message's frame list */
|
374
|
+
zframe_t* zframe = zmsg_first(message->message);
|
375
|
+
VALUE frame_object = rb_czmq_alloc_frame(zframe);
|
376
|
+
ZmqGetFrame(frame_object);
|
377
|
+
frame->flags &= ~ZMQ_FRAME_OWNED;
|
378
|
+
frame->message = message;
|
379
|
+
zlist_push(message->frames, (void*)frame_object);
|
380
|
+
|
323
381
|
return Qtrue;
|
324
382
|
}
|
325
383
|
|
@@ -340,9 +398,19 @@ static VALUE rb_czmq_message_addstr(VALUE obj, VALUE str)
|
|
340
398
|
int rc = 0;
|
341
399
|
errno = 0;
|
342
400
|
ZmqGetMessage(obj);
|
401
|
+
ZmqAssertMessageOwned(message);
|
343
402
|
Check_Type(str, T_STRING);
|
344
403
|
rc = zmsg_addmem(message->message, StringValueCStr(str), RSTRING_LEN(str));
|
345
404
|
ZmqAssert(rc);
|
405
|
+
|
406
|
+
/* keep zlist of frame ruby objects in sync with message's frame list */
|
407
|
+
zframe_t* zframe = zmsg_last(message->message);
|
408
|
+
VALUE frame_object = rb_czmq_alloc_frame(zframe);
|
409
|
+
ZmqGetFrame(frame_object);
|
410
|
+
frame->flags &= ~ZMQ_FRAME_OWNED;
|
411
|
+
frame->message = message;
|
412
|
+
zlist_append(message->frames, (void*)frame_object);
|
413
|
+
|
346
414
|
return Qtrue;
|
347
415
|
}
|
348
416
|
|
@@ -363,8 +431,13 @@ static VALUE rb_czmq_message_popstr(VALUE obj)
|
|
363
431
|
{
|
364
432
|
char *str = NULL;
|
365
433
|
ZmqGetMessage(obj);
|
434
|
+
ZmqAssertMessageOwned(message);
|
366
435
|
str = zmsg_popstr(message->message);
|
367
436
|
if (str == NULL) return Qnil;
|
437
|
+
|
438
|
+
/* destroys the frame, keep frame objects list in sync: */
|
439
|
+
zlist_pop(message->frames);
|
440
|
+
|
368
441
|
return rb_str_new2(str);
|
369
442
|
}
|
370
443
|
|
@@ -386,9 +459,30 @@ static VALUE rb_czmq_message_wrap(VALUE obj, VALUE frame_obj)
|
|
386
459
|
{
|
387
460
|
errno = 0;
|
388
461
|
ZmqGetMessage(obj);
|
389
|
-
|
390
|
-
|
391
|
-
|
462
|
+
ZmqAssertMessageOwned(message);
|
463
|
+
|
464
|
+
{
|
465
|
+
ZmqGetFrame(frame_obj);
|
466
|
+
ZmqAssertFrameOwned(frame);
|
467
|
+
zmsg_wrap(message->message, frame->frame);
|
468
|
+
frame->flags &= ~ZMQ_FRAME_OWNED;
|
469
|
+
frame->message = message;
|
470
|
+
}
|
471
|
+
|
472
|
+
/* keep frame objects list in sync. Two frames have been added. frame_obj from above
|
473
|
+
and a new one for the empty frame. */
|
474
|
+
{
|
475
|
+
zmsg_first(message->message);
|
476
|
+
zframe_t* empty_frame = zmsg_next(message->message);
|
477
|
+
|
478
|
+
VALUE empty_frame_object = rb_czmq_alloc_frame(empty_frame);
|
479
|
+
ZmqGetFrame(empty_frame_object);
|
480
|
+
frame->flags &= ~ZMQ_FRAME_OWNED;
|
481
|
+
frame->message = message;
|
482
|
+
|
483
|
+
zlist_push(message->frames, (void*)empty_frame_object);
|
484
|
+
zlist_push(message->frames, (void*)frame_obj);
|
485
|
+
}
|
392
486
|
return Qnil;
|
393
487
|
}
|
394
488
|
|
@@ -410,11 +504,29 @@ static VALUE rb_czmq_message_wrap(VALUE obj, VALUE frame_obj)
|
|
410
504
|
|
411
505
|
static VALUE rb_czmq_message_unwrap(VALUE obj)
|
412
506
|
{
|
413
|
-
zframe_t *frame = NULL;
|
414
507
|
ZmqGetMessage(obj);
|
415
|
-
|
416
|
-
|
417
|
-
|
508
|
+
ZmqAssertMessageOwned(message);
|
509
|
+
|
510
|
+
/* reimplemented the zmsg_unwrap function for simpler logic: */
|
511
|
+
zframe_t *zframe = zmsg_pop(message->message);
|
512
|
+
VALUE frame_obj = 0;
|
513
|
+
if (zframe != NULL) {
|
514
|
+
frame_obj = (VALUE)zlist_pop(message->frames);
|
515
|
+
}
|
516
|
+
|
517
|
+
zframe_t *empty = zmsg_first(message->message);
|
518
|
+
if (zframe_size(empty) == 0) {
|
519
|
+
empty = zmsg_pop(message->message);
|
520
|
+
zframe_destroy (&empty);
|
521
|
+
zlist_pop(message->frames);
|
522
|
+
}
|
523
|
+
|
524
|
+
{
|
525
|
+
ZmqGetFrame(frame_obj);
|
526
|
+
frame->message = NULL;
|
527
|
+
frame->flags |= ZMQ_FRAME_OWNED;
|
528
|
+
}
|
529
|
+
return frame_obj ? frame_obj : Qnil;
|
418
530
|
}
|
419
531
|
|
420
532
|
/*
|
@@ -431,16 +543,11 @@ static VALUE rb_czmq_message_unwrap(VALUE obj)
|
|
431
543
|
|
432
544
|
static VALUE rb_czmq_message_dup(VALUE obj)
|
433
545
|
{
|
434
|
-
VALUE dup;
|
435
|
-
zmq_message_wrapper *dup_msg = NULL;
|
436
|
-
errno = 0;
|
437
546
|
ZmqGetMessage(obj);
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
dup_msg
|
442
|
-
rb_obj_call_init(dup, 0, NULL);
|
443
|
-
return dup;
|
547
|
+
ZmqAssertMessageOwned(message);
|
548
|
+
|
549
|
+
zmsg_t* dup_msg = zmsg_dup(message->message);
|
550
|
+
return rb_czmq_alloc_message(dup_msg);
|
444
551
|
}
|
445
552
|
|
446
553
|
/*
|
@@ -460,6 +567,7 @@ static VALUE rb_czmq_message_dup(VALUE obj)
|
|
460
567
|
static VALUE rb_czmq_message_destroy(VALUE obj)
|
461
568
|
{
|
462
569
|
ZmqGetMessage(obj);
|
570
|
+
ZmqAssertMessageOwned(message);
|
463
571
|
rb_czmq_free_message(message);
|
464
572
|
return Qnil;
|
465
573
|
}
|
@@ -483,6 +591,7 @@ static VALUE rb_czmq_message_encode(VALUE obj)
|
|
483
591
|
byte *buff;
|
484
592
|
size_t buff_size;
|
485
593
|
ZmqGetMessage(obj);
|
594
|
+
ZmqReturnNilUnlessOwned(message);
|
486
595
|
buff_size = zmsg_encode(message->message, &buff);
|
487
596
|
return rb_str_new((char *)buff, buff_size);
|
488
597
|
}
|
@@ -531,8 +640,10 @@ static VALUE rb_czmq_message_eql_p(VALUE obj, VALUE other_message)
|
|
531
640
|
size_t other_buff_size;
|
532
641
|
ZmqGetMessage(obj);
|
533
642
|
ZmqAssertMessage(other_message);
|
643
|
+
ZmqAssertMessageOwned(message);
|
534
644
|
Data_Get_Struct(other_message, zmq_message_wrapper, other);
|
535
645
|
if (!other) rb_raise(rb_eTypeError, "uninitialized ZMQ message!");
|
646
|
+
ZmqAssertMessageOwned(other);
|
536
647
|
|
537
648
|
if (zmsg_size(message->message) != zmsg_size(other->message)) return Qfalse;
|
538
649
|
if (zmsg_content_size(message->message) != zmsg_content_size(other->message)) return Qfalse;
|
@@ -580,15 +691,33 @@ static VALUE rb_czmq_message_to_a(VALUE obj)
|
|
580
691
|
{
|
581
692
|
VALUE ary;
|
582
693
|
ZmqGetMessage(obj);
|
583
|
-
|
584
|
-
|
585
|
-
|
586
|
-
|
587
|
-
|
694
|
+
ZmqAssertMessageOwned(message);
|
695
|
+
ary = rb_ary_new2(zlist_size(message->frames));
|
696
|
+
VALUE frame_obj = (VALUE)zlist_first(message->frames);
|
697
|
+
while (frame_obj) {
|
698
|
+
rb_ary_push(ary, frame_obj);
|
699
|
+
frame_obj = (VALUE)zlist_next(message->frames);
|
588
700
|
}
|
589
701
|
return ary;
|
590
702
|
}
|
591
703
|
|
704
|
+
/*
|
705
|
+
* call-seq:
|
706
|
+
* msg.gone? #=> false
|
707
|
+
* msg.destroy # or send
|
708
|
+
* msg.gone? #=> true
|
709
|
+
*
|
710
|
+
* Return boolean indicating if the ZMQ::Message is gone (sent or destroyed). If the message is
|
711
|
+
* gone, accessor methods will return nil and methods requiring data or methods that mutate
|
712
|
+
* the message will raise an exception.
|
713
|
+
*/
|
714
|
+
|
715
|
+
static VALUE rb_czmq_message_gone(VALUE obj)
|
716
|
+
{
|
717
|
+
ZmqGetMessage(obj);
|
718
|
+
return (message->flags & ZMQ_MESSAGE_OWNED) ? Qfalse : Qtrue;
|
719
|
+
}
|
720
|
+
|
592
721
|
void _init_rb_czmq_message()
|
593
722
|
{
|
594
723
|
rb_cZmqMessage = rb_define_class_under(rb_mZmq, "Message", rb_cObject);
|
@@ -617,4 +746,5 @@ void _init_rb_czmq_message()
|
|
617
746
|
rb_define_method(rb_cZmqMessage, "eql?", rb_czmq_message_equals, 1);
|
618
747
|
rb_define_method(rb_cZmqMessage, "==", rb_czmq_message_equals, 1);
|
619
748
|
rb_define_method(rb_cZmqMessage, "to_a", rb_czmq_message_to_a, 0);
|
749
|
+
rb_define_method(rb_cZmqMessage, "gone?", rb_czmq_message_gone, 0);
|
620
750
|
}
|
data/ext/rbczmq/message.h
CHANGED
@@ -1,11 +1,15 @@
|
|
1
1
|
#ifndef RBCZMQ_MESSAGE_H
|
2
2
|
#define RBCZMQ_MESSAGE_H
|
3
3
|
|
4
|
-
|
4
|
+
/* This flag indicates that the wrapped zmsg_t is owned by ruby
|
5
|
+
and can be freed when the ZMQ::Message object is garbage collected */
|
6
|
+
#define ZMQ_MESSAGE_OWNED 0x01
|
5
7
|
|
6
8
|
typedef struct {
|
7
9
|
zmsg_t *message;
|
8
10
|
int flags;
|
11
|
+
/* a zlist of frame wrapper objects for the frames in this message */
|
12
|
+
zlist_t *frames;
|
9
13
|
} zmq_message_wrapper;
|
10
14
|
|
11
15
|
#define ZmqAssertMessage(obj) ZmqAssertType(obj, rb_cZmqMessage, "ZMQ::Message")
|
@@ -13,11 +17,23 @@ typedef struct {
|
|
13
17
|
zmq_message_wrapper *message = NULL; \
|
14
18
|
ZmqAssertMessage(obj); \
|
15
19
|
Data_Get_Struct(obj, zmq_message_wrapper, message); \
|
16
|
-
if (!message) rb_raise(rb_eTypeError, "uninitialized ZMQ message!");
|
20
|
+
if (!message) rb_raise(rb_eTypeError, "uninitialized ZMQ message!");
|
21
|
+
|
22
|
+
/*
|
17
23
|
if (message->flags & ZMQ_MESSAGE_DESTROYED) rb_raise(rb_eZmqError, "ZMQ::Message instance %p has been destroyed by the ZMQ framework", (void *)obj);
|
24
|
+
*/
|
25
|
+
|
26
|
+
#define ZmqReturnNilUnlessOwned(wrapper) if (wrapper && (wrapper->flags & ZMQ_MESSAGE_OWNED) == 0) { \
|
27
|
+
return Qnil; \
|
28
|
+
}
|
29
|
+
|
30
|
+
#define ZmqAssertMessageOwned(wrapper) if (wrapper && (wrapper->flags & ZMQ_MESSAGE_OWNED) == 0) { \
|
31
|
+
rb_raise(rb_eTypeError, "Cannot modify a message that is gone."); \
|
32
|
+
}
|
18
33
|
|
19
34
|
VALUE rb_czmq_alloc_message(zmsg_t *message);
|
20
35
|
void rb_czmq_free_message(zmq_message_wrapper *message);
|
36
|
+
void rb_czmq_mark_message(zmq_message_wrapper *message);
|
21
37
|
|
22
38
|
void _init_rb_czmq_message();
|
23
39
|
|
data/ext/rbczmq/pollitem.c
CHANGED
@@ -250,4 +250,4 @@ void _init_rb_czmq_pollitem()
|
|
250
250
|
rb_define_method(rb_cZmqPollitem, "handler", rb_czmq_pollitem_handler, 0);
|
251
251
|
rb_define_method(rb_cZmqPollitem, "handler=", rb_czmq_pollitem_handler_equals, 1);
|
252
252
|
rb_define_method(rb_cZmqPollitem, "verbose=", rb_czmq_pollitem_set_verbose, 1);
|
253
|
-
}
|
253
|
+
}
|
data/ext/rbczmq/rbczmq_ext.c
CHANGED
@@ -25,8 +25,6 @@ VALUE rb_cZmqPoller;
|
|
25
25
|
VALUE rb_cZmqPollitem;
|
26
26
|
VALUE rb_cZmqBeacon;
|
27
27
|
|
28
|
-
st_table *frames_map = NULL;
|
29
|
-
|
30
28
|
VALUE intern_call;
|
31
29
|
VALUE intern_readable;
|
32
30
|
VALUE intern_writable;
|
@@ -216,8 +214,6 @@ static VALUE rb_czmq_m_proxy(int argc, VALUE *argv, ZMQ_UNUSED VALUE klass)
|
|
216
214
|
|
217
215
|
void Init_rbczmq_ext()
|
218
216
|
{
|
219
|
-
frames_map = st_init_numtable();
|
220
|
-
|
221
217
|
intern_call = rb_intern("call");
|
222
218
|
intern_readable = rb_intern("on_readable");
|
223
219
|
intern_writable = rb_intern("on_writable");
|
data/ext/rbczmq/rbczmq_ext.h
CHANGED
data/ext/rbczmq/socket.c
CHANGED
@@ -229,7 +229,7 @@ static VALUE rb_czmq_socket_bind(VALUE obj, VALUE endpoint)
|
|
229
229
|
args.endpoint = StringValueCStr(endpoint);
|
230
230
|
rc = (int)rb_thread_blocking_region(rb_czmq_nogvl_socket_bind, (void *)&args, RUBY_UBF_IO, 0);
|
231
231
|
/* ZmqAssert will return false on any non-zero return code. Bind returns the port number */
|
232
|
-
if (rc < 0) {
|
232
|
+
if (rc < 0) {
|
233
233
|
ZmqAssert(rc);
|
234
234
|
}
|
235
235
|
if (sock->verbose)
|
@@ -562,6 +562,7 @@ static VALUE rb_czmq_socket_send_frame(int argc, VALUE *argv, VALUE obj)
|
|
562
562
|
ZmqSockGuardCrossThread(sock);
|
563
563
|
rb_scan_args(argc, argv, "11", &frame_obj, &flags);
|
564
564
|
ZmqGetFrame(frame_obj);
|
565
|
+
ZmqAssertFrameOwnedNoMessage(frame);
|
565
566
|
|
566
567
|
if (NIL_P(flags)) {
|
567
568
|
flgs = 0;
|
@@ -573,13 +574,17 @@ static VALUE rb_czmq_socket_send_frame(int argc, VALUE *argv, VALUE obj)
|
|
573
574
|
|
574
575
|
if (sock->verbose) {
|
575
576
|
cur_time = rb_czmq_formatted_current_time();
|
576
|
-
print_frame = (flgs & ZFRAME_REUSE) ? frame : zframe_dup(frame);
|
577
|
+
print_frame = (flgs & ZFRAME_REUSE) ? frame->frame : zframe_dup(frame->frame);
|
577
578
|
}
|
578
579
|
args.socket = sock;
|
579
|
-
args.frame = frame;
|
580
|
+
args.frame = frame->frame;
|
580
581
|
args.flags = flgs;
|
581
582
|
rc = (int)rb_thread_blocking_region(rb_czmq_nogvl_send_frame, (void *)&args, RUBY_UBF_IO, 0);
|
582
583
|
ZmqAssert(rc);
|
584
|
+
if ((flgs & ZFRAME_REUSE) == 0) {
|
585
|
+
/* frame has been destroyed, clear the owns flag */
|
586
|
+
frame->flags &= ~ZMQ_FRAME_OWNED;
|
587
|
+
}
|
583
588
|
if (sock->verbose) ZmqDumpFrame("send_frame", print_frame);
|
584
589
|
return Qtrue;
|
585
590
|
}
|
@@ -623,11 +628,12 @@ static VALUE rb_czmq_socket_send_message(VALUE obj, VALUE message_obj)
|
|
623
628
|
ZmqAssertSocketNotPending(sock, "can only send on a bound or connected socket!");
|
624
629
|
ZmqSockGuardCrossThread(sock);
|
625
630
|
ZmqGetMessage(message_obj);
|
631
|
+
ZmqAssertMessageOwned(message);
|
626
632
|
if (sock->verbose) print_message = zmsg_dup(message->message);
|
627
633
|
args.socket = sock;
|
628
634
|
args.message = message->message;
|
629
635
|
rb_thread_blocking_region(rb_czmq_nogvl_send_message, (void *)&args, RUBY_UBF_IO, 0);
|
630
|
-
message->flags
|
636
|
+
message->flags &= ~ZMQ_MESSAGE_OWNED;
|
631
637
|
if (sock->verbose) ZmqDumpMessage("send_message", print_message);
|
632
638
|
return Qnil;
|
633
639
|
}
|
@@ -1652,7 +1658,7 @@ static VALUE rb_czmq_socket_monitor_thread(void *arg)
|
|
1652
1658
|
|
1653
1659
|
args.monitored_socket_wrapper = sock;
|
1654
1660
|
args.socket = s;
|
1655
|
-
|
1661
|
+
|
1656
1662
|
while (1) {
|
1657
1663
|
zmq_msg_init (&args.msg);
|
1658
1664
|
rc = (int)rb_thread_blocking_region(rb_czmq_nogvl_monitor_recv, (void *)&args, RUBY_UBF_IO, 0);
|
data/lib/zmq.rb
CHANGED
data/lib/zmq/logger.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'logger'
|
4
|
+
|
5
|
+
module ZMQ
|
6
|
+
|
7
|
+
# A logging class that sends its output to a ZMQ socket. This allows log messages to be sent
|
8
|
+
# asynchronously to another process and across a network if required. The receiving socket
|
9
|
+
# will receive messages, each with text of one log message.
|
10
|
+
#
|
11
|
+
# Example usage:
|
12
|
+
#
|
13
|
+
# socket = context.socket(ZMQ::PUSH)
|
14
|
+
# socket.connect("tcp://logserver:5555")
|
15
|
+
# logger = ZMQ::Logger.new(socket)
|
16
|
+
# logger.debug("Hello logger")
|
17
|
+
#
|
18
|
+
class Logger < ::Logger
|
19
|
+
|
20
|
+
class InvalidSocketError < ZMQ::Error ; end
|
21
|
+
|
22
|
+
# only these socket classes are allowed to be used for sending
|
23
|
+
VALID_SOCKET_CLASSES = [
|
24
|
+
Socket::Pub,
|
25
|
+
Socket::Push,
|
26
|
+
Socket::Pair
|
27
|
+
]
|
28
|
+
|
29
|
+
# Initialise a new logger object. The logger sends log messages to a socket.
|
30
|
+
# The caller is responsible for connecting the socket before using the logger to
|
31
|
+
# send log output to the socket.
|
32
|
+
#
|
33
|
+
# Supported socket types are a Socket::Pub, Socket::Push, and Socket::Pair
|
34
|
+
def initialize(socket)
|
35
|
+
raise InvalidSocketError unless VALID_SOCKET_CLASSES.any? { |klass| socket.is_a?(klass) }
|
36
|
+
super(nil)
|
37
|
+
@logdev = LogDevice.new(socket)
|
38
|
+
end
|
39
|
+
|
40
|
+
# implements an interface similar to ::Logger::LogDevice. This is the recipient of the
|
41
|
+
# formatted log messages
|
42
|
+
class LogDevice
|
43
|
+
# :nodoc:
|
44
|
+
def initialize(socket)
|
45
|
+
@socket = socket
|
46
|
+
end
|
47
|
+
|
48
|
+
# write the formatted log message to the socket.
|
49
|
+
def write(message)
|
50
|
+
@socket.send(message)
|
51
|
+
end
|
52
|
+
|
53
|
+
def close
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
data/lib/zmq/version.rb
CHANGED
data/test/test_frame.rb
CHANGED
data/test/test_logger.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require File.join(File.dirname(__FILE__), 'helper')
|
4
|
+
|
5
|
+
class TestZmqLogger < ZmqTestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@ctx = ZMQ::Context.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def teardown
|
12
|
+
@ctx.destroy
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_invalid_socket
|
16
|
+
socket = @ctx.socket(ZMQ::REQ)
|
17
|
+
assert_raises ZMQ::Logger::InvalidSocketError do
|
18
|
+
ZMQ::Logger.new(socket)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_valid_socket
|
23
|
+
socket = @ctx.socket(ZMQ::PUSH)
|
24
|
+
assert_nothing_raised do
|
25
|
+
ZMQ::Logger.new(socket)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_send_message
|
30
|
+
reader = @ctx.socket(ZMQ::PULL)
|
31
|
+
port = reader.bind("tcp://*:*")
|
32
|
+
assert port > 0
|
33
|
+
writer = @ctx.socket(ZMQ::PUSH)
|
34
|
+
writer.connect("tcp://localhost:#{port}")
|
35
|
+
logger = ZMQ::Logger.new(writer)
|
36
|
+
assert logger.debug("hellö world")
|
37
|
+
message = reader.recv.force_encoding Encoding::UTF_8
|
38
|
+
assert_not_nil message =~ /hellö world/
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
data/test/test_message.rb
CHANGED
@@ -11,10 +11,11 @@ class TestZmqMessage < ZmqTestCase
|
|
11
11
|
|
12
12
|
def test_destroyed
|
13
13
|
msg = ZMQ::Message("one", "two")
|
14
|
+
assert_not_nil msg.encode
|
15
|
+
assert !msg.gone?
|
14
16
|
msg.destroy
|
15
|
-
|
16
|
-
|
17
|
-
end
|
17
|
+
assert msg.gone?
|
18
|
+
assert_nil msg.encode
|
18
19
|
end
|
19
20
|
|
20
21
|
def test_message_sugar
|
@@ -182,7 +183,7 @@ class TestZmqMessage < ZmqTestCase
|
|
182
183
|
end
|
183
184
|
|
184
185
|
def test_equals
|
185
|
-
msg =
|
186
|
+
msg = ZMQ::Message.new
|
186
187
|
msg.pushstr "body"
|
187
188
|
msg.pushstr "header"
|
188
189
|
|
@@ -198,4 +199,96 @@ class TestZmqMessage < ZmqTestCase
|
|
198
199
|
assert !msg.eql?(other)
|
199
200
|
assert other.eql?(other)
|
200
201
|
end
|
201
|
-
|
202
|
+
|
203
|
+
def test_message_with_frames
|
204
|
+
msg = ZMQ::Message.new
|
205
|
+
frame = ZMQ::Frame.new("hello")
|
206
|
+
assert_equal "hello", frame.data
|
207
|
+
msg.add frame
|
208
|
+
# frame is owned by message, but message is still owned by ruby,
|
209
|
+
# so the frame data should still be accessible:
|
210
|
+
assert_equal "hello", frame.data
|
211
|
+
end
|
212
|
+
|
213
|
+
def test_messge_add_frame_twice
|
214
|
+
msg = ZMQ::Message.new
|
215
|
+
frame = ZMQ::Frame.new("hello")
|
216
|
+
msg.add frame
|
217
|
+
assert_raises ZMQ::Error do
|
218
|
+
msg.add frame
|
219
|
+
end
|
220
|
+
end
|
221
|
+
|
222
|
+
def test_message_is_gone_after_send
|
223
|
+
ctx = ZMQ::Context.new
|
224
|
+
endpoint = "inproc://test.test_message_is_gone_after_send"
|
225
|
+
push = ctx.bind(:PUSH, endpoint)
|
226
|
+
pull = ctx.connect(:PULL, endpoint)
|
227
|
+
msg = ZMQ::Message.new
|
228
|
+
frame = ZMQ::Frame.new("hello")
|
229
|
+
msg.add frame
|
230
|
+
push.send_message(msg)
|
231
|
+
assert msg.gone?
|
232
|
+
assert frame.gone?
|
233
|
+
ensure
|
234
|
+
ctx.destroy
|
235
|
+
end
|
236
|
+
|
237
|
+
def test_message_has_frames_on_receive
|
238
|
+
ctx = ZMQ::Context.new
|
239
|
+
endpoint = "inproc://test.test_message_is_gone_after_send"
|
240
|
+
push = ctx.bind(:PUSH, endpoint)
|
241
|
+
pull = ctx.connect(:PULL, endpoint)
|
242
|
+
msg = ZMQ::Message.new
|
243
|
+
msg.add ZMQ::Frame.new("hello")
|
244
|
+
msg.add ZMQ::Frame.new("world")
|
245
|
+
push.send_message(msg)
|
246
|
+
received = pull.recv_message
|
247
|
+
assert_not_nil received
|
248
|
+
assert_equal 2, received.size
|
249
|
+
assert_equal "hello", received.first.data
|
250
|
+
assert_equal "world", received.next.data
|
251
|
+
ensure
|
252
|
+
ctx.destroy
|
253
|
+
end
|
254
|
+
|
255
|
+
def test_message_remove_frame
|
256
|
+
msg = ZMQ::Message.new
|
257
|
+
frame = ZMQ::Frame.new("hello")
|
258
|
+
msg.add frame
|
259
|
+
assert_equal 1, msg.size
|
260
|
+
# same object is returned
|
261
|
+
assert_equal frame.object_id, msg.first.object_id
|
262
|
+
msg.remove frame
|
263
|
+
assert_equal 0, msg.size
|
264
|
+
end
|
265
|
+
|
266
|
+
def test_message_array_same_frame_objects
|
267
|
+
msg = ZMQ::Message.new
|
268
|
+
frame = ZMQ::Frame.new("hello")
|
269
|
+
msg.add frame
|
270
|
+
ary = msg.to_a
|
271
|
+
assert_equal 1, ary.count
|
272
|
+
assert_equal frame, ary.first
|
273
|
+
assert_equal frame.object_id, ary.first.object_id
|
274
|
+
end
|
275
|
+
|
276
|
+
def test_message_unwrap_dup
|
277
|
+
ctx = ZMQ::Context.new
|
278
|
+
router = ctx.socket(ZMQ::ROUTER)
|
279
|
+
port = router.bind("tcp://127.0.0.1:*")
|
280
|
+
req = ctx.connect(ZMQ::REQ, "tcp://127.0.0.1:#{port}")
|
281
|
+
msg = ZMQ::Message.new
|
282
|
+
msg.addstr "hello world"
|
283
|
+
req.send_message msg
|
284
|
+
msg2 = router.recv_message
|
285
|
+
identity = msg2.unwrap
|
286
|
+
assert_equal "hello world", msg2.first.data
|
287
|
+
msg3 = ZMQ::Message.new
|
288
|
+
msg3.addstr "reply"
|
289
|
+
msg3.wrap identity.dup
|
290
|
+
assert_equal 3, msg3.size
|
291
|
+
ensure
|
292
|
+
ctx.destroy
|
293
|
+
end
|
294
|
+
end
|
metadata
CHANGED
@@ -1,8 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rbczmq
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
5
|
-
prerelease:
|
4
|
+
version: 1.7.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Lourens Naudé
|
@@ -11,12 +10,11 @@ authors:
|
|
11
10
|
autorequire:
|
12
11
|
bindir: bin
|
13
12
|
cert_chain: []
|
14
|
-
date: 2013-07-
|
13
|
+
date: 2013-07-21 00:00:00.000000000 Z
|
15
14
|
dependencies:
|
16
15
|
- !ruby/object:Gem::Dependency
|
17
16
|
name: rake-compiler
|
18
17
|
requirement: !ruby/object:Gem::Requirement
|
19
|
-
none: false
|
20
18
|
requirements:
|
21
19
|
- - ~>
|
22
20
|
- !ruby/object:Gem::Version
|
@@ -24,7 +22,6 @@ dependencies:
|
|
24
22
|
type: :development
|
25
23
|
prerelease: false
|
26
24
|
version_requirements: !ruby/object:Gem::Requirement
|
27
|
-
none: false
|
28
25
|
requirements:
|
29
26
|
- - ~>
|
30
27
|
- !ruby/object:Gem::Version
|
@@ -86,6 +83,7 @@ files:
|
|
86
83
|
- lib/zmq/default_handler.rb
|
87
84
|
- lib/zmq/frame.rb
|
88
85
|
- lib/zmq/handler.rb
|
86
|
+
- lib/zmq/logger.rb
|
89
87
|
- lib/zmq/loop.rb
|
90
88
|
- lib/zmq/message.rb
|
91
89
|
- lib/zmq/monitor.rb
|
@@ -136,6 +134,7 @@ files:
|
|
136
134
|
- test/test_context.rb
|
137
135
|
- test/test_frame.rb
|
138
136
|
- test/test_handler.rb
|
137
|
+
- test/test_logger.rb
|
139
138
|
- test/test_loop.rb
|
140
139
|
- test/test_message.rb
|
141
140
|
- test/test_monitoring.rb
|
@@ -529,28 +528,27 @@ files:
|
|
529
528
|
- ext/zeromq/version.sh
|
530
529
|
homepage: http://github.com/methodmissing/rbczmq
|
531
530
|
licenses: []
|
531
|
+
metadata: {}
|
532
532
|
post_install_message:
|
533
533
|
rdoc_options:
|
534
534
|
- --charset=UTF-8
|
535
535
|
require_paths:
|
536
536
|
- lib
|
537
537
|
required_ruby_version: !ruby/object:Gem::Requirement
|
538
|
-
none: false
|
539
538
|
requirements:
|
540
539
|
- - ! '>='
|
541
540
|
- !ruby/object:Gem::Version
|
542
541
|
version: '0'
|
543
542
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
544
|
-
none: false
|
545
543
|
requirements:
|
546
544
|
- - ! '>='
|
547
545
|
- !ruby/object:Gem::Version
|
548
546
|
version: '0'
|
549
547
|
requirements: []
|
550
548
|
rubyforge_project:
|
551
|
-
rubygems_version:
|
549
|
+
rubygems_version: 2.0.3
|
552
550
|
signing_key:
|
553
|
-
specification_version:
|
551
|
+
specification_version: 4
|
554
552
|
summary: Ruby extension for ZeroMQ (ZMQ) using CZMQ - High-level C Binding for ØMQ
|
555
553
|
(http://czmq.zeromq.org)
|
556
554
|
test_files:
|
@@ -573,6 +571,7 @@ test_files:
|
|
573
571
|
- test/test_context.rb
|
574
572
|
- test/test_frame.rb
|
575
573
|
- test/test_handler.rb
|
574
|
+
- test/test_logger.rb
|
576
575
|
- test/test_loop.rb
|
577
576
|
- test/test_message.rb
|
578
577
|
- test/test_monitoring.rb
|
@@ -582,4 +581,3 @@ test_files:
|
|
582
581
|
- test/test_threading.rb
|
583
582
|
- test/test_timer.rb
|
584
583
|
- test/test_zmq.rb
|
585
|
-
has_rdoc: true
|