rbczmq 1.6.4 → 1.7.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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=
@@ -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
 
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rbczmq (1.6.2)
4
+ rbczmq (1.7.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
@@ -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
+ }
@@ -35,4 +35,4 @@ struct nogvl_beacon_subscribe_args {
35
35
 
36
36
  void _init_rb_czmq_beacon();
37
37
 
38
- #endif
38
+ #endif
@@ -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
- ZmqRegisterFrame(frame);
26
- frame_obj = Data_Wrap_Struct(rb_cZmqFrame, 0, rb_czmq_free_frame_gc, frame);
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(zframe_t *frame)
29
+ void rb_czmq_free_frame(zmq_frame_wrapper *frame)
39
30
  {
40
- if (frame) {
41
- if (st_lookup(frames_map, (st_data_t)frame, 0)) {
42
- st_delete(frames_map, (st_data_t*)&frame, 0);
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
- zframe_t *frame = (zframe_t *)ptr;
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
- ZmqRegisterFrame(fr);
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
- size = zframe_size(frame);
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
- size = zframe_size(frame);
152
- return ZmqEncode(rb_str_new((char *)zframe_data(frame), (long)size));
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
- return rb_str_new2(zframe_strhex(frame));
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
- dup_fr = zframe_dup(frame);
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
- ZmqRegisterFrame(dup_fr);
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
- return (zframe_more(frame) == ZFRAME_MORE) ? Qtrue : Qfalse;
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
- zframe_t *other = NULL;
259
+ zmq_frame_wrapper *other = NULL;
272
260
  ZmqGetFrame(obj);
261
+ ZmqAssertFrameOwned(frame);
273
262
  ZmqAssertFrame(other_frame);
274
- Data_Get_Struct(other_frame, zframe_t, other);
275
- if (!other) rb_raise(rb_eTypeError, "uninitialized ZMQ frame!"); \
276
- if (!(st_lookup(frames_map, (st_data_t)other, 0))) rb_raise(rb_eZmqError, "object %p has been destroyed by the ZMQ framework", (void *)other_frame);
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
- zframe_t *other = NULL;
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, zframe_t, other);
321
- if (!other) rb_raise(rb_eTypeError, "uninitialized ZMQ frame!"); \
322
- if (!(st_lookup(frames_map, (st_data_t)other, 0))) rb_raise(rb_eZmqError, "object %p has been destroyed by the ZMQ framework", (void *)other_frame);
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
  }
@@ -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
- zframe_t *frame = NULL; \
24
+ zmq_frame_wrapper *frame = NULL; \
7
25
  ZmqAssertFrame(obj); \
8
- Data_Get_Struct(obj, zframe_t, frame); \
9
- if (!frame) rb_raise(rb_eTypeError, "uninitialized ZMQ frame!"); \
10
- if (!(st_lookup(frames_map, (st_data_t)frame, 0))) rb_raise(rb_eZmqError, "ZMQ::Frame instance %p has been destroyed by the ZMQ framework", (void *)obj);
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 ZmqRegisterFrame(fr) \
13
- zframe_freefn((fr), (zframe_free_fn *)rb_czmq_frame_freed, NULL); \
14
- st_insert(frames_map, (st_data_t)(fr), (st_data_t)0);
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(zframe_t *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
 
@@ -8,9 +8,12 @@
8
8
  void rb_czmq_free_message(zmq_message_wrapper *message)
9
9
  {
10
10
  errno = 0;
11
- zmsg_destroy(&message->message);
12
- message->message = NULL;
13
- message->flags |= ZMQ_MESSAGE_DESTROYED;
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
- if (msg->message != NULL && !(msg->flags & ZMQ_MESSAGE_DESTROYED)) rb_czmq_free_message(msg);
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 = 0;
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
- zmq_message_wrapper *msg = NULL;
62
- errno = 0;
63
- message = Data_Make_Struct(rb_cZmqMessage, zmq_message_wrapper, 0, rb_czmq_free_message_gc, msg);
64
- msg->message = zmsg_new();
65
- ZmqAssertObjOnAlloc(msg->message, msg);
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
- rc = zmsg_push(message->message, frame);
162
+ ZmqAssertFrameOwnedNoMessage(frame);
163
+
164
+ rc = zmsg_push(message->message, frame->frame);
132
165
  ZmqAssert(rc);
133
- rb_czmq_frame_freed(frame);
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
- rc = zmsg_add(message->message, frame);
193
+ ZmqAssertFrameOwnedNoMessage(frame);
194
+
195
+ rc = zmsg_add(message->message, frame->frame);
158
196
  ZmqAssert(rc);
159
- rb_czmq_frame_freed(frame);
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
- frame = zmsg_pop(message->message);
222
+ ZmqAssertMessageOwned(message);
223
+ frame = zmsg_pop(message->message); /* we now own the frame */
183
224
  if (frame == NULL) return Qnil;
184
- return rb_czmq_alloc_frame(frame);
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
- frame = zmsg_first(message->message);
226
- if (frame == NULL) return Qnil;
227
- return rb_czmq_alloc_frame(zframe_dup(frame));
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
- frame = zmsg_next(message->message);
250
- if (frame == NULL) return Qnil;
251
- return rb_czmq_alloc_frame(zframe_dup(frame));
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
- frame = zmsg_last(message->message);
273
- if (frame == NULL) return Qnil;
274
- return rb_czmq_alloc_frame(zframe_dup(frame));
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
- zframe_t *frame = NULL;
297
- ZmqAssertFrame(frame_obj);
298
- Data_Get_Struct(frame_obj, zframe_t, frame);
299
- zmsg_remove(message->message, frame);
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
- ZmqGetFrame(frame_obj);
390
- zmsg_wrap(message->message, frame);
391
- rb_czmq_frame_freed(frame);
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
- frame = zmsg_unwrap(message->message);
416
- if (frame == NULL) return Qnil;
417
- return rb_czmq_alloc_frame(frame);
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
- dup = Data_Make_Struct(rb_cZmqMessage, zmq_message_wrapper, 0, rb_czmq_free_message_gc, dup_msg);
439
- dup_msg->message = zmsg_dup(message->message);
440
- ZmqAssertObjOnAlloc(dup_msg->message, dup_msg);
441
- dup_msg->flags = message->flags;
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
- ary = rb_ary_new2(zmsg_size(message->message));
584
- zframe_t *frame = zmsg_first(message->message);
585
- while (frame) {
586
- rb_ary_push(ary, rb_czmq_alloc_frame(zframe_dup(frame)));
587
- frame = zmsg_next(message->message);
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
  }
@@ -1,11 +1,15 @@
1
1
  #ifndef RBCZMQ_MESSAGE_H
2
2
  #define RBCZMQ_MESSAGE_H
3
3
 
4
- #define ZMQ_MESSAGE_DESTROYED 0x01
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
 
@@ -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
+ }
@@ -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");
@@ -75,8 +75,6 @@ extern VALUE rb_cZmqPoller;
75
75
  extern VALUE rb_cZmqPollitem;
76
76
  extern VALUE rb_cZmqBeacon;
77
77
 
78
- extern st_table *frames_map;
79
-
80
78
  extern VALUE intern_call;
81
79
  extern VALUE intern_readable;
82
80
  extern VALUE intern_writable;
@@ -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 |= ZMQ_MESSAGE_DESTROYED;
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
@@ -82,4 +82,5 @@ require "zmq/timer"
82
82
  require "zmq/frame"
83
83
  require "zmq/message"
84
84
  require "zmq/poller"
85
- require "zmq/pollitem"
85
+ require "zmq/pollitem"
86
+ require "zmq/logger"
@@ -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
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module ZMQ
4
- VERSION = "1.6.4"
5
- end
4
+ VERSION = "1.7.0"
5
+ end
@@ -11,10 +11,9 @@ class TestZmqFrame < ZmqTestCase
11
11
 
12
12
  def test_destroyed_frame
13
13
  frame = ZMQ::Frame("message")
14
+ assert !frame.gone?
14
15
  frame.destroy
15
- assert_raises ZMQ::Error do
16
- frame.data
17
- end
16
+ assert frame.gone?
18
17
  end
19
18
 
20
19
  def test_alloc_empty
@@ -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
@@ -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
- assert_raises ZMQ::Error do
16
- msg.encode
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 = ZMQ::Message.new
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
- end
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.6.4
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-09 00:00:00.000000000 Z
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: 1.8.24
549
+ rubygems_version: 2.0.3
552
550
  signing_key:
553
- specification_version: 3
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