3 static VALUE cLWES_Emitter
;
4 static ID id_TYPE_DB
, id_TYPE_LIST
, id_NAME
;
7 /* the underlying struct for LWES::Emitter */
8 struct _rb_lwes_emitter
{
9 struct lwes_emitter
*emitter
;
12 /* gets the _rb_lwes_emitter struct pointer from self */
13 static struct _rb_lwes_emitter
* _rle(VALUE self
)
15 struct _rb_lwes_emitter
*rle
;
17 Data_Get_Struct(self
, struct _rb_lwes_emitter
, rle
);
22 /* GC automatically calls this when object is finalized */
23 static void rle_free(void *ptr
)
25 struct _rb_lwes_emitter
*rle
= ptr
;
28 lwes_emitter_destroy(rle
->emitter
);
32 /* called by the GC when object is allocated */
33 static VALUE
rle_alloc(VALUE klass
)
35 struct _rb_lwes_emitter
*rle
;
37 return Data_Make_Struct(klass
, struct _rb_lwes_emitter
,
44 * key => [ numeric_type, Numeric ],
47 * memo - lwes_event pointer
49 static VALUE
event_hash_iter_i(VALUE kv
, VALUE memo
)
53 struct lwes_event
*event
= (struct lwes_event
*)memo
;
54 LWES_CONST_SHORT_STRING name
;
57 assert(TYPE(kv
) == T_ARRAY
&&
58 "hash iteration not giving key-value pairs");
60 name
= RSTRING_PTR(rb_obj_as_string(tmp
[0]));
65 rv
= lwes_event_set_BOOLEAN(event
, name
, TRUE
);
68 rv
= lwes_event_set_BOOLEAN(event
, name
, FALSE
);
71 rv
= lwesrb_event_set_numeric(event
, name
, v
);
74 rv
= lwes_event_set_STRING(event
, name
, RSTRING_PTR(v
));
80 rb_raise(rb_eArgError
, "unhandled type %s=%s for event=%s",
81 name
, RSTRING_PTR(rb_inspect(v
)), event
->eventName
);
83 rb_raise(rb_eRuntimeError
, "failed to set %s=%s for event=%s",
84 name
, RSTRING_PTR(rb_inspect(v
)), event
->eventName
);
88 static VALUE
_emit_hash(VALUE _tmp
)
90 VALUE
*tmp
= (VALUE
*)_tmp
;
92 VALUE _event
= tmp
[1];
93 struct lwes_event
*event
= (struct lwes_event
*)tmp
[2];
95 rb_iterate(rb_each
, _event
, event_hash_iter_i
, (VALUE
)event
);
96 if (lwes_emitter_emit(_rle(self
)->emitter
, event
) < 0)
97 rb_raise(rb_eRuntimeError
, "failed to emit event");
102 static int set_field(
103 struct lwes_event
*event
,
104 LWES_CONST_SHORT_STRING name
,
109 case LWES_TYPE_BOOLEAN
:
111 return lwes_event_set_BOOLEAN(event
, name
, FALSE
);
112 else if (val
== Qtrue
)
113 return lwes_event_set_BOOLEAN(event
, name
, TRUE
);
115 rb_raise(rb_eTypeError
, "non-boolean set for %s: %s",
116 name
, RSTRING_PTR(rb_inspect(val
)));
117 case LWES_TYPE_STRING
:
118 if (TYPE(val
) != T_STRING
)
119 rb_raise(rb_eTypeError
, "non-String set for %s: %s",
120 name
, RSTRING_PTR(rb_inspect(val
)));
121 return lwes_event_set_STRING(event
, name
, RSTRING_PTR(val
));
123 return lwesrb_event_set_num(event
, name
, type
, val
);
125 assert(0 && "you should never get here (set_field)");
129 static VALUE
_emit_struct(VALUE _argv
)
131 VALUE
*argv
= (VALUE
*)_argv
;
132 VALUE self
= argv
[0];
133 VALUE _event
= argv
[1];
134 struct lwes_event
*event
= (struct lwes_event
*)argv
[2];
135 VALUE type_list
= argv
[3];
139 if (TYPE(type_list
) != T_ARRAY
)
140 rb_raise(rb_eArgError
, "could not get TYPE_LIST const");
142 i
= RARRAY_LEN(type_list
);
143 for (tmp
= RARRAY_PTR(type_list
); --i
>= 0; tmp
++) {
144 /* inner: [ :field_sym, "field_name", type ] */
145 VALUE
*inner
= RARRAY_PTR(*tmp
);
146 VALUE val
= rb_struct_aref(_event
, inner
[0]);
148 LWES_CONST_SHORT_STRING name
;
154 name
= RSTRING_PTR(inner
[1]);
155 type
= NUM2INT(inner
[2]);
156 rv
= set_field(event
, name
, type
, val
);
160 rb_raise(rb_eRuntimeError
,
161 "failed to set %s=%s for event=%s (error: %d)",
162 name
, RSTRING_PTR(rb_inspect(val
)),
163 event
->eventName
, rv
);
166 if (lwes_emitter_emit(_rle(self
)->emitter
, event
) < 0)
167 rb_raise(rb_eRuntimeError
, "failed to emit event");
172 static VALUE
_destroy_event(VALUE _event
)
174 struct lwes_event
*event
= (struct lwes_event
*)_event
;
176 assert(event
&& "destroying NULL event");
177 lwes_event_destroy(event
);
182 static VALUE
emit_hash(VALUE self
, VALUE name
, VALUE _event
)
185 struct lwes_event
*event
= lwes_event_create(NULL
, RSTRING_PTR(name
));
188 rb_raise(rb_eRuntimeError
, "failed to create lwes_event");
192 tmp
[2] = (VALUE
)event
;
193 rb_ensure(_emit_hash
, (VALUE
)&tmp
, _destroy_event
, (VALUE
)event
);
198 static struct lwes_event_type_db
* get_type_db(VALUE event
)
200 VALUE type_db
= rb_const_get(CLASS_OF(event
), id_TYPE_DB
);
202 if (CLASS_OF(type_db
) != cLWES_TypeDB
)
203 rb_raise(rb_eArgError
, "class does not have valid TYPE_DB");
205 return lwesrb_get_type_db(type_db
);
208 static VALUE
emit_struct(VALUE self
, VALUE _event
)
211 struct lwes_event_type_db
*db
= get_type_db(_event
);
212 struct lwes_event
*event
;
213 VALUE event_class
= CLASS_OF(_event
);
214 VALUE name
= rb_const_get(event_class
, id_NAME
);
215 VALUE type_list
= rb_const_get(event_class
, id_TYPE_LIST
);
217 if (TYPE(name
) != T_STRING
|| TYPE(type_list
) != T_ARRAY
)
218 rb_raise(rb_eArgError
,
219 "could not get class NAME or TYPE_LIST from: %s",
220 RSTRING_PTR(rb_inspect(_event
)));
222 event
= lwes_event_create(db
, RSTRING_PTR(name
));
224 rb_raise(rb_eRuntimeError
, "failed to create lwes_event");
228 argv
[2] = (VALUE
)event
;
230 rb_ensure(_emit_struct
, (VALUE
)&argv
, _destroy_event
, (VALUE
)event
);
235 static VALUE
emitter_ltlt(VALUE self
, VALUE event
)
237 if (TYPE(event
) != T_STRUCT
)
238 rb_raise(rb_eArgError
,
239 "Must be a Struct: %s",
240 RSTRING_PTR(rb_inspect(event
)));
242 return emit_struct(self
, event
);
247 * emitter = LWES::Emitter.new
249 * emitter.emit("EventName", :foo => "HI")
251 * emitter.emit(EventStruct, :foo => "HI")
253 * struct = EventStruct.new
255 * emitter.emit(struct)
257 static VALUE
emitter_emit(int argc
, VALUE
*argv
, VALUE self
)
261 argc
= rb_scan_args(argc
, argv
, "11", &name
, &event
);
263 switch (TYPE(name
)) {
265 if (TYPE(event
) == T_HASH
)
266 return emit_hash(self
, name
, event
);
267 rb_raise(rb_eArgError
,
268 "second argument must be a hash when first "
272 rb_raise(rb_eArgError
,
273 "second argument not allowed when first"
276 return emit_struct(self
, event
);
278 if (TYPE(event
) != T_HASH
)
279 rb_raise(rb_eArgError
,
280 "second argument must be a Hash when first"
284 * we can optimize this so there's no intermediate
287 event
= rb_funcall(name
, id_new
, 1, event
);
288 return emit_struct(self
, event
);
290 rb_raise(rb_eArgError
,
291 "bad argument: %s, must be a String, Struct or Class",
292 RSTRING_PTR(rb_inspect(name
)));
295 assert(0 && "should never get here");
300 * Destroys the associated lwes_emitter and the associated socket. This
301 * method is rarely needed as Ruby garbage collection will take care of
302 * closing for you, but may be useful in odd cases when it is desirable
303 * to release file descriptors ASAP.
305 static VALUE
emitter_close(VALUE self
)
307 rle_free(_rle(self
));
312 /* should only used internally by #initialize */
313 static VALUE
_create(VALUE self
, VALUE options
)
315 struct _rb_lwes_emitter
*rle
= _rle(self
);
316 VALUE address
, iface
, port
, heartbeat
, ttl
;
317 LWES_CONST_SHORT_STRING _address
, _iface
;
318 LWES_U_INT_32 _port
; /* odd, uint16 would be enough here */
319 LWES_BOOLEAN _emit_heartbeat
= FALSE
;
320 LWES_INT_16 _freq
= 0;
321 LWES_U_INT_32 _ttl
= UINT32_MAX
; /* nobody sets a ttl this long, right? */
324 rb_raise(rb_eRuntimeError
, "already created lwes_emitter");
325 if (TYPE(options
) != T_HASH
)
326 rb_raise(rb_eTypeError
, "options must be a hash");
328 address
= rb_hash_aref(options
, ID2SYM(rb_intern("address")));
329 if (TYPE(address
) != T_STRING
)
330 rb_raise(rb_eTypeError
, ":address must be a string");
331 _address
= RSTRING_PTR(address
);
333 iface
= rb_hash_aref(options
, ID2SYM(rb_intern("iface")));
334 if (TYPE(iface
) != T_STRING
)
335 rb_raise(rb_eTypeError
, ":iface must be a string");
336 _iface
= RSTRING_PTR(address
);
338 port
= rb_hash_aref(options
, ID2SYM(rb_intern("port")));
339 if (TYPE(port
) != T_FIXNUM
)
340 rb_raise(rb_eTypeError
, ":port must be a Fixnum");
341 _port
= NUM2UINT(port
);
343 heartbeat
= rb_hash_aref(options
, ID2SYM(rb_intern("heartbeat")));
344 if (TYPE(heartbeat
) == T_FIXNUM
) {
345 int tmp
= NUM2INT(heartbeat
);
347 rb_raise(rb_eArgError
,":heartbeat > INT16_MAX seconds");
348 _emit_heartbeat
= TRUE
;
349 _freq
= (LWES_INT_16
)tmp
;
350 } else if (NIL_P(heartbeat
)) { /* do nothing, use defaults */
352 rb_raise(rb_eTypeError
, ":heartbeat must be a Fixnum or nil");
354 ttl
= rb_hash_aref(options
, ID2SYM(rb_intern("ttl")));
355 if (TYPE(ttl
) == T_FIXNUM
) {
356 unsigned LONG_LONG tmp
= NUM2ULL(ttl
);
357 if (tmp
>= UINT32_MAX
)
358 rb_raise(rb_eArgError
, ":ttl >= UINT32_MAX seconds");
359 _ttl
= (LWES_U_INT_32
)tmp
;
360 } else if (NIL_P(ttl
)) { /* do nothing, no ttl */
362 rb_raise(rb_eTypeError
, ":ttl must be a Fixnum or nil");
364 if (_ttl
== UINT32_MAX
)
365 rle
->emitter
= lwes_emitter_create(
366 _address
, _iface
, _port
, _emit_heartbeat
, _freq
);
368 rle
->emitter
= lwes_emitter_create_with_ttl(
369 _address
, _iface
, _port
, _emit_heartbeat
, _freq
, _ttl
);
372 rb_raise(rb_eRuntimeError
, "failed to create LWES emitter");
377 /* Init_lwes_ext will call this */
378 void lwesrb_init_emitter(void)
380 VALUE mLWES
= rb_define_module("LWES");
381 cLWES_Emitter
= rb_define_class_under(mLWES
, "Emitter", rb_cObject
);
383 rb_define_method(cLWES_Emitter
, "<<", emitter_ltlt
, 1);
384 rb_define_method(cLWES_Emitter
, "emit", emitter_emit
, -1);
385 rb_define_method(cLWES_Emitter
, "_create", _create
, 1);
386 rb_define_method(cLWES_Emitter
, "close", emitter_close
, 0);
387 rb_define_alloc_func(cLWES_Emitter
, rle_alloc
);
388 LWESRB_MKID(TYPE_DB
);
389 LWESRB_MKID(TYPE_LIST
);