zyre 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 5946a8a32c3932017f3c6fc60d6a54e3a2196a5e193a769975a1c4b47cbb405e
4
+ data.tar.gz: 5e51339b1fbc508dd0de7f3abc921aa7c2912cc243fda3a059d9057648c6acb9
5
+ SHA512:
6
+ metadata.gz: 5177153a30ea6f2f28ebfb7372e3055a51ec793ea5a5bd51c3afde8b41ba1909b88a5daae334ab5fd52db9858e10b1f0184e7a4f566f7f8ee7240311748e1ab4
7
+ data.tar.gz: 61057878f14e360a57bf233ee5649dec9659686090d20f72461fcb955e387fa204e1afdcbadb8b5112e517a64547a27df5aa18eeea2706a9d65221724fbc89a5
@@ -0,0 +1,2 @@
1
+ b��
2
+ ��ˑ�}�d��ܐk���B܆����le��Kt��'���J�~� �����Bf�4�xIЛx�(�Z9� s�L�a��f��|c у��)�'�}w���Ij�v
Binary file
@@ -0,0 +1,8 @@
1
+ # Release History for zyre
2
+
3
+ ---
4
+
5
+ ## v0.1.0 [2020-11-05] Michael Granger <ged@faeriemud.org>
6
+
7
+ First release.
8
+
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2020 Ravn Group
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,104 @@
1
+ # Ruby Zyre
2
+
3
+ home
4
+ : https://gitlab.com/ravngroup/open-source/ruby-zyre
5
+
6
+ code
7
+ : https://gitlab.com/ravngroup/open-source/ruby-zyre/-/tree/master
8
+
9
+ github
10
+ : https://github.com/ged/ruby-zyre
11
+
12
+ docs
13
+ : https://deveiate.org/code/zyre
14
+
15
+
16
+ ## Description
17
+
18
+ A ZRE library for Ruby. This is a Ruby (MRI) binding for the Zyre library for
19
+ reliable group messaging over local area networks, an implementation of [the ZeroMQ Realtime Exchange protocol][ZRE].
20
+
21
+
22
+ ### Examples
23
+
24
+ # Join the Zyre network on the network associated with the given interface
25
+ # and dump events from the 'global' group to stderr.
26
+ node = Zyre::Node.new
27
+ node.interface = 'igb0'
28
+ node.start
29
+
30
+ while event = node.recv
31
+ event.print
32
+ end
33
+
34
+
35
+ ### To-Do
36
+
37
+ * Implement Zyre::Node#peer_groups and Zyre::Node#peer_address
38
+ * Implement the draft API methods on Zyre::Node
39
+ * Hook up logging via `zsys_set_logsender`
40
+ * Add richer matching to Zyre::Event#match.
41
+
42
+ ## Prerequisites
43
+
44
+ * Ruby 2.7+
45
+ * Zyre (https://github.com/zeromq/zyre)
46
+
47
+
48
+ ## Installation
49
+
50
+ $ gem install zyre
51
+
52
+
53
+ ## Contributing
54
+
55
+ You can check out the current development source with Mercurial via its
56
+ [project page](https://gitlab.com/ravngroup/open-source/ruby-zyre).
57
+
58
+ After checking out the source, run:
59
+
60
+ $ gem install -Ng
61
+ $ rake setup
62
+
63
+ This will install dependencies, and do any other necessary setup for
64
+ development.
65
+
66
+
67
+ ## Authors
68
+
69
+ - Michael Granger <ged@faeriemud.org>
70
+
71
+
72
+ ## License
73
+
74
+ Copyright (c) 2020, Ravn Group
75
+ All rights reserved.
76
+
77
+ Redistribution and use in source and binary forms, with or without
78
+ modification, are permitted provided that the following conditions are met:
79
+
80
+ * Redistributions of source code must retain the above copyright notice,
81
+ this list of conditions and the following disclaimer.
82
+
83
+ * Redistributions in binary form must reproduce the above copyright notice,
84
+ this list of conditions and the following disclaimer in the documentation
85
+ and/or other materials provided with the distribution.
86
+
87
+ * Neither the name of the author/s, nor the names of the project's
88
+ contributors may be used to endorse or promote products derived from this
89
+ software without specific prior written permission.
90
+
91
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
92
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
93
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
94
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
95
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
96
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
97
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
98
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
99
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
100
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
101
+
102
+
103
+ [ZRE]: https://rfc.zeromq.org/spec/36/
104
+
@@ -0,0 +1,479 @@
1
+ /*
2
+ * event.c - An event for or from a Zyre cluster
3
+ * $Id$
4
+ *
5
+ * Authors:
6
+ * * Michael Granger <ged@FaerieMUD.org>
7
+ *
8
+ */
9
+
10
+ #include "zyre_ext.h"
11
+
12
+ VALUE rzyre_cZyreEvent;
13
+
14
+
15
+ static void rzyre_event_free( void *ptr );
16
+
17
+ static const rb_data_type_t rzyre_event_t = {
18
+ "Zyre::Event",
19
+ {
20
+ NULL,
21
+ rzyre_event_free
22
+ },
23
+ 0,
24
+ 0,
25
+ RUBY_TYPED_FREE_IMMEDIATELY,
26
+ };
27
+
28
+
29
+ /*
30
+ * Free function
31
+ */
32
+ static void
33
+ rzyre_event_free( void *ptr )
34
+ {
35
+ if ( ptr ) {
36
+ zyre_event_destroy( (zyre_event_t **)&ptr );
37
+ }
38
+ }
39
+
40
+
41
+ /*
42
+ * Alloc function
43
+ */
44
+ static VALUE
45
+ rzyre_event_alloc( VALUE klass )
46
+ {
47
+ return TypedData_Wrap_Struct( klass, &rzyre_event_t, NULL );
48
+ }
49
+
50
+
51
+ /*
52
+ * Fetch the data pointer and check it for sanity.
53
+ */
54
+ static inline zyre_event_t *
55
+ rzyre_get_event( VALUE self )
56
+ {
57
+ zyre_event_t *ptr;
58
+
59
+ if ( !IsZyreEvent(self) ) {
60
+ rb_raise( rb_eTypeError, "wrong argument type %s (expected Zyre::Event)",
61
+ rb_class2name(CLASS_OF( self )) );
62
+ }
63
+
64
+ ptr = DATA_PTR( self );
65
+ assert( ptr );
66
+
67
+ return ptr;
68
+ }
69
+
70
+
71
+ /*
72
+ * Async read function; called without the GVL.
73
+ */
74
+ static void *
75
+ rzyre_read_event( void *node_ptr )
76
+ {
77
+ zyre_event_t *event_ptr;
78
+ assert( node_ptr );
79
+
80
+ event_ptr = zyre_event_new( (zyre_t *)node_ptr );
81
+ assert( event_ptr );
82
+ return (void *)event_ptr;
83
+ }
84
+
85
+
86
+ /*
87
+ * call-seq:
88
+ * Zyre::Event.from_node( node ) -> event
89
+ *
90
+ * Read the next event from the given Zyre::Node and wrap it in a Zyre::Event.
91
+ *
92
+ */
93
+ static VALUE
94
+ rzyre_event_s_from_node( VALUE klass, VALUE node )
95
+ {
96
+ zyre_t *node_ptr = rzyre_get_node( node );
97
+ zyre_event_t *event;
98
+
99
+ assert( node_ptr );
100
+
101
+ event = rb_thread_call_without_gvl2( rzyre_read_event, (void *)node_ptr, RUBY_UBF_IO, 0 );
102
+
103
+ if ( event ) {
104
+ const char *event_type = zyre_event_type( event );
105
+ VALUE event_type_s = rb_utf8_str_new_cstr( event_type );
106
+ VALUE event_class = rb_funcall( klass, rb_intern("type_by_name"), 1, event_type_s );
107
+ VALUE event_instance = rb_class_new_instance( 0, NULL, event_class );
108
+
109
+ RTYPEDDATA_DATA( event_instance ) = event;
110
+
111
+ return event_instance;
112
+ } else {
113
+ return Qnil;
114
+ }
115
+ }
116
+
117
+
118
+ char *
119
+ rzyre_copy_string( VALUE string )
120
+ {
121
+ const char *c_string = StringValueCStr( string );
122
+ char *copy = (char *) zmalloc( strnlen(c_string, BUFSIZ) + 1 );
123
+
124
+ assert( copy );
125
+ stpncpy( copy, c_string, strnlen(c_string, BUFSIZ) + 1 );
126
+
127
+ return copy;
128
+ }
129
+
130
+
131
+ char *
132
+ rzyre_copy_required_string( VALUE string, const char *field_name )
133
+ {
134
+ if ( RB_TYPE_P(string, T_UNDEF) ) {
135
+ rb_raise( rb_eArgError, "missing required field :%s", field_name );
136
+ } else {
137
+ return rzyre_copy_string( string );
138
+ }
139
+ }
140
+
141
+
142
+ static int
143
+ rzyre_zhash_from_rhash_i( VALUE key, VALUE value, VALUE zhash_ptr )
144
+ {
145
+ zhash_t *zhash = (zhash_t *)zhash_ptr;
146
+
147
+ zhash_insert( zhash, StringValueCStr(key), StringValueCStr(value) );
148
+
149
+ return ST_CONTINUE;
150
+ }
151
+
152
+
153
+ static zhash_t *
154
+ rzyre_zhash_from_rhash( VALUE ruby_hash )
155
+ {
156
+ zhash_t *zhash = zhash_new();
157
+
158
+ // If it was passed, it should be a Hash
159
+ // :FIXME: Allow anything that ducktypes with :each_pair?
160
+ if ( !RB_TYPE_P(ruby_hash, T_UNDEF) ) {
161
+ Check_Type( ruby_hash, T_HASH );
162
+ rb_hash_foreach( ruby_hash, rzyre_zhash_from_rhash_i, (VALUE)zhash );
163
+ }
164
+
165
+ return zhash;
166
+ }
167
+
168
+
169
+ /*
170
+ * call-seq:
171
+ * Zyre::Event.synthesized( type, peer_uuid, **fields ) -> event
172
+ *
173
+ * Create an event in memory without going through a Zyre::Node. This is useful for
174
+ * testing.
175
+ *
176
+ * uuid = UUID.generate
177
+ * event = Zyre::Event.synthesized( :ENTER, uuid, peer_name: 'node1' )
178
+ * expect( some_system.handle_event(event) ).to have_handled_an_enter_event
179
+ *
180
+ */
181
+ static VALUE
182
+ rzyre_event_s_synthesize( int argc, VALUE *argv, VALUE klass )
183
+ {
184
+ VALUE rval, event_type, peer_uuid, kwargs, event_class;
185
+ static VALUE kwvals[5];
186
+ static ID keyword_ids[5];
187
+ zyre_event_t *ptr = NULL;
188
+
189
+ // Parse the arguments + keyword arguments
190
+ if ( !keyword_ids[0] ) {
191
+ CONST_ID( keyword_ids[0], "peer_name");
192
+ CONST_ID( keyword_ids[1], "headers");
193
+ CONST_ID( keyword_ids[2], "peer_addr");
194
+ CONST_ID( keyword_ids[3], "group");
195
+ CONST_ID( keyword_ids[4], "msg");
196
+ }
197
+
198
+ rb_scan_args( argc, argv, "2:", &event_type, &peer_uuid, &kwargs );
199
+ if ( RTEST(kwargs) ) {
200
+ rb_get_kwargs( kwargs, keyword_ids, 0, 5, kwvals );
201
+ }
202
+
203
+ // Translate the event type argument into the appropriate class and instantiate it
204
+ event_class = rb_funcall( klass, rb_intern("type_by_name"), 1, event_type );
205
+ event_type = rb_funcall( event_class, rb_intern("type_name"), 0 );
206
+ rval = rb_class_new_instance( 0, NULL, event_class );
207
+
208
+ // Set up the zyre_event memory for the object
209
+ RTYPEDDATA_DATA( rval ) = ptr = (zyre_event_t *) zmalloc( sizeof *ptr );
210
+
211
+ // Set the values that are required for every event type
212
+ ptr->type = rzyre_copy_string( event_type );
213
+ ptr->peer_uuid = rzyre_copy_string( peer_uuid );
214
+
215
+ // Set the peer_name or default it if it wasn't specified
216
+ if ( !RB_TYPE_P(kwvals[0], T_UNDEF) ) {
217
+ ptr->peer_name = rzyre_copy_string( kwvals[0] );
218
+ } else {
219
+ ptr->peer_name = (char *) zmalloc( 2 + 6 + 1 );
220
+ assert( ptr->peer_name );
221
+ bzero( ptr->peer_name, 2 + 6 + 1 );
222
+ strncpy( ptr->peer_name, "S-", 2 );
223
+ memcpy( ptr->peer_name + 2, ptr->peer_uuid, 6 );
224
+ }
225
+
226
+ if ( streq(ptr->type, "ENTER") ) {
227
+ ptr->peer_addr = rzyre_copy_required_string( kwvals[2], "peer_addr" );
228
+ ptr->headers = rzyre_zhash_from_rhash( kwvals[1] );
229
+ }
230
+ else if ( streq(ptr->type, "JOIN") ) {
231
+ ptr->group = rzyre_copy_required_string( kwvals[3], "group" );
232
+ }
233
+ else if ( streq(ptr->type, "LEAVE") ) {
234
+ ptr->group = rzyre_copy_required_string( kwvals[3], "group" );
235
+ }
236
+ else if ( streq(ptr->type, "WHISPER") ) {
237
+ const char *msg_str = rzyre_copy_required_string( kwvals[4], "msg" );
238
+ zmsg_t *msg = zmsg_new();
239
+
240
+ zmsg_addstr( msg, msg_str );
241
+ ptr->msg = msg;
242
+ msg = NULL;
243
+ }
244
+ else if ( streq(ptr->type, "SHOUT") ) {
245
+ const char *msg_str = rzyre_copy_required_string( kwvals[4], "msg" );
246
+ zmsg_t *msg = zmsg_new();
247
+
248
+ zmsg_addstr( msg, msg_str );
249
+
250
+ ptr->group = rzyre_copy_required_string( kwvals[3], "group" );
251
+ ptr->msg = msg;
252
+ msg = NULL;
253
+ }
254
+ else if ( streq(ptr->type, "LEADER") ) {
255
+ ptr->group = rzyre_copy_required_string( kwvals[3], "group" );
256
+ }
257
+
258
+ return rval;
259
+ }
260
+
261
+
262
+ /*
263
+ * call-seq:
264
+ * event.type -> str
265
+ *
266
+ * Returns event type as a Symbol. Possible values are:
267
+ * :ENTER, :EXIT, :JOIN, :LEAVE, :EVASIVE, :WHISPER, and :SHOUT
268
+ * and for the local node: :STOP
269
+ *
270
+ */
271
+ static VALUE
272
+ rzyre_event_type( VALUE self )
273
+ {
274
+ zyre_event_t *ptr = rzyre_get_event( self );
275
+ const char *type_str = zyre_event_type( ptr );
276
+ const VALUE type = rb_str_new2( type_str );
277
+
278
+ return rb_to_symbol( type );
279
+ }
280
+
281
+
282
+ /*
283
+ * call-seq:
284
+ * event.peer_uuid -> str
285
+ *
286
+ * Return the sending peer's uuid as a string
287
+ */
288
+ static VALUE
289
+ rzyre_event_peer_uuid( VALUE self ) {
290
+ zyre_event_t *ptr = rzyre_get_event( self );
291
+ const char *uuid_str = zyre_event_peer_uuid( ptr );
292
+
293
+ return rb_str_new2( uuid_str );
294
+ }
295
+
296
+
297
+ /*
298
+ * call-seq:
299
+ * event.peer_name
300
+ *
301
+ * Return the sending peer's public name as a string
302
+ */
303
+ static VALUE
304
+ rzyre_event_peer_name( VALUE self ) {
305
+ zyre_event_t *ptr = rzyre_get_event( self );
306
+ const char *name_str = zyre_event_peer_name( ptr );
307
+
308
+ return rb_str_new2( name_str );
309
+ }
310
+
311
+
312
+ /*
313
+ * call-seq:
314
+ * event.peer_addr
315
+ *
316
+ * Return the sending peer's ipaddress as a string
317
+ */
318
+ static VALUE
319
+ rzyre_event_peer_addr( VALUE self ) {
320
+ zyre_event_t *ptr = rzyre_get_event( self );
321
+ const char *addr_str = zyre_event_peer_addr( ptr );
322
+
323
+ if ( addr_str ) {
324
+ return rb_str_new2( addr_str );
325
+ } else {
326
+ return Qnil;
327
+ }
328
+
329
+ }
330
+
331
+
332
+ /*
333
+ * call-seq:
334
+ * event.event_headers
335
+ *
336
+ * Returns the event headers, or NULL if there are none
337
+ */
338
+ static VALUE
339
+ rzyre_event_headers( VALUE self ) {
340
+ zyre_event_t *ptr = rzyre_get_event( self );
341
+ zhash_t *headers = zyre_event_headers( ptr );
342
+ VALUE rhash = rb_hash_new();
343
+ const char *key, *val;
344
+
345
+ if ( headers ) {
346
+ val = (const char *)zhash_first( headers );
347
+ while( val ) {
348
+ key = zhash_cursor( headers );
349
+ rb_hash_aset( rhash, rb_str_new2(key), rb_str_new2(val) );
350
+ val = (const char *)zhash_next( headers );
351
+ }
352
+ }
353
+
354
+ return rhash;
355
+ }
356
+
357
+
358
+ /*
359
+ * call-seq:
360
+ * event.event_header( name )
361
+ *
362
+ * Returns value of the header +name+ from the message headers
363
+ * obtained by ENTER. Return nil if no value was found.
364
+ */
365
+ static VALUE
366
+ rzyre_event_header( VALUE self, VALUE name ) {
367
+ zyre_event_t *ptr = rzyre_get_event( self );
368
+ const char *name_str = StringValueCStr( name );
369
+ const char *value_str = zyre_event_header( ptr, name_str );
370
+
371
+ if ( value_str ) {
372
+ return rb_str_new2( value_str );
373
+ } else {
374
+ return Qnil;
375
+ }
376
+ }
377
+
378
+
379
+ /*
380
+ * call-seq:
381
+ * event.event_group
382
+ *
383
+ * Returns the group name that a SHOUT event was sent to
384
+ */
385
+ static VALUE
386
+ rzyre_event_group( VALUE self ) {
387
+ zyre_event_t *ptr = rzyre_get_event( self );
388
+ const char *group_str = zyre_event_group( ptr );
389
+
390
+ if ( group_str ) {
391
+ return rb_str_new2( group_str );
392
+ } else {
393
+ return Qnil;
394
+ }
395
+ }
396
+
397
+
398
+ /*
399
+ * call-seq:
400
+ * event.event_msg
401
+ *
402
+ * Returns the incoming message payload.
403
+ */
404
+ static VALUE
405
+ rzyre_event_msg( VALUE self ) {
406
+ zyre_event_t *ptr = rzyre_get_event( self );
407
+ zmsg_t *msg = zyre_event_msg( ptr );
408
+ VALUE rval = Qnil;
409
+
410
+ // :TODO: Support multipart messages when Zyre does.
411
+ if ( msg ) {
412
+ zframe_t *frame = zmsg_first( msg );
413
+ char *str = zframe_strdup( frame );
414
+
415
+ rval = rb_utf8_str_new( str, zframe_size(frame) );
416
+ rb_obj_freeze( rval );
417
+
418
+ free( str );
419
+ }
420
+
421
+ return rval;
422
+ }
423
+
424
+
425
+ /*
426
+ * call-seq:
427
+ * event.print
428
+ *
429
+ * Print event to zsys log
430
+ */
431
+ static VALUE
432
+ rzyre_event_print( VALUE self ) {
433
+ zyre_event_t *ptr = rzyre_get_event( self );
434
+
435
+ zyre_event_print( ptr );
436
+
437
+ return Qtrue;
438
+ }
439
+
440
+
441
+ /*
442
+ * Initialize the Event class.
443
+ */
444
+ void
445
+ rzyre_init_event( void ) {
446
+
447
+ #ifdef FOR_RDOC
448
+ rb_cData = rb_define_class( "Data" );
449
+ rzyre_mZyre = rb_define_module( "Zyre" );
450
+ #endif
451
+
452
+ /*
453
+ * Document-class: Zyre::Event
454
+ *
455
+ * An event read from a Zyre network.
456
+ *
457
+ * Refs:
458
+ * - https://github.com/zeromq/zyre#readme
459
+ */
460
+ rzyre_cZyreEvent = rb_define_class_under( rzyre_mZyre, "Event", rb_cObject );
461
+
462
+ rb_define_alloc_func( rzyre_cZyreEvent, rzyre_event_alloc );
463
+
464
+ rb_define_singleton_method( rzyre_cZyreEvent, "from_node", rzyre_event_s_from_node, 1 );
465
+ rb_define_singleton_method( rzyre_cZyreEvent, "synthesize", rzyre_event_s_synthesize, -1 );
466
+
467
+ rb_define_method( rzyre_cZyreEvent, "type", rzyre_event_type, 0 );
468
+ rb_define_method( rzyre_cZyreEvent, "peer_uuid", rzyre_event_peer_uuid, 0 );
469
+ rb_define_method( rzyre_cZyreEvent, "peer_name", rzyre_event_peer_name, 0 );
470
+ rb_define_method( rzyre_cZyreEvent, "peer_addr", rzyre_event_peer_addr, 0 );
471
+ rb_define_method( rzyre_cZyreEvent, "headers", rzyre_event_headers, 0 );
472
+ rb_define_method( rzyre_cZyreEvent, "header", rzyre_event_header, 1 );
473
+ rb_define_method( rzyre_cZyreEvent, "group", rzyre_event_group, 0 );
474
+ rb_define_method( rzyre_cZyreEvent, "msg", rzyre_event_msg, 0 );
475
+ rb_define_method( rzyre_cZyreEvent, "print", rzyre_event_print, 0 );
476
+
477
+ rb_require( "zyre/event" );
478
+ }
479
+