lwes 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,36 @@
1
+ require 'lwes'
2
+
3
+ module MyApp
4
+ end
5
+
6
+ # create an Emitter which may be used for the lifetime of your process
7
+ emitter = LWES::Emitter.new(:address => '224.1.1.11',
8
+ :port => 12345,
9
+ :heartbeat => 30, # nil to disable
10
+ :ttl => 1) # nil for no ttl
11
+
12
+ # parse your ESF file at startup, the example below assumes you
13
+ # have "Event1" and "Event2" defined in your ESF file:
14
+ type_db = LWES::TypeDB.new("my_events.esf")
15
+
16
+ # create classes to use, by default and to encourage DRY-ness,
17
+ # we map each event in the ESF file to a class
18
+ # Optionally, you may specify :parent => module/namespace
19
+ type_db.create_classes! :parent => MyApp
20
+
21
+ # inside your application, you may now do this to slowly build up
22
+ # fields for the event
23
+ my_event = MyApp::Event1.new
24
+ my_event.started = Time.now.to_i
25
+ my_event.remote_addr = "192.168.0.1"
26
+ # ...do a lot of stuff here in between...
27
+ # my_event.field1 = value1
28
+ # my_event.field2 = value2
29
+ # my_event.field3 = value3
30
+ my_event.finished = Time.now.to_i
31
+ emitter.emit my_event
32
+
33
+ # Alternatively, if you know ahead of time all the fields you want to
34
+ # set for an event, you can emit an event in one step:
35
+
36
+ emitter.emit MyApp::Event2, :field1 => "HI1", :field2 => "HI2"# ...
@@ -0,0 +1,17 @@
1
+ MetaEventInfo
2
+ {
3
+ ip_addr SenderIP;
4
+ }
5
+
6
+ Event1
7
+ {
8
+ int32 started;
9
+ int32 finished;
10
+ ip_addr remote_addr;
11
+ }
12
+
13
+ Event2
14
+ {
15
+ string field1;
16
+ string field2;
17
+ }
@@ -0,0 +1,366 @@
1
+ #include "lwes_ruby.h"
2
+
3
+ static VALUE cLWES_Emitter;
4
+ static ID sym_TYPE_DB, sym_TYPE_LIST, sym_NAME;
5
+ static ID id_new;
6
+
7
+ /* the underlying struct for LWES::Emitter */
8
+ struct _rb_lwes_emitter {
9
+ struct lwes_emitter *emitter;
10
+ };
11
+
12
+ /* gets the _rb_lwes_emitter struct pointer from self */
13
+ static struct _rb_lwes_emitter * _rle(VALUE self)
14
+ {
15
+ struct _rb_lwes_emitter *rle;
16
+
17
+ Data_Get_Struct(self, struct _rb_lwes_emitter, rle);
18
+
19
+ return rle;
20
+ }
21
+
22
+ /* GC automatically calls this when object is finalized */
23
+ static void rle_free(void *ptr)
24
+ {
25
+ struct _rb_lwes_emitter *rle = ptr;
26
+
27
+ if (rle->emitter)
28
+ lwes_emitter_destroy(rle->emitter);
29
+ rle->emitter = NULL;
30
+ }
31
+
32
+ /* called by the GC when object is allocated */
33
+ static VALUE rle_alloc(VALUE klass)
34
+ {
35
+ struct _rb_lwes_emitter *rle;
36
+
37
+ return Data_Make_Struct(klass, struct _rb_lwes_emitter,
38
+ NULL, rle_free, rle);
39
+ }
40
+
41
+ /*
42
+ * kv - Array:
43
+ * key => String,
44
+ * key => [ numeric_type, Numeric ],
45
+ * key => true,
46
+ * key => false,
47
+ * memo - lwes_event pointer
48
+ */
49
+ static VALUE event_hash_iter_i(VALUE kv, VALUE memo)
50
+ {
51
+ VALUE *tmp;
52
+ VALUE v;
53
+ struct lwes_event *event = (struct lwes_event *)memo;
54
+ LWES_CONST_SHORT_STRING name;
55
+ int rv = 0;
56
+
57
+ assert(TYPE(kv) == T_ARRAY &&
58
+ "hash iteration not giving key-value pairs");
59
+ tmp = RARRAY_PTR(kv);
60
+ name = RSTRING_PTR(rb_obj_as_string(tmp[0]));
61
+
62
+ v = tmp[1];
63
+ switch (TYPE(v)) {
64
+ case T_TRUE:
65
+ rv = lwes_event_set_BOOLEAN(event, name, TRUE);
66
+ break;
67
+ case T_FALSE:
68
+ rv = lwes_event_set_BOOLEAN(event, name, FALSE);
69
+ break;
70
+ case T_ARRAY:
71
+ rv = lwesrb_event_set_numeric(event, name, v);
72
+ break;
73
+ case T_STRING:
74
+ rv = lwes_event_set_STRING(event, name, RSTRING_PTR(v));
75
+ break;
76
+ }
77
+ if (rv > 0)
78
+ return Qnil;
79
+ if (rv == 0)
80
+ rb_raise(rb_eArgError, "unhandled type %s=%s for event=%s",
81
+ name, RSTRING_PTR(rb_inspect(v)), event->eventName);
82
+ /* rv < 0 */
83
+ rb_raise(rb_eRuntimeError, "failed to set %s=%s for event=%s",
84
+ name, RSTRING_PTR(rb_inspect(v)), event->eventName);
85
+ return Qfalse;
86
+ }
87
+
88
+ static VALUE _emit_hash(VALUE _tmp)
89
+ {
90
+ VALUE *tmp = (VALUE *)_tmp;
91
+ VALUE self = tmp[0];
92
+ VALUE _event = tmp[1];
93
+ struct lwes_event *event = (struct lwes_event *)tmp[2];
94
+
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");
98
+
99
+ return _event;
100
+ }
101
+
102
+ static int set_field(
103
+ struct lwes_event *event,
104
+ LWES_CONST_SHORT_STRING name,
105
+ LWES_TYPE type,
106
+ VALUE val)
107
+ {
108
+ switch (type) {
109
+ case LWES_TYPE_BOOLEAN:
110
+ if (val == Qfalse)
111
+ return lwes_event_set_BOOLEAN(event, name, FALSE);
112
+ else if (val == Qtrue)
113
+ return lwes_event_set_BOOLEAN(event, name, TRUE);
114
+ else
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));
122
+ default:
123
+ return lwesrb_event_set_num(event, name, type, val);
124
+ }
125
+ assert(0 && "you should never get here (set_field)");
126
+ return -1;
127
+ }
128
+
129
+ static VALUE _emit_struct(VALUE _argv)
130
+ {
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 = rb_const_get(CLASS_OF(_event), SYM2ID(sym_TYPE_LIST));
136
+ long i = RARRAY_LEN(type_list);
137
+ VALUE *tmp;
138
+
139
+ for (tmp = RARRAY_PTR(type_list); --i >= 0; tmp++) {
140
+ /* inner: [ :field_sym, "field_name", type ] */
141
+ VALUE *inner = RARRAY_PTR(*tmp);
142
+ VALUE val = rb_struct_aref(_event, inner[0]);
143
+ int rv;
144
+ LWES_CONST_SHORT_STRING name;
145
+ LWES_TYPE type;
146
+
147
+ if (NIL_P(val))
148
+ continue;
149
+
150
+ name = RSTRING_PTR(inner[1]);
151
+ type = NUM2INT(inner[2]);
152
+ rv = set_field(event, name, type, val);
153
+ if (rv > 0)
154
+ continue;
155
+
156
+ rb_raise(rb_eRuntimeError,
157
+ "failed to set %s=%s for event=%s (error: %d)",
158
+ name, RSTRING_PTR(rb_inspect(val)),
159
+ event->eventName, rv);
160
+ }
161
+
162
+ if (lwes_emitter_emit(_rle(self)->emitter, event) < 0)
163
+ rb_raise(rb_eRuntimeError, "failed to emit event");
164
+
165
+ return _event;
166
+ }
167
+
168
+ static VALUE _destroy_event(VALUE _event)
169
+ {
170
+ struct lwes_event *event = (struct lwes_event *)_event;
171
+
172
+ assert(event && "destroying NULL event");
173
+ lwes_event_destroy(event);
174
+
175
+ return Qnil;
176
+ }
177
+
178
+ static VALUE emit_hash(VALUE self, VALUE name, VALUE _event)
179
+ {
180
+ VALUE tmp[3];
181
+ struct lwes_event *event = lwes_event_create(NULL, RSTRING_PTR(name));
182
+
183
+ if (!event)
184
+ rb_raise(rb_eRuntimeError, "failed to create lwes_event");
185
+
186
+ tmp[0] = self;
187
+ tmp[1] = _event;
188
+ tmp[2] = (VALUE)event;
189
+ rb_ensure(_emit_hash, (VALUE)&tmp, _destroy_event, (VALUE)event);
190
+
191
+ return _event;
192
+ }
193
+
194
+ static struct lwes_event_type_db * get_type_db(VALUE event)
195
+ {
196
+ VALUE type_db = rb_const_get(CLASS_OF(event), SYM2ID(sym_TYPE_DB));
197
+
198
+ return lwesrb_get_type_db(type_db);
199
+ }
200
+
201
+ static VALUE emit_struct(VALUE self, VALUE name, VALUE _event)
202
+ {
203
+ VALUE argv[3];
204
+ struct lwes_event_type_db *db = get_type_db(_event);
205
+ struct lwes_event *event = lwes_event_create(db, RSTRING_PTR(name));
206
+
207
+ if (!event)
208
+ rb_raise(rb_eRuntimeError, "failed to create lwes_event");
209
+
210
+ argv[0] = self;
211
+ argv[1] = _event;
212
+ argv[2] = (VALUE)event;
213
+ rb_ensure(_emit_struct, (VALUE)&argv, _destroy_event, (VALUE)event);
214
+
215
+ return _event;
216
+ }
217
+
218
+ /*
219
+ * call-seq:
220
+ * emitter = LWES::Emitter.new
221
+ *
222
+ * emitter.emit("EventName", :foo => "HI")
223
+ *
224
+ * emitter.emit(EventStruct, :foo => "HI")
225
+ *
226
+ * struct = EventStruct.new
227
+ * struct.foo = "HI"
228
+ * emitter.emit(struct)
229
+ */
230
+ static VALUE emitter_emit(int argc, VALUE *argv, VALUE self)
231
+ {
232
+ VALUE name = Qnil;
233
+ VALUE event = Qnil;
234
+ argc = rb_scan_args(argc, argv, "11", &name, &event);
235
+
236
+ switch (TYPE(name)) {
237
+ case T_STRING:
238
+ if (TYPE(event) == T_HASH)
239
+ return emit_hash(self, name, event);
240
+ rb_raise(rb_eArgError,
241
+ "second argument must be a hash when first "
242
+ "is a String");
243
+ case T_STRUCT:
244
+ if (argc >= 2)
245
+ rb_raise(rb_eArgError,
246
+ "second argument not allowed when first"
247
+ " is a Struct");
248
+ event = name;
249
+ name = rb_const_get(CLASS_OF(event), SYM2ID(sym_NAME));
250
+ return emit_struct(self, name, event);
251
+ case T_CLASS:
252
+ if (TYPE(event) != T_HASH)
253
+ rb_raise(rb_eArgError,
254
+ "second argument must be a Hash when first"
255
+ " is a Class");
256
+
257
+ /*
258
+ * we can optimize this so there's no intermediate
259
+ * struct created
260
+ */
261
+ event = rb_funcall(name, id_new, 1, event);
262
+ name = rb_const_get(name, SYM2ID(sym_NAME));
263
+ return emit_struct(self, name, event);
264
+ default:
265
+ rb_raise(rb_eArgError,
266
+ "bad argument: %s, must be a String, Struct or Class",
267
+ RSTRING_PTR(rb_inspect(name)));
268
+ }
269
+
270
+ assert(0 && "should never get here");
271
+ return event;
272
+ }
273
+
274
+ /*
275
+ * Destroys the associated lwes_emitter and the associated socket. This
276
+ * method is rarely needed as Ruby garbage collection will take care of
277
+ * closing for you, but may be useful in odd cases when it is desirable
278
+ * to release file descriptors ASAP.
279
+ */
280
+ static VALUE emitter_close(VALUE self)
281
+ {
282
+ rle_free(_rle(self));
283
+
284
+ return Qnil;
285
+ }
286
+
287
+ /* should only used internally by #initialize */
288
+ static VALUE _create(VALUE self, VALUE options)
289
+ {
290
+ struct _rb_lwes_emitter *rle = _rle(self);
291
+ VALUE address, iface, port, heartbeat, ttl;
292
+ LWES_CONST_SHORT_STRING _address, _iface;
293
+ LWES_U_INT_32 _port; /* odd, uint16 would be enough here */
294
+ LWES_BOOLEAN _emit_heartbeat = FALSE;
295
+ LWES_INT_16 _freq = 0;
296
+ LWES_U_INT_32 _ttl = UINT32_MAX; /* nobody sets a ttl this long, right? */
297
+
298
+ if (rle->emitter)
299
+ rb_raise(rb_eRuntimeError, "already created lwes_emitter");
300
+ if (TYPE(options) != T_HASH)
301
+ rb_raise(rb_eTypeError, "options must be a hash");
302
+
303
+ address = rb_hash_aref(options, ID2SYM(rb_intern("address")));
304
+ if (TYPE(address) != T_STRING)
305
+ rb_raise(rb_eTypeError, ":address must be a string");
306
+ _address = RSTRING_PTR(address);
307
+
308
+ iface = rb_hash_aref(options, ID2SYM(rb_intern("iface")));
309
+ if (TYPE(iface) != T_STRING)
310
+ rb_raise(rb_eTypeError, ":iface must be a string");
311
+ _iface = RSTRING_PTR(address);
312
+
313
+ port = rb_hash_aref(options, ID2SYM(rb_intern("port")));
314
+ if (TYPE(port) != T_FIXNUM)
315
+ rb_raise(rb_eTypeError, ":port must be a Fixnum");
316
+ _port = NUM2UINT(port);
317
+
318
+ heartbeat = rb_hash_aref(options, ID2SYM(rb_intern("heartbeat")));
319
+ if (TYPE(heartbeat) == T_FIXNUM) {
320
+ int tmp = NUM2INT(heartbeat);
321
+ if (tmp > INT16_MAX)
322
+ rb_raise(rb_eArgError,":heartbeat > INT16_MAX seconds");
323
+ _emit_heartbeat = TRUE;
324
+ _freq = (LWES_INT_16)tmp;
325
+ } else if (NIL_P(heartbeat)) { /* do nothing, use defaults */
326
+ } else
327
+ rb_raise(rb_eTypeError, ":heartbeat must be a Fixnum or nil");
328
+
329
+ ttl = rb_hash_aref(options, ID2SYM(rb_intern("ttl")));
330
+ if (TYPE(ttl) == T_FIXNUM) {
331
+ unsigned LONG_LONG tmp = NUM2ULL(ttl);
332
+ if (tmp >= UINT32_MAX)
333
+ rb_raise(rb_eArgError, ":ttl >= UINT32_MAX seconds");
334
+ _ttl = (LWES_U_INT_32)tmp;
335
+ } else if (NIL_P(ttl)) { /* do nothing, no ttl */
336
+ } else
337
+ rb_raise(rb_eTypeError, ":ttl must be a Fixnum or nil");
338
+
339
+ if (_ttl == UINT32_MAX)
340
+ rle->emitter = lwes_emitter_create(
341
+ _address, _iface, _port, _emit_heartbeat, _freq);
342
+ else
343
+ rle->emitter = lwes_emitter_create_with_ttl(
344
+ _address, _iface, _port, _emit_heartbeat, _freq, _ttl);
345
+
346
+ if (!rle->emitter)
347
+ rb_raise(rb_eRuntimeError, "failed to create LWES emitter");
348
+
349
+ return self;
350
+ }
351
+
352
+ /* Init_lwes_ext will call this */
353
+ void lwesrb_init_emitter(void)
354
+ {
355
+ VALUE mLWES = rb_define_module("LWES");
356
+ cLWES_Emitter = rb_define_class_under(mLWES, "Emitter", rb_cObject);
357
+
358
+ rb_define_method(cLWES_Emitter, "emit", emitter_emit, -1);
359
+ rb_define_method(cLWES_Emitter, "_create", _create, 1);
360
+ rb_define_method(cLWES_Emitter, "close", emitter_close, 0);
361
+ rb_define_alloc_func(cLWES_Emitter, rle_alloc);
362
+ LWESRB_MKSYM(TYPE_DB);
363
+ LWESRB_MKSYM(TYPE_LIST);
364
+ LWESRB_MKSYM(NAME);
365
+ id_new = rb_intern("new");
366
+ }
@@ -0,0 +1,55 @@
1
+ require 'net/http'
2
+ require 'mkmf'
3
+ require 'fileutils'
4
+ dir_config('lwes')
5
+
6
+ pwd = File.expand_path(File.dirname(__FILE__))
7
+ v = '0.22.3'
8
+ dir = "lwes-#{v}"
9
+ inst = "#{pwd}/.inst"
10
+ tgz = "#{dir}.tar.gz"
11
+ url = "http://sourceforge.net/projects/lwes/files/lwes-c/#{v}/#{tgz}/download"
12
+
13
+ # from Net::HTTP example
14
+ def fetch(uri_str, limit = 10)
15
+ raise ArgumentError, 'HTTP redirect too deep' if limit == 0
16
+
17
+ response = Net::HTTP.get_response(URI.parse(uri_str))
18
+ case response
19
+ when Net::HTTPSuccess then response
20
+ when Net::HTTPRedirection then fetch(response['location'], limit - 1)
21
+ else
22
+ response.error!
23
+ end
24
+ end
25
+
26
+ unless have_library('lwes') && have_header('lwes.h')
27
+ warn "LWES library not found, downloading and building"
28
+ Dir.chdir(pwd) do
29
+ unless test ?r, tgz
30
+ response = fetch(url)
31
+ File.open("#{tgz}.#{$$}.#{rand}.tmp", "wb") do |fp|
32
+ fp.write(response.body)
33
+ File.rename(fp.path, tgz)
34
+ end
35
+ end
36
+ unless test ?r, "#{inst}/.ok"
37
+ FileUtils.rm_rf(dir)
38
+ system('tar', 'zxf', tgz) or abort "tar failed with #{$?}"
39
+ Dir.chdir(dir) do
40
+ system("./configure", "--prefix=#{inst}", "--disable-hardcore") or
41
+ abort "configure failed with #{$?}"
42
+ system("make") or abort "make failed with #{$?}"
43
+ system("make", "install") or abort "make install failed with #{$?}"
44
+ end
45
+ FileUtils.rm_rf(dir)
46
+ File.open("#{inst}/.ok", "wb") { }
47
+ end
48
+ $CFLAGS = "-I#{inst}/include/lwes-0 #{$CFLAGS}"
49
+ $LDFLAGS = "-Wl,-rpath=#{inst}/lib -L#{inst}/lib #{$LDFLAGS}"
50
+ have_library('lwes') && have_header('lwes.h') or
51
+ abort "installation failed"
52
+ end
53
+ end
54
+
55
+ create_makefile('lwes_ext')