zyre 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,272 @@
1
+ /*
2
+ * poller.c - A poller for doing evented IO on one or more Zyre nodes
3
+ * $Id$
4
+ *
5
+ * Authors:
6
+ * * Michael Granger <ged@FaerieMUD.org>
7
+ *
8
+ */
9
+
10
+ #include "zyre_ext.h"
11
+
12
+ VALUE rzyre_cZyrePoller;
13
+
14
+
15
+ static void rzyre_poller_free( void *ptr );
16
+
17
+ static const rb_data_type_t rzyre_poller_t = {
18
+ "Zyre::Poller",
19
+ {
20
+ NULL,
21
+ rzyre_poller_free
22
+ },
23
+ 0,
24
+ 0,
25
+ RUBY_TYPED_FREE_IMMEDIATELY,
26
+ };
27
+
28
+
29
+ /*
30
+ * Free function
31
+ */
32
+ static void
33
+ rzyre_poller_free( void *ptr )
34
+ {
35
+ if ( ptr ) {
36
+ zpoller_destroy( (zpoller_t **)&ptr );
37
+ }
38
+ }
39
+
40
+
41
+ /*
42
+ * Alloc function
43
+ */
44
+ static VALUE
45
+ rzyre_poller_alloc( VALUE klass )
46
+ {
47
+ return TypedData_Wrap_Struct( klass, &rzyre_poller_t, NULL );
48
+ }
49
+
50
+
51
+ /*
52
+ * Fetch the data pointer and check it for sanity.
53
+ */
54
+ static inline zpoller_t *
55
+ rzyre_get_poller( VALUE self )
56
+ {
57
+ zpoller_t *ptr;
58
+
59
+ if ( !IsZyrePoller(self) ) {
60
+ rb_raise( rb_eTypeError, "wrong argument type %s (expected Zyre::Poller)",
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
+ * call-seq:
73
+ * Zyre::Poller.new( *nodes ) -> poller
74
+ *
75
+ * Create a poller that will wait for input on any of the given +nodes+.
76
+ *
77
+ */
78
+ static VALUE
79
+ rzyre_poller_initialize( VALUE self, VALUE nodes )
80
+ {
81
+ zpoller_t *ptr;
82
+
83
+ TypedData_Get_Struct( self, zpoller_t, &rzyre_poller_t, ptr );
84
+ if ( !ptr ) {
85
+ RTYPEDDATA_DATA( self ) = ptr = zpoller_new( NULL );
86
+ assert( ptr );
87
+
88
+ rb_ivar_set( self, rb_intern("@nodes"), rb_hash_new() );
89
+ }
90
+
91
+ rb_funcall( self, rb_intern("add"), 1, nodes );
92
+
93
+ return self;
94
+ }
95
+
96
+
97
+ /*
98
+ * call-seq:
99
+ * poller.add( *nodes )
100
+ *
101
+ * Add the specified +nodes+ to the list which will be polled by a call to #wait.
102
+ *
103
+ */
104
+ static VALUE
105
+ rzyre_poller_add( VALUE self, VALUE nodes )
106
+ {
107
+ zpoller_t *ptr = rzyre_get_poller( self );
108
+ VALUE nodemap = rb_ivar_get( self, rb_intern("@nodes") );
109
+ long i;
110
+
111
+ // For each node given, record its endpoint in @nodes so we can map it back to
112
+ // the node later and add it to the poller.
113
+ nodes = rb_funcall( nodes, rb_intern("flatten"), 0 );
114
+ for ( i=0; i < RARRAY_LEN(nodes); i++ ) {
115
+ VALUE node = RARRAY_AREF( nodes, i );
116
+ zyre_t *zyre_node = rzyre_get_node( node );
117
+ zsock_t *sock = zyre_socket( zyre_node );
118
+ const char *endpoint_str = zsock_endpoint( sock );
119
+
120
+ assert( endpoint_str );
121
+
122
+ rb_hash_aset( nodemap, rb_str_new2(endpoint_str), node );
123
+ zpoller_add( ptr, sock );
124
+ }
125
+
126
+ return Qtrue;
127
+ }
128
+
129
+
130
+ /*
131
+ * call-seq:
132
+ * poller.nodes -> hash
133
+ *
134
+ * Return a (frozen copy) of the Hash of the nodes the Poller will wait on.
135
+ *
136
+ */
137
+ static VALUE
138
+ rzyre_poller_nodes( VALUE self )
139
+ {
140
+ VALUE rval = rb_obj_dup( rb_ivar_get(self, rb_intern( "@nodes" )) );
141
+
142
+ return rb_hash_freeze( rval );
143
+ }
144
+
145
+
146
+ /*
147
+ * call-seq:
148
+ * poller.remove( *nodes )
149
+ *
150
+ * Add the specified +nodes+ to the list which will be polled by a call to #wait.
151
+ *
152
+ */
153
+ static VALUE
154
+ rzyre_poller_remove( VALUE self, VALUE nodes )
155
+ {
156
+ zpoller_t *ptr = rzyre_get_poller( self );
157
+ VALUE nodemap = rb_ivar_get( self, rb_intern("@nodes") );
158
+ long i;
159
+
160
+ // For each node given, record its endpoint in @nodes so we can map it back to
161
+ // the node later and remove it to the poller.
162
+ nodes = rb_funcall( nodes, rb_intern("flatten"), 0 );
163
+ for ( i=0; i < RARRAY_LEN(nodes); i++ ) {
164
+ VALUE node = RARRAY_AREF( nodes, i );
165
+ zyre_t *zyre_node = rzyre_get_node( node );
166
+ zsock_t *sock = zyre_socket( zyre_node );
167
+ const char *endpoint_str = zsock_endpoint( sock );
168
+
169
+ assert( endpoint_str );
170
+
171
+ rb_hash_aset( nodemap, rb_str_new2(endpoint_str), node );
172
+ zpoller_remove( ptr, sock );
173
+ }
174
+
175
+ return Qtrue;
176
+ }
177
+
178
+
179
+ typedef struct {
180
+ zpoller_t *poller;
181
+ int timeout;
182
+ } wait_call_t;
183
+
184
+ /*
185
+ * Async wait function; called without the GVL.
186
+ */
187
+ static void *
188
+ rzyre_poller_wait_without_gvl( void *wait_call )
189
+ {
190
+ wait_call_t *call = (wait_call_t *)wait_call;
191
+ return zpoller_wait( call->poller, call->timeout );
192
+ }
193
+
194
+
195
+ /*
196
+ * call-seq:
197
+ * poller.wait( timeout=-1 ) -> node or nil
198
+ *
199
+ * Poll the registered nodes for I/O, return first one that has input. The
200
+ * timeout should be zero or greater, or -1 to wait indefinitely. Socket
201
+ * priority is defined by their order in the poll list. If the timeout expired,
202
+ * returns nil. If poll call is interrupted (SIGINT) or the ZMQ context was
203
+ * destroyed, an Interrupt is raised.
204
+ *
205
+ */
206
+ static VALUE
207
+ rzyre_poller_wait( int argc, VALUE *argv, VALUE self )
208
+ {
209
+ zpoller_t *ptr = rzyre_get_poller( self );
210
+ VALUE rval = Qnil;
211
+ zsock_t *sock;
212
+ VALUE timeout_arg;
213
+ VALUE nodemap = rb_ivar_get( self, rb_intern("@nodes") );
214
+ int timeout = -1;
215
+ wait_call_t call;
216
+
217
+ if ( rb_scan_args(argc, argv, "01", &timeout_arg) ) {
218
+ timeout = floor( NUM2DBL(timeout_arg) * 1000 );
219
+ }
220
+
221
+ rzyre_log_obj( self, "debug", "waiting on %d socket/s (timeout: %d)",
222
+ RHASH_SIZE(nodemap), timeout );
223
+
224
+ call.poller = ptr;
225
+ call.timeout = timeout;
226
+ sock = (zsock_t *)rb_thread_call_without_gvl2( rzyre_poller_wait_without_gvl, (void *)&call,
227
+ RUBY_UBF_IO, 0 );
228
+
229
+ if ( sock ) {
230
+ const char *endpoint = zsock_endpoint( sock );
231
+ rval = rb_hash_aref( nodemap, rb_str_new2(endpoint) );
232
+ }
233
+
234
+ return rval;
235
+ }
236
+
237
+
238
+
239
+ /*
240
+ * Initialize the Poller class.
241
+ */
242
+ void
243
+ rzyre_init_poller( void ) {
244
+
245
+ #ifdef FOR_RDOC
246
+ rb_cData = rb_define_class( "Data" );
247
+ rzyre_mZyre = rb_define_module( "Zyre" );
248
+ #endif
249
+
250
+ /*
251
+ * Document-class: Zyre::Poller
252
+ *
253
+ * A poller for evented Zyre IO. Built on zpoller from czmq.
254
+ *
255
+ * Refs:
256
+ * - http://api.zeromq.org/czmq3-0:zpoller
257
+ *
258
+ */
259
+ rzyre_cZyrePoller = rb_define_class_under( rzyre_mZyre, "Poller", rb_cObject );
260
+
261
+ rb_define_alloc_func( rzyre_cZyrePoller, rzyre_poller_alloc );
262
+
263
+ rb_define_protected_method( rzyre_cZyrePoller, "initialize", rzyre_poller_initialize, -2 );
264
+
265
+ rb_define_method( rzyre_cZyrePoller, "add", rzyre_poller_add, -2 );
266
+ rb_define_method( rzyre_cZyrePoller, "nodes", rzyre_poller_nodes, 0 );
267
+ rb_define_method( rzyre_cZyrePoller, "remove", rzyre_poller_remove, 1 );
268
+ rb_define_method( rzyre_cZyrePoller, "wait", rzyre_poller_wait, -1 );
269
+
270
+ rb_require( "zyre/poller" );
271
+ }
272
+
@@ -0,0 +1,154 @@
1
+ /*
2
+ * zyre_ext.c - Ruby binding for Zyre
3
+ * $Id$
4
+ *
5
+ * Authors:
6
+ * * Michael Granger <ged@FaerieMUD.org>
7
+ *
8
+ */
9
+
10
+ #include "zyre_ext.h"
11
+
12
+ VALUE rzyre_mZyre;
13
+
14
+
15
+ /* --------------------------------------------------------------
16
+ * Logging Functions
17
+ * -------------------------------------------------------------- */
18
+
19
+ /*
20
+ * Log a message to the given +context+ object's logger.
21
+ */
22
+ void
23
+ #ifdef HAVE_STDARG_PROTOTYPES
24
+ rzyre_log_obj( VALUE context, const char *level, const char *fmt, ... )
25
+ #else
26
+ rzyre_log_obj( VALUE context, const char *level, const char *fmt, va_dcl )
27
+ #endif
28
+ {
29
+ char buf[BUFSIZ];
30
+ va_list args;
31
+ VALUE logger = Qnil;
32
+ VALUE message = Qnil;
33
+
34
+ va_init_list( args, fmt );
35
+ vsnprintf( buf, BUFSIZ, fmt, args );
36
+ message = rb_str_new2( buf );
37
+
38
+ logger = rb_funcall( context, rb_intern("log"), 0 );
39
+ rb_funcall( logger, rb_intern(level), 1, message );
40
+
41
+ va_end( args );
42
+ }
43
+
44
+
45
+ /*
46
+ * Log a message to the global logger.
47
+ */
48
+ void
49
+ #ifdef HAVE_STDARG_PROTOTYPES
50
+ rzyre_log( const char *level, const char *fmt, ... )
51
+ #else
52
+ rzyre_log( const char *level, const char *fmt, va_dcl )
53
+ #endif
54
+ {
55
+ char buf[BUFSIZ];
56
+ va_list args;
57
+ VALUE logger = Qnil;
58
+ VALUE message = Qnil;
59
+
60
+ va_init_list( args, fmt );
61
+ vsnprintf( buf, BUFSIZ, fmt, args );
62
+ message = rb_str_new2( buf );
63
+
64
+ logger = rb_funcall( rzyre_mZyre, rb_intern("logger"), 0 );
65
+ rb_funcall( logger, rb_intern(level), 1, message );
66
+
67
+ va_end( args );
68
+ }
69
+
70
+
71
+
72
+ /* --------------------------------------------------------------
73
+ * Module methods
74
+ * -------------------------------------------------------------- */
75
+
76
+ /*
77
+ * call-seq:
78
+ * Zyre.zyre_version -> int
79
+ *
80
+ * Return the version of the underlying libzyre.
81
+ *
82
+ */
83
+ static VALUE
84
+ rzyre_s_zyre_version()
85
+ {
86
+ static uint64_t version;
87
+
88
+ version = zyre_version();
89
+
90
+ return INT2NUM( version );
91
+ }
92
+
93
+
94
+ /*
95
+ * call-seq:
96
+ * Zyre.interfaces -> hash
97
+ *
98
+ * Return a Hash of broadcast-capable interfaces on the local host keyed by name. The
99
+ * values contain other information about the interface:
100
+ *
101
+ * {
102
+ * "<interface name>" => {
103
+ * address: "<interface address>",
104
+ * broadcast: "<interface broadcast address>",
105
+ * netmask: "<interface network mask>",
106
+ * }
107
+ * }
108
+ */
109
+ static VALUE
110
+ rzyre_s_interfaces()
111
+ {
112
+ ziflist_t *iflist = ziflist_new();
113
+ const VALUE rval = rb_hash_new();
114
+ const char *iface = ziflist_first( iflist );
115
+
116
+ while ( iface ) {
117
+ const char *address_s = ziflist_address( iflist );
118
+ const char *broadcast_s = ziflist_broadcast( iflist );
119
+ const char *netmask_s = ziflist_netmask( iflist );
120
+ const VALUE info_hash = rb_hash_new();
121
+
122
+ rb_hash_aset( info_hash, ID2SYM(rb_intern("address")), rb_usascii_str_new_cstr(address_s) );
123
+ rb_hash_aset( info_hash, ID2SYM(rb_intern("broadcast")), rb_usascii_str_new_cstr(broadcast_s) );
124
+ rb_hash_aset( info_hash, ID2SYM(rb_intern("netmask")), rb_usascii_str_new_cstr(netmask_s) );
125
+
126
+ rb_hash_aset( rval, rb_usascii_str_new_cstr(iface), info_hash );
127
+
128
+ iface = ziflist_next( iflist );
129
+ }
130
+
131
+ ziflist_destroy( &iflist );
132
+
133
+ return rval;
134
+ }
135
+
136
+
137
+ /*
138
+ * Zyre extension init function
139
+ */
140
+ void
141
+ Init_zyre_ext()
142
+ {
143
+ rzyre_mZyre = rb_define_module( "Zyre" );
144
+
145
+ rb_define_singleton_method( rzyre_mZyre, "zyre_version", rzyre_s_zyre_version, 0 );
146
+ rb_define_singleton_method( rzyre_mZyre, "interfaces", rzyre_s_interfaces, 0 );
147
+
148
+ // :TODO: set up zsys_set_logsender()
149
+
150
+ rzyre_init_node();
151
+ rzyre_init_event();
152
+ rzyre_init_poller();
153
+ }
154
+
@@ -0,0 +1,99 @@
1
+ /*
2
+ * zyre_ext.h - Ruby binding for Zyre
3
+ * $Id$
4
+ *
5
+ * Authors:
6
+ * * Michael Granger <ged@FaerieMUD.org>
7
+ *
8
+ */
9
+
10
+ #ifndef ZYRE_EXT_H_90322ABD
11
+ #define ZYRE_EXT_H_90322ABD
12
+
13
+ #include <ruby.h>
14
+ #include <ruby/intern.h>
15
+ #include <ruby/thread.h>
16
+
17
+ #include "zyre.h"
18
+ #include "czmq.h"
19
+ #include "extconf.h"
20
+
21
+ #ifndef TRUE
22
+ # define TRUE 1
23
+ #endif
24
+
25
+ #ifndef FALSE
26
+ # define FALSE 0
27
+ #endif
28
+
29
+
30
+ // For synthesized events
31
+ struct _zyre_event_t {
32
+ char *type; // Event type as string
33
+ char *peer_uuid; // Sender UUID as string
34
+ char *peer_name; // Sender public name as string
35
+ char *peer_addr; // Sender ipaddress as string, for an ENTER event
36
+ zhash_t *headers; // Headers, for an ENTER event
37
+ char *group; // Group name for a SHOUT event
38
+ zmsg_t *msg; // Message payload for SHOUT or WHISPER
39
+ };
40
+
41
+
42
+ /* --------------------------------------------------------------
43
+ * Declarations
44
+ * -------------------------------------------------------------- */
45
+
46
+ #ifdef HAVE_STDARG_PROTOTYPES
47
+ #include <stdarg.h>
48
+ #define va_init_list(a,b) va_start(a,b)
49
+ void rzyre_log_obj( VALUE, const char *, const char *, ... );
50
+ void rzyre_log( const char *, const char *, ... );
51
+ #else
52
+ #include <varargs.h>
53
+ #define va_init_list(a,b) va_start(a)
54
+ void rzyre_log_obj( VALUE, const char *, const char *, va_dcl );
55
+ void rzyre_log( const char *, const char *, va_dcl );
56
+ #endif
57
+
58
+
59
+ /* --------------------------------------------------------------
60
+ * Structs
61
+ * -------------------------------------------------------------- */
62
+
63
+
64
+
65
+ /* -------------------------------------------------------
66
+ * Globals
67
+ * ------------------------------------------------------- */
68
+
69
+ /*
70
+ * Modules
71
+ */
72
+ extern VALUE rzyre_mZyre;
73
+ extern VALUE rzyre_cZyreNode;
74
+ extern VALUE rzyre_cZyreEvent;
75
+ extern VALUE rzyre_cZyrePoller;
76
+
77
+
78
+ /* --------------------------------------------------------------
79
+ * Type-check macros
80
+ * -------------------------------------------------------------- */
81
+
82
+ #define IsZyreNode( obj ) rb_obj_is_kind_of( (obj), rzyre_cZyreNode )
83
+ #define IsZyreEvent( obj ) rb_obj_is_kind_of( (obj), rzyre_cZyreEvent )
84
+ #define IsZyrePoller( obj ) rb_obj_is_kind_of( (obj), rzyre_cZyrePoller )
85
+
86
+
87
+ /* -------------------------------------------------------
88
+ * Initializer functions
89
+ * ------------------------------------------------------- */
90
+ extern void Init_zyre_ext _(( void ));
91
+
92
+ extern void rzyre_init_node _(( void ));
93
+ extern void rzyre_init_event _(( void ));
94
+ extern void rzyre_init_poller _(( void ));
95
+
96
+ extern zyre_t * rzyre_get_node _(( VALUE ));
97
+
98
+ #endif /* end of include guard: ZYRE_EXT_H_90322ABD */
99
+