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
;
10 LWES_CONST_SHORT_STRING address
;
11 LWES_CONST_SHORT_STRING iface
;
13 LWES_BOOLEAN emit_heartbeat
;
18 /* gets the _rb_lwes_emitter struct pointer from self */
19 static struct _rb_lwes_emitter
* _rle(VALUE self
)
21 struct _rb_lwes_emitter
*rle
;
23 Data_Get_Struct(self
, struct _rb_lwes_emitter
, rle
);
28 /* GC automatically calls this when object is finalized */
29 static void rle_free(void *ptr
)
31 struct _rb_lwes_emitter
*rle
= ptr
;
34 lwes_emitter_destroy(rle
->emitter
);
38 static struct lwes_event
*
39 lwesrb_event_create(struct lwes_event_type_db
*db
, VALUE name
)
42 const char *event_name
= RSTRING_PTR(name
);
43 struct lwes_event
*event
;
46 event
= lwes_event_create(db
, event_name
);
48 if (--gc_retry
== 0) {
52 rb_raise(rb_eRuntimeError
, "failed to create lwes_event");
57 /* called by the GC when object is allocated */
58 static VALUE
rle_alloc(VALUE klass
)
60 struct _rb_lwes_emitter
*rle
;
62 return Data_Make_Struct(klass
, struct _rb_lwes_emitter
,
69 * key => [ numeric_type, Numeric ],
72 * memo - lwes_event pointer
74 static VALUE
event_hash_iter_i(VALUE kv
, VALUE memo
)
78 struct lwes_event
*event
= (struct lwes_event
*)memo
;
79 LWES_CONST_SHORT_STRING name
;
83 assert(TYPE(kv
) == T_ARRAY
&&
84 "hash iteration not giving key-value pairs");
86 name
= RSTRING_PTR(rb_obj_as_string(tmp
[0]));
92 rv
= lwes_event_set_BOOLEAN(event
, name
, TRUE
);
95 rv
= lwes_event_set_BOOLEAN(event
, name
, FALSE
);
98 rv
= lwesrb_event_set_numeric(event
, name
, val
);
101 rv
= lwes_event_set_STRING(event
, name
, RSTRING_PTR(val
));
106 } else if (rv
== 0) {
107 rb_raise(rb_eArgError
, "unhandled type %s=%s for event=%s",
108 name
, RSTRING_PTR(rb_inspect(val
)), event
->eventName
);
110 /* looking at the lwes source code, -3 is allocation errors */
111 if (rv
== -3 && --gc_retry
== 0) {
115 rb_raise(rb_eRuntimeError
, "failed to set %s=%s for event=%s",
116 name
, RSTRING_PTR(rb_inspect(val
)), event
->eventName
);
121 static VALUE
_emit_hash(VALUE _tmp
)
123 VALUE
*tmp
= (VALUE
*)_tmp
;
125 VALUE _event
= tmp
[1];
126 struct lwes_event
*event
= (struct lwes_event
*)tmp
[2];
128 rb_iterate(rb_each
, _event
, event_hash_iter_i
, (VALUE
)event
);
129 if (lwes_emitter_emit(_rle(self
)->emitter
, event
) < 0)
130 rb_raise(rb_eRuntimeError
, "failed to emit event");
137 struct lwes_event
*event
,
138 LWES_CONST_SHORT_STRING name
,
147 case LWES_TYPE_BOOLEAN
:
149 rv
= lwes_event_set_BOOLEAN(event
, name
, FALSE
);
150 else if (val
== Qtrue
)
151 rv
= lwes_event_set_BOOLEAN(event
, name
, TRUE
);
153 rb_raise(rb_eTypeError
, "non-boolean set for %s: %s",
154 name
, RSTRING_PTR(rb_inspect(val
)));
156 case LWES_TYPE_STRING
:
157 if (TYPE(val
) != T_STRING
)
158 rb_raise(rb_eTypeError
, "non-String set for %s: %s",
159 name
, RSTRING_PTR(rb_inspect(val
)));
160 rv
= lwes_event_set_STRING(event
, name
, RSTRING_PTR(val
));
163 rv
= lwesrb_event_set_num(event
, name
, type
, val
);
168 if (rv
== -3 && --gc_retry
== 0) {
172 rb_raise(rb_eRuntimeError
,
173 "failed to set %s=%s for event=%s (error: %d)",
174 name
, RSTRING_PTR(rb_inspect(val
)),
175 event
->eventName
, rv
);
178 assert(0 && "you should never get here (set_field)");
181 static VALUE
_emit_struct(VALUE _argv
)
183 VALUE
*argv
= (VALUE
*)_argv
;
184 VALUE self
= argv
[0];
185 VALUE _event
= argv
[1];
186 struct lwes_event
*event
= (struct lwes_event
*)argv
[2];
187 VALUE type_list
= argv
[3];
191 if (TYPE(type_list
) != T_ARRAY
)
192 rb_raise(rb_eArgError
, "could not get TYPE_LIST const");
194 i
= RARRAY_LEN(type_list
);
195 for (tmp
= RARRAY_PTR(type_list
); --i
>= 0; tmp
++) {
196 /* inner: [ :field_sym, "field_name", type ] */
197 VALUE
*inner
= RARRAY_PTR(*tmp
);
198 VALUE val
= rb_struct_aref(_event
, inner
[0]);
199 LWES_CONST_SHORT_STRING name
;
205 name
= RSTRING_PTR(inner
[1]);
206 type
= NUM2INT(inner
[2]);
207 set_field(event
, name
, type
, val
);
210 if (lwes_emitter_emit(_rle(self
)->emitter
, event
) < 0)
211 rb_raise(rb_eRuntimeError
, "failed to emit event");
216 static VALUE
_destroy_event(VALUE _event
)
218 struct lwes_event
*event
= (struct lwes_event
*)_event
;
220 assert(event
&& "destroying NULL event");
221 lwes_event_destroy(event
);
226 static VALUE
emit_hash(VALUE self
, VALUE name
, VALUE _event
)
229 struct lwes_event
*event
= lwesrb_event_create(NULL
, name
);
233 tmp
[2] = (VALUE
)event
;
234 rb_ensure(_emit_hash
, (VALUE
)&tmp
, _destroy_event
, (VALUE
)event
);
239 static struct lwes_event_type_db
* get_type_db(VALUE event_class
)
241 VALUE type_db
= rb_const_get(event_class
, id_TYPE_DB
);
243 if (CLASS_OF(type_db
) != cLWES_TypeDB
)
244 rb_raise(rb_eArgError
, "class does not have valid TYPE_DB");
246 return lwesrb_get_type_db(type_db
);
249 static VALUE
emit_struct(VALUE self
, VALUE _event
)
252 VALUE event_class
= CLASS_OF(_event
);
253 struct lwes_event_type_db
*db
= get_type_db(event_class
);
254 struct lwes_event
*event
;
255 VALUE name
= rb_const_get(event_class
, id_NAME
);
256 VALUE type_list
= rb_const_get(event_class
, id_TYPE_LIST
);
258 if (TYPE(name
) != T_STRING
|| TYPE(type_list
) != T_ARRAY
)
259 rb_raise(rb_eArgError
,
260 "could not get class NAME or TYPE_LIST from: %s",
261 RSTRING_PTR(rb_inspect(_event
)));
263 event
= lwesrb_event_create(db
, name
);
267 argv
[2] = (VALUE
)event
;
269 rb_ensure(_emit_struct
, (VALUE
)&argv
, _destroy_event
, (VALUE
)event
);
276 * emitter = LWES::Emitter.new
277 * event = EventStruct.new
281 static VALUE
emitter_ltlt(VALUE self
, VALUE event
)
283 if (TYPE(event
) != T_STRUCT
)
284 rb_raise(rb_eArgError
,
285 "Must be a Struct: %s",
286 RSTRING_PTR(rb_inspect(event
)));
288 return emit_struct(self
, event
);
293 * emitter = LWES::Emitter.new
295 * emitter.emit("EventName", :foo => "HI")
297 * emitter.emit(EventStruct, :foo => "HI")
299 * struct = EventStruct.new
301 * emitter.emit(struct)
303 static VALUE
emitter_emit(int argc
, VALUE
*argv
, VALUE self
)
307 argc
= rb_scan_args(argc
, argv
, "11", &name
, &event
);
309 switch (TYPE(name
)) {
311 if (TYPE(event
) == T_HASH
)
312 return emit_hash(self
, name
, event
);
313 rb_raise(rb_eArgError
,
314 "second argument must be a hash when first "
318 rb_raise(rb_eArgError
,
319 "second argument not allowed when first"
322 return emit_struct(self
, event
);
324 if (TYPE(event
) != T_HASH
)
325 rb_raise(rb_eArgError
,
326 "second argument must be a Hash when first"
330 * we can optimize this so there's no intermediate
333 event
= rb_funcall(name
, id_new
, 1, event
);
334 return emit_struct(self
, event
);
336 rb_raise(rb_eArgError
,
337 "bad argument: %s, must be a String, Struct or Class",
338 RSTRING_PTR(rb_inspect(name
)));
341 assert(0 && "should never get here");
346 * Destroys the associated lwes_emitter and the associated socket. This
347 * method is rarely needed as Ruby garbage collection will take care of
348 * closing for you, but may be useful in odd cases when it is desirable
349 * to release file descriptors ASAP.
351 static VALUE
emitter_close(VALUE self
)
353 struct _rb_lwes_emitter
*rle
= _rle(self
);
356 lwes_emitter_destroy(rle
->emitter
);
362 static void lwesrb_emitter_create(struct _rb_lwes_emitter
*rle
)
366 if (rle
->ttl
== UINT32_MAX
)
367 rle
->emitter
= lwes_emitter_create(
368 rle
->address
, rle
->iface
, rle
->port
,
369 rle
->emit_heartbeat
, rle
->freq
);
371 rle
->emitter
= lwes_emitter_create_with_ttl(
372 rle
->address
, rle
->iface
, rle
->port
,
373 rle
->emit_heartbeat
, rle
->freq
, rle
->ttl
);
376 if (--gc_retry
== 0) {
380 rb_raise(rb_eRuntimeError
, "failed to create LWES emitter");
384 /* should only used internally by #initialize */
385 static VALUE
_create(VALUE self
, VALUE options
)
387 struct _rb_lwes_emitter
*rle
= _rle(self
);
388 VALUE address
, iface
, port
, heartbeat
, ttl
;
390 rle
->emit_heartbeat
= FALSE
;
392 rle
->ttl
= UINT32_MAX
; /* nobody sets a ttl this long, right? */
395 rb_raise(rb_eRuntimeError
, "already created lwes_emitter");
396 if (TYPE(options
) != T_HASH
)
397 rb_raise(rb_eTypeError
, "options must be a hash");
399 address
= rb_hash_aref(options
, ID2SYM(rb_intern("address")));
400 if (TYPE(address
) != T_STRING
)
401 rb_raise(rb_eTypeError
, ":address must be a string");
402 rle
->address
= RSTRING_PTR(address
);
404 iface
= rb_hash_aref(options
, ID2SYM(rb_intern("iface")));
405 switch (TYPE(iface
)) {
410 rle
->iface
= RSTRING_PTR(iface
);
413 rb_raise(rb_eTypeError
, ":iface must be a String or nil");
416 port
= rb_hash_aref(options
, ID2SYM(rb_intern("port")));
417 if (TYPE(port
) != T_FIXNUM
)
418 rb_raise(rb_eTypeError
, ":port must be a Fixnum");
419 rle
->port
= NUM2UINT(port
);
421 heartbeat
= rb_hash_aref(options
, ID2SYM(rb_intern("heartbeat")));
422 if (TYPE(heartbeat
) == T_FIXNUM
) {
423 int tmp
= NUM2INT(heartbeat
);
425 rb_raise(rb_eArgError
,":heartbeat > INT16_MAX seconds");
426 rle
->emit_heartbeat
= TRUE
;
427 rle
->freq
= (LWES_INT_16
)tmp
;
428 } else if (NIL_P(heartbeat
)) { /* do nothing, use defaults */
430 rb_raise(rb_eTypeError
, ":heartbeat must be a Fixnum or nil");
432 ttl
= rb_hash_aref(options
, ID2SYM(rb_intern("ttl")));
433 if (TYPE(ttl
) == T_FIXNUM
) {
434 unsigned LONG_LONG tmp
= NUM2ULL(ttl
);
435 if (tmp
>= UINT32_MAX
)
436 rb_raise(rb_eArgError
, ":ttl >= UINT32_MAX seconds");
437 rle
->ttl
= (LWES_U_INT_32
)tmp
;
438 } else if (NIL_P(ttl
)) { /* do nothing, no ttl */
440 rb_raise(rb_eTypeError
, ":ttl must be a Fixnum or nil");
442 lwesrb_emitter_create(rle
);
447 /* Init_lwes_ext will call this */
448 void lwesrb_init_emitter(void)
450 VALUE mLWES
= rb_define_module("LWES");
451 cLWES_Emitter
= rb_define_class_under(mLWES
, "Emitter", rb_cObject
);
453 rb_define_method(cLWES_Emitter
, "<<", emitter_ltlt
, 1);
454 rb_define_method(cLWES_Emitter
, "emit", emitter_emit
, -1);
455 rb_define_method(cLWES_Emitter
, "_create", _create
, 1);
456 rb_define_method(cLWES_Emitter
, "close", emitter_close
, 0);
457 rb_define_alloc_func(cLWES_Emitter
, rle_alloc
);
458 LWESRB_MKID(TYPE_DB
);
459 LWESRB_MKID(TYPE_LIST
);