From 72232ea02d559d6588b6bed4c3bfa3a82a0a439d Mon Sep 17 00:00:00 2001 From: "Erik S. Chang" Date: Wed, 29 Sep 2010 23:12:36 +0000 Subject: [PATCH] initial cut of event parsing This will be expanded and could end up being potentially give us a faster emitter, too. git-svn-id: https://lwes.svn.sourceforge.net/svnroot/lwes/lwes-ruby/trunk@578 a2f82657-cdd2-4550-bd36-68a8e7111808 --- ext/lwes/event.c | 210 ++++++++++++++++++++++++++++++++++++++++++++++++ ext/lwes/lwes.c | 1 + ext/lwes/lwes_ruby.h | 4 + lib/lwes.rb | 1 + lib/lwes/event.rb | 5 ++ test/unit/test_event.rb | 58 +++++++++++++ 6 files changed, 279 insertions(+) create mode 100644 ext/lwes/event.c create mode 100644 lib/lwes/event.rb create mode 100644 test/unit/test_event.rb diff --git a/ext/lwes/event.c b/ext/lwes/event.c new file mode 100644 index 0000000..6360e62 --- /dev/null +++ b/ext/lwes/event.c @@ -0,0 +1,210 @@ +#include "lwes_ruby.h" +static VALUE cLWES_Event; + +static ID id_TYPE_DB, id_NAME; +static VALUE sym_name; + +static struct lwes_event * lwesrb_get_event(VALUE self) +{ + struct lwes_event *event; + + Data_Get_Struct(self, struct lwes_event, event); + + return event; +} + +static void event_free(void *ptr) +{ + struct lwes_event *event = ptr; + + lwes_event_destroy(event); +} + + +static VALUE event_alloc(VALUE klass) +{ + struct lwes_event *e; + + if (klass == cLWES_Event) { + e = lwes_event_create_no_name(NULL); + if (e == NULL) { + rb_gc(); + e = lwes_event_create_no_name(NULL); + } + } else { + VALUE type_db = rb_const_get(klass, id_TYPE_DB); + struct lwes_event_type_db *tdb = lwesrb_get_type_db(type_db); + VALUE name = rb_const_get(klass, id_NAME); + const char *ename = StringValuePtr(name); + + e = lwes_event_create(tdb, ename); + if (e == NULL) { + rb_gc(); + e = lwes_event_create(tdb, ename); + } + } + if (e == NULL) + rb_memerror(); + + return Data_Wrap_Struct(klass, NULL, event_free, e); +} + +/* + * kv - Array: + * key => String, + * key => [ numeric_type, Numeric ], + * key => true, + * key => false, + * memo - lwes_event pointer + */ +static VALUE event_hash_iter_i(VALUE kv, VALUE memo) +{ + /* TODO */ +} + +static struct lwes_event_type_db * get_type_db(VALUE self) +{ + VALUE type_db = rb_const_get(CLASS_OF(self), id_TYPE_DB); + struct lwes_event_type_db *tdb = lwesrb_get_type_db(type_db); + + return tdb; +} + +static VALUE event_init(int argc, VALUE *argv, VALUE self) +{ + VALUE hash; + struct lwes_event *event; + + rb_scan_args(argc, argv, "01", &hash); + + Data_Get_Struct(self, struct lwes_event, event); + + return self; +} + +static VALUE event_aset(VALUE self, VALUE key, VALUE val) +{ + struct lwes_event_type_db *tdb = get_type_db(self); + struct lwes_event *e = lwesrb_get_event(self); + const char *attr = StringValuePtr(key); + struct lwes_hash *ehash = lwes_hash_get(tdb->events, e->eventName); + LWES_BYTE *attr_type; + + if (ehash == NULL) + rb_raise(rb_eArgError, "invalid event: %s\n", e->eventName); + + attr_type = lwes_hash_get(ehash, attr); + if (attr_type == NULL) + rb_raise(rb_eArgError, "invalid attribute: %s\n", attr); + + switch (*attr_type) { + } +} + +static VALUE lwesrb_attr_to_value(struct lwes_event_attribute *attr) +{ + if (attr->type == LWES_STRING_TOKEN) { + return rb_str_new2((const char *)attr->value); + } else if (attr->type == LWES_U_INT_16_TOKEN) { + return UINT2NUM(*((uint16_t *)attr->value)); + } else if (attr->type == LWES_INT_16_TOKEN) { + return INT2FIX(*((int16_t *)attr->value)); + } else if (attr->type == LWES_U_INT_32_TOKEN) { + return UINT2NUM(*((uint32_t *)attr->value)); + } else if (attr->type == LWES_INT_32_TOKEN) { + return INT2NUM(*((int32_t *)attr->value)); + } else if (attr->type == LWES_U_INT_64_TOKEN) { + return ULL2NUM(*((uint64_t *)attr->value)); + } else if (attr->type == LWES_INT_64_TOKEN) { + return LL2NUM(*((int64_t *)attr->value)); + } else if (attr->type == LWES_BOOLEAN_TOKEN) { + LWES_BOOLEAN b = *(LWES_BOOLEAN*)attr->value; + return b ? Qtrue : Qfalse; + } else if (attr->type == LWES_IP_ADDR_TOKEN) { + LWES_IP_ADDR *addr = attr->value; + VALUE str = rb_str_new(0, INET_ADDRSTRLEN); + socklen_t len = (socklen_t)INET_ADDRSTRLEN; + const char *name; + + name = inet_ntop(AF_INET, addr, RSTRING_PTR(str), len); + if (name == NULL) + rb_raise(rb_eTypeError, "invalid IP address"); + rb_str_set_len(str, strlen(name)); + return str; + } else { + /* + * possible event corruption + * skip it like the C library does ... + */ + } + return Qnil; +} + +static VALUE to_hash(VALUE self) +{ + struct lwes_event *e = lwesrb_get_event(self); + + return lwesrb_event_to_hash(e); +} + +static VALUE parse(VALUE self, VALUE buf) +{ + VALUE event = event_alloc(cLWES_Event); + struct lwes_event *e = lwesrb_get_event(event); + struct lwes_event_deserialize_tmp dtmp; + LWES_BYTE_P bytes; + size_t num_bytes; + int rc; + + StringValue(buf); + bytes = (LWES_BYTE_P)RSTRING_PTR(buf); + num_bytes = (size_t)RSTRING_LEN(buf); + rc = lwes_event_from_bytes(e, bytes, num_bytes, 0, &dtmp); + if (rc < 0) + rb_raise(rb_eRuntimeError, + "failed to parse LWES event (code: %d)\n", rc); + return event; +} + +VALUE lwesrb_event_to_hash(struct lwes_event *e) +{ + VALUE rv = rb_hash_new(); + VALUE val; + struct lwes_hash_enumeration hen; + LWES_SHORT_STRING name; + VALUE sym_attr_name; + struct lwes_event_attribute *attr; + + if (e->eventName != NULL) { + val = rb_str_new2(e->eventName); + rb_hash_aset(rv, sym_name, val); + } + + if (! lwes_hash_keys(e->attributes, &hen)) + return rv; + while (lwes_hash_enumeration_has_more_elements(&hen)) { + name = lwes_hash_enumeration_next_element(&hen); + sym_attr_name = ID2SYM(rb_intern(name)); + attr = lwes_hash_get(e->attributes, name); + val = lwesrb_attr_to_value(attr); + if (! NIL_P(val)) + rb_hash_aset(rv, sym_attr_name, val); + } + + return rv; +} + +void lwesrb_init_event(void) +{ + VALUE mLWES = rb_define_module("LWES"); + cLWES_Event = rb_define_class_under(mLWES, "Event", rb_cObject); + + rb_define_method(cLWES_Event, "initialize", event_init, -1); + rb_define_alloc_func(cLWES_Event, event_alloc); + rb_define_singleton_method(cLWES_Event, "parse", parse, 1); + rb_define_method(cLWES_Event, "to_hash", to_hash, 0); + + LWESRB_MKID(TYPE_DB); + LWESRB_MKID(NAME); + LWESRB_MKSYM(name); +} diff --git a/ext/lwes/lwes.c b/ext/lwes/lwes.c index 449e388..96425e2 100644 --- a/ext/lwes/lwes.c +++ b/ext/lwes/lwes.c @@ -22,4 +22,5 @@ void Init_lwes_ext(void) lwesrb_init_numeric(); lwesrb_init_emitter(); lwesrb_init_type_db(); + lwesrb_init_event(); } diff --git a/ext/lwes/lwes_ruby.h b/ext/lwes/lwes_ruby.h index 3987b6c..4960634 100644 --- a/ext/lwes/lwes_ruby.h +++ b/ext/lwes/lwes_ruby.h @@ -19,6 +19,8 @@ void lwesrb_init_emitter(void); void lwesrb_init_numeric(void); +void lwesrb_init_event(void); + void lwesrb_dump_type(LWES_BYTE type, LWES_BYTE_P buf, size_t *off); void lwesrb_dump_num(LWES_BYTE type, VALUE val, LWES_BYTE_P buf, size_t *off); @@ -42,4 +44,6 @@ void lwesrb_dump_num_ary(VALUE array, LWES_BYTE_P buf, size_t *off); #define RAISE_INSPECT(v) RSTRING_PTR(raise_inspect = rb_inspect(v)) +VALUE lwesrb_event_to_hash(struct lwes_event *e); + #endif /* LWES_RUBY_H */ diff --git a/lib/lwes.rb b/lib/lwes.rb index 609abe1..b7e923e 100644 --- a/lib/lwes.rb +++ b/lib/lwes.rb @@ -5,5 +5,6 @@ module LWES autoload :TypeDB, "lwes/type_db" autoload :Struct, "lwes/struct" autoload :Emitter, "lwes/emitter" + autoload :Event, "lwes/event" end require "lwes_ext" diff --git a/lib/lwes/event.rb b/lib/lwes/event.rb new file mode 100644 index 0000000..756205b --- /dev/null +++ b/lib/lwes/event.rb @@ -0,0 +1,5 @@ +class LWES::Event + def inspect + "#<#{self.class}:#{to_hash}>" + end +end diff --git a/test/unit/test_event.rb b/test/unit/test_event.rb new file mode 100644 index 0000000..7bd03b0 --- /dev/null +++ b/test/unit/test_event.rb @@ -0,0 +1,58 @@ +require "#{File.expand_path(File.dirname(__FILE__))}/../test_helper" +require 'ipaddr' + +class TestEvent < Test::Unit::TestCase + + def setup + @options = LISTENER_DEFAULTS.dup + end + + def test_inspect + ev = LWES::Event.new + assert_instance_of String, ev.inspect + end + + def test_to_hash + ev = LWES::Event.new + assert_equal({}, ev.to_hash) + end + + def test_emit_recieve_hash + receiver = UDPSocket.new + receiver.bind(nil, @options[:port]) + emitter = LWES::Emitter.new(@options) + tmp = { + :str => 'hello', + :uint16 => [ :uint16, 6344 ], + :int16 => [ :int16, -6344 ], + :uint32 => [ :uint32, 6344445 ], + :int32 => [ :int32, -6344445 ], + :uint64 => [ :uint64, 6344445123123 ], + :int64 => [ :int64, -6344445123123 ], + :true => true, + :false => false, + :addr => [ :ip_addr, "127.0.0.1" ], + } + + emitter.emit "Event", tmp + buf, addr = receiver.recvfrom(65536) + parsed = LWES::Event.parse(buf) + expect = { + :name => "Event", + :uint16 => 6344, + :str => "hello", + :int16 => -6344, + :uint32 => 6344445, + :int32 => -6344445, + :uint64 => 6344445123123, + :int64 => -6344445123123, + :true => true, + :false => false, + :addr => "127.0.0.1", + } + assert_instance_of LWES::Event, parsed + assert_equal expect, parsed.to_hash + ensure + receiver.close + end +end -- 2.11.4.GIT