lwes 0.7.0 → 0.8.0pre1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +4 -0
- data/ChangeLog +4 -0
- data/README +10 -40
- data/Rakefile +7 -4
- data/ext/lwes_ext/.gitignore +2 -0
- data/ext/{lwes → lwes_ext}/emitter.c +63 -53
- data/ext/{lwes → lwes_ext}/event.c +121 -67
- data/ext/{lwes → lwes_ext}/extconf.rb +3 -2
- data/ext/lwes_ext/listener.c +165 -0
- data/ext/{lwes → lwes_ext}/lwes-0.23.1.tar.gz +0 -0
- data/ext/{lwes → lwes_ext}/lwes.c +1 -0
- data/ext/{lwes → lwes_ext}/lwes_ruby.h +13 -6
- data/ext/{lwes → lwes_ext}/numeric.c +7 -71
- data/ext/lwes_ext/type_conv.c +99 -0
- data/ext/{lwes → lwes_ext}/type_db.c +18 -30
- data/lib/lwes/class_maker.rb +50 -0
- data/lib/lwes/event.rb +53 -3
- data/lib/lwes/listener.rb +26 -0
- data/lib/lwes/struct.rb +113 -146
- data/lib/lwes/type_db.rb +33 -30
- data/lib/lwes.rb +41 -2
- data/lwes.gemspec +7 -37
- data/test/test_helper.rb +2 -2
- data/test/unit/test_emit_struct.rb +1 -1
- data/test/unit/test_event.rb +80 -0
- data/test/unit/test_listener.rb +82 -0
- data/test/unit/test_struct.rb +7 -3
- data/test/unit/test_type_db.rb +4 -3
- data/test/unit/test_type_db_events.rb +47 -0
- metadata +39 -27
@@ -2,6 +2,7 @@ require 'net/http'
|
|
2
2
|
require 'mkmf'
|
3
3
|
require 'fileutils'
|
4
4
|
dir_config('lwes')
|
5
|
+
have_func('rb_thread_blocking_region', 'ruby.h')
|
5
6
|
|
6
7
|
pwd = File.expand_path(File.dirname(__FILE__))
|
7
8
|
v = '0.23.1'
|
@@ -41,14 +42,14 @@ end
|
|
41
42
|
unless have_library('lwes') && have_header('lwes.h')
|
42
43
|
warn "LWES library not found, building locally"
|
43
44
|
sub_cd(pwd) do
|
44
|
-
unless
|
45
|
+
unless File.readable?(tgz)
|
45
46
|
response = fetch(url)
|
46
47
|
File.open("#{tgz}.#{$$}.#{rand}.tmp", "wb") do |fp|
|
47
48
|
fp.write(response.body)
|
48
49
|
File.rename(fp.path, tgz)
|
49
50
|
end
|
50
51
|
end
|
51
|
-
unless
|
52
|
+
unless File.readable?("#{inst}/.ok")
|
52
53
|
FileUtils.rm_rf(dir)
|
53
54
|
system('tar', 'zxf', tgz) or abort "tar failed with #{$?}"
|
54
55
|
sub_cd(dir) do
|
@@ -0,0 +1,165 @@
|
|
1
|
+
#include "lwes_ruby.h"
|
2
|
+
#include <errno.h>
|
3
|
+
|
4
|
+
static void listener_free(void *ptr)
|
5
|
+
{
|
6
|
+
struct lwes_listener *listener = ptr;
|
7
|
+
|
8
|
+
if (listener)
|
9
|
+
(void)lwes_listener_destroy(listener);
|
10
|
+
}
|
11
|
+
|
12
|
+
static struct lwes_listener *listener_ptr(VALUE self)
|
13
|
+
{
|
14
|
+
struct lwes_listener *listener = DATA_PTR(self);
|
15
|
+
|
16
|
+
if (listener == NULL)
|
17
|
+
rb_raise(rb_eIOError, "closed listener");
|
18
|
+
return listener;
|
19
|
+
}
|
20
|
+
|
21
|
+
static void fail(int rc, const char *fn)
|
22
|
+
{
|
23
|
+
if (errno)
|
24
|
+
rb_sys_fail(fn);
|
25
|
+
rb_raise(rb_eRuntimeError, "%s failed with: %d", fn, rc);
|
26
|
+
}
|
27
|
+
|
28
|
+
/*
|
29
|
+
* call-seq:
|
30
|
+
* listener.close => nil
|
31
|
+
*
|
32
|
+
* Closes the socket used by the LWES::Listener object. Raises IOError if
|
33
|
+
* already closed.
|
34
|
+
*/
|
35
|
+
static VALUE listener_close(VALUE self)
|
36
|
+
{
|
37
|
+
struct lwes_listener *listener = listener_ptr(self);
|
38
|
+
int err;
|
39
|
+
|
40
|
+
DATA_PTR(self) = NULL;
|
41
|
+
errno = 0;
|
42
|
+
err = lwes_listener_destroy(listener);
|
43
|
+
if (err)
|
44
|
+
fail(err, "lwes_listener_destroy()");
|
45
|
+
return Qnil;
|
46
|
+
}
|
47
|
+
|
48
|
+
static VALUE listener_alloc(VALUE klass)
|
49
|
+
{
|
50
|
+
return Data_Wrap_Struct(klass, NULL, listener_free, NULL);
|
51
|
+
}
|
52
|
+
|
53
|
+
/*
|
54
|
+
* call-seq:
|
55
|
+
* listener = LWES::Listener.new(address: "224.1.1.11", port: 12345)
|
56
|
+
*
|
57
|
+
* Binds an LWES listener socket to receive events on. It takes the following
|
58
|
+
* options:
|
59
|
+
*
|
60
|
+
* - +:address+ is a dotted quad string of an IPv4 address to listen on.
|
61
|
+
* - +:port+ is the port to listen on
|
62
|
+
* - +:iface+ is a dotted quad string of the interface to listen on (optional)
|
63
|
+
*/
|
64
|
+
static VALUE listener_init(VALUE self, VALUE options)
|
65
|
+
{
|
66
|
+
struct lwes_listener *listener;
|
67
|
+
LWES_SHORT_STRING address;
|
68
|
+
LWES_SHORT_STRING iface;
|
69
|
+
LWES_U_INT_32 port;
|
70
|
+
VALUE tmp;
|
71
|
+
|
72
|
+
if (DATA_PTR(self))
|
73
|
+
rb_raise(rb_eRuntimeError,
|
74
|
+
"initializing already initialized Listener");
|
75
|
+
if (TYPE(options) != T_HASH)
|
76
|
+
rb_raise(rb_eTypeError, "options must be a hash");
|
77
|
+
|
78
|
+
tmp = rb_hash_aref(options, ID2SYM(rb_intern("address")));
|
79
|
+
address = StringValueCStr(tmp);
|
80
|
+
|
81
|
+
tmp = rb_hash_aref(options, ID2SYM(rb_intern("iface")));
|
82
|
+
iface = NIL_P(tmp) ? NULL : StringValueCStr(tmp);
|
83
|
+
|
84
|
+
tmp = rb_hash_aref(options, ID2SYM(rb_intern("port")));
|
85
|
+
port = (LWES_U_INT_32)lwesrb_uint16(tmp);
|
86
|
+
|
87
|
+
listener = lwes_listener_create(address, iface, port);
|
88
|
+
if (listener == NULL) {
|
89
|
+
rb_gc();
|
90
|
+
listener = lwes_listener_create(address, iface, port);
|
91
|
+
if (listener == NULL)
|
92
|
+
rb_raise(rb_eRuntimeError,
|
93
|
+
"failed to create LWES Listener");
|
94
|
+
}
|
95
|
+
|
96
|
+
DATA_PTR(self) = listener;
|
97
|
+
|
98
|
+
return self;
|
99
|
+
}
|
100
|
+
|
101
|
+
struct recv_args {
|
102
|
+
struct lwes_listener *listener;
|
103
|
+
struct lwes_event *event;
|
104
|
+
unsigned timeout_ms;
|
105
|
+
};
|
106
|
+
|
107
|
+
static VALUE recv_event(void *ptr)
|
108
|
+
{
|
109
|
+
struct recv_args *a = ptr;
|
110
|
+
int r;
|
111
|
+
|
112
|
+
if (a->timeout_ms == UINT_MAX)
|
113
|
+
r = lwes_listener_recv(a->listener, a->event);
|
114
|
+
else
|
115
|
+
r = lwes_listener_recv_by(a->listener, a->event, a->timeout_ms);
|
116
|
+
return (VALUE)r;
|
117
|
+
}
|
118
|
+
|
119
|
+
#ifdef HAVE_RB_THREAD_BLOCKING_REGION
|
120
|
+
/*
|
121
|
+
* call-seq:
|
122
|
+
* listener.recv => LWES::Event
|
123
|
+
* listener.recv(timeout_ms) => LWES::Event or nil
|
124
|
+
*
|
125
|
+
* Receives and returns one LWES::Event from the network.
|
126
|
+
* An optional timeout (in milliseconds) may be specified and cause this
|
127
|
+
* to return +nil+ on timeout. This method is only available under Ruby 1.9.
|
128
|
+
*/
|
129
|
+
static VALUE listener_recv(int argc, VALUE *argv, VALUE self)
|
130
|
+
{
|
131
|
+
struct recv_args args;
|
132
|
+
VALUE timeout;
|
133
|
+
int r, saved_errno;
|
134
|
+
|
135
|
+
rb_scan_args(argc, argv, "01", &timeout);
|
136
|
+
|
137
|
+
args.listener = listener_ptr(self);
|
138
|
+
args.event = lwes_event_create_no_name(NULL);
|
139
|
+
args.timeout_ms = NIL_P(timeout) ? UINT_MAX : NUM2UINT(timeout);
|
140
|
+
|
141
|
+
saved_errno = errno = 0;
|
142
|
+
r = (int)rb_thread_blocking_region(recv_event, &args, RUBY_UBF_IO, 0);
|
143
|
+
if (r >= 0)
|
144
|
+
return lwesrb_wrap_event(cLWES_Event, args.event);
|
145
|
+
saved_errno = errno;
|
146
|
+
(void)lwes_event_destroy(args.event);
|
147
|
+
if (r == -2 && ! NIL_P(timeout))
|
148
|
+
return Qnil;
|
149
|
+
errno = saved_errno;
|
150
|
+
fail(r, "lwes_listener_recv(_by)");
|
151
|
+
return Qnil;
|
152
|
+
}
|
153
|
+
#endif /* HAVE_RB_THREAD_BLOCKING_REGION */
|
154
|
+
|
155
|
+
void lwesrb_init_listener(void)
|
156
|
+
{
|
157
|
+
VALUE mLWES = rb_define_module("LWES");
|
158
|
+
VALUE cListener = rb_define_class_under(mLWES, "Listener", rb_cObject);
|
159
|
+
rb_define_alloc_func(cListener, listener_alloc);
|
160
|
+
rb_define_private_method(cListener, "initialize", listener_init, 1);
|
161
|
+
#ifdef HAVE_RB_THREAD_BLOCKING_REGION
|
162
|
+
rb_define_method(cListener, "recv", listener_recv, -1);
|
163
|
+
#endif
|
164
|
+
rb_define_method(cListener, "close", listener_close, 0);
|
165
|
+
}
|
File without changes
|
@@ -21,6 +21,10 @@ void lwesrb_init_numeric(void);
|
|
21
21
|
|
22
22
|
void lwesrb_init_event(void);
|
23
23
|
|
24
|
+
void lwesrb_init_listener(void);
|
25
|
+
|
26
|
+
VALUE lwesrb_wrap_event(VALUE klass, struct lwes_event *e);
|
27
|
+
|
24
28
|
void lwesrb_dump_type(LWES_BYTE type, LWES_BYTE_P buf, size_t *off);
|
25
29
|
|
26
30
|
void lwesrb_dump_num(LWES_BYTE type, VALUE val, LWES_BYTE_P buf, size_t *off);
|
@@ -37,17 +41,20 @@ void lwesrb_dump_num_ary(VALUE array, LWES_BYTE_P buf, size_t *off);
|
|
37
41
|
# define RARRAY_LEN(s) (RARRAY(s)->len)
|
38
42
|
#endif
|
39
43
|
|
40
|
-
#ifndef RSTRUCT_PTR
|
41
|
-
# define RSTRUCT_PTR(s) (RSTRUCT(s)->ptr)
|
42
|
-
# define RSTRUCT_LEN(s) (RSTRUCT(s)->len)
|
43
|
-
#endif
|
44
|
-
|
45
44
|
#define RAISE_INSPECT(v) RSTRING_PTR(raise_inspect = rb_inspect(v))
|
46
45
|
|
47
46
|
extern VALUE cLWES_Event;
|
48
47
|
|
49
48
|
struct lwes_event * lwesrb_get_event(VALUE self);
|
50
49
|
|
51
|
-
|
50
|
+
LWES_U_INT_16 lwesrb_uint16(VALUE val);
|
51
|
+
LWES_INT_16 lwesrb_int16(VALUE val);
|
52
|
+
LWES_U_INT_32 lwesrb_uint32(VALUE val);
|
53
|
+
LWES_INT_32 lwesrb_int32(VALUE val);
|
54
|
+
LWES_U_INT_64 lwesrb_uint64(VALUE val);
|
55
|
+
/* NUM2LL can raise RangeError */
|
56
|
+
#define lwesrb_int64(VAL) (LWES_INT_64)NUM2LL((VAL))
|
57
|
+
LWES_IP_ADDR lwesrb_ip_addr(VALUE val);
|
58
|
+
LWES_BOOLEAN lwesrb_boolean(VALUE val);
|
52
59
|
|
53
60
|
#endif /* LWES_RUBY_H */
|
@@ -8,110 +8,46 @@ static ID
|
|
8
8
|
sym_ip_addr;
|
9
9
|
static ID id_to_i;
|
10
10
|
|
11
|
-
void lwesrb_dump_type(LWES_BYTE type, LWES_BYTE_P buf, size_t *off)
|
12
|
-
{
|
13
|
-
if (marshall_BYTE(type, buf, MAX_MSG_SIZE, off) > 0)
|
14
|
-
return;
|
15
|
-
rb_raise(rb_eRuntimeError, "failed to dump type=%02x", (unsigned)type);
|
16
|
-
}
|
17
|
-
|
18
11
|
static int dump_uint16(VALUE val, LWES_BYTE_P buf, size_t *off)
|
19
12
|
{
|
20
|
-
int32_t tmp = NUM2INT(val);
|
21
|
-
|
22
|
-
if (tmp < 0)
|
23
|
-
rb_raise(rb_eRangeError, ":uint16 negative: %d", tmp);
|
24
|
-
if (tmp > UINT16_MAX)
|
25
|
-
rb_raise(rb_eRangeError, ":uint16 too large: %d", tmp);
|
26
|
-
|
27
13
|
lwesrb_dump_type(LWES_U_INT_16_TOKEN, buf, off);
|
28
|
-
return marshall_U_INT_16((
|
14
|
+
return marshall_U_INT_16(lwesrb_uint16(val), buf, MAX_MSG_SIZE, off);
|
29
15
|
}
|
30
16
|
|
31
17
|
static int dump_int16(VALUE val, LWES_BYTE_P buf, size_t *off)
|
32
18
|
{
|
33
|
-
int32_t tmp = NUM2INT(val);
|
34
|
-
|
35
|
-
if (tmp > INT16_MAX)
|
36
|
-
rb_raise(rb_eRangeError, ":int16 too large: %i", tmp);
|
37
|
-
if (tmp < INT16_MIN)
|
38
|
-
rb_raise(rb_eRangeError, ":int16 too small: %i", tmp);
|
39
|
-
|
40
19
|
lwesrb_dump_type(LWES_INT_16_TOKEN, buf, off);
|
41
|
-
return marshall_INT_16((
|
20
|
+
return marshall_INT_16(lwesrb_int16(val), buf, MAX_MSG_SIZE, off);
|
42
21
|
}
|
43
22
|
|
44
23
|
static int dump_uint32(VALUE val, LWES_BYTE_P buf, size_t *off)
|
45
24
|
{
|
46
|
-
LONG_LONG tmp = NUM2LL(val);
|
47
|
-
|
48
|
-
if (tmp < 0)
|
49
|
-
rb_raise(rb_eRangeError, ":uint32 negative: %lli", tmp);
|
50
|
-
if (tmp > UINT32_MAX)
|
51
|
-
rb_raise(rb_eRangeError, ":uint32 too large: %lli", tmp);
|
52
|
-
|
53
25
|
lwesrb_dump_type(LWES_U_INT_32_TOKEN, buf, off);
|
54
|
-
return marshall_U_INT_32((
|
26
|
+
return marshall_U_INT_32(lwesrb_uint32(val), buf, MAX_MSG_SIZE, off);
|
55
27
|
}
|
56
28
|
|
57
29
|
static int dump_int32(VALUE val, LWES_BYTE_P buf, size_t *off)
|
58
30
|
{
|
59
|
-
LONG_LONG tmp = NUM2LL(val);
|
60
|
-
|
61
|
-
if (tmp > INT32_MAX)
|
62
|
-
rb_raise(rb_eRangeError, ":int32 too large: %lli", tmp);
|
63
|
-
if (tmp < INT32_MIN)
|
64
|
-
rb_raise(rb_eRangeError, ":int32 too small: %lli", tmp);
|
65
|
-
|
66
31
|
lwesrb_dump_type(LWES_INT_32_TOKEN, buf, off);
|
67
|
-
return marshall_INT_32((
|
32
|
+
return marshall_INT_32(lwesrb_int32(val), buf, MAX_MSG_SIZE, off);
|
68
33
|
}
|
69
34
|
|
70
35
|
static int dump_uint64(VALUE val, LWES_BYTE_P buf, size_t *off)
|
71
36
|
{
|
72
|
-
unsigned LONG_LONG tmp = NUM2ULL(val); /* can raise RangeError */
|
73
|
-
ID type = TYPE(val);
|
74
|
-
|
75
|
-
if ((type == T_FIXNUM && FIX2LONG(val) < 0) ||
|
76
|
-
(type == T_BIGNUM && RTEST(rb_funcall(val, '<', 1, INT2FIX(0))))) {
|
77
|
-
volatile VALUE raise_inspect;
|
78
|
-
|
79
|
-
rb_raise(rb_eRangeError, ":uint64 negative: %s",
|
80
|
-
RAISE_INSPECT(val));
|
81
|
-
}
|
82
|
-
|
83
37
|
lwesrb_dump_type(LWES_U_INT_64_TOKEN, buf, off);
|
84
|
-
return marshall_U_INT_64((
|
38
|
+
return marshall_U_INT_64(lwesrb_uint64(val), buf, MAX_MSG_SIZE, off);
|
85
39
|
}
|
86
40
|
|
87
41
|
static int dump_int64(VALUE val, LWES_BYTE_P buf, size_t *off)
|
88
42
|
{
|
89
|
-
LONG_LONG tmp = NUM2LL(val); /* can raise RangeError */
|
90
|
-
|
91
43
|
lwesrb_dump_type(LWES_INT_64_TOKEN, buf, off);
|
92
|
-
return marshall_INT_64((
|
44
|
+
return marshall_INT_64(lwesrb_int64(val), buf, MAX_MSG_SIZE, off);
|
93
45
|
}
|
94
46
|
|
95
47
|
static int dump_ip_addr(VALUE val, LWES_BYTE_P buf, size_t *off)
|
96
48
|
{
|
97
|
-
LWES_IP_ADDR addr;
|
98
|
-
volatile VALUE raise_inspect;
|
99
|
-
|
100
|
-
switch (TYPE(val)) {
|
101
|
-
case T_STRING:
|
102
|
-
addr.s_addr = inet_addr(RSTRING_PTR(val));
|
103
|
-
break;
|
104
|
-
case T_FIXNUM:
|
105
|
-
case T_BIGNUM:
|
106
|
-
addr.s_addr = htonl(NUM2UINT(val));
|
107
|
-
break;
|
108
|
-
default:
|
109
|
-
rb_raise(rb_eTypeError,
|
110
|
-
":ip_addr address must be String or Integer: %s",
|
111
|
-
RAISE_INSPECT(val));
|
112
|
-
}
|
113
49
|
lwesrb_dump_type(LWES_IP_ADDR_TOKEN, buf, off);
|
114
|
-
return marshall_IP_ADDR(
|
50
|
+
return marshall_IP_ADDR(lwesrb_ip_addr(val), buf, MAX_MSG_SIZE, off);
|
115
51
|
}
|
116
52
|
|
117
53
|
/* simple type => function dispatch map */
|
@@ -0,0 +1,99 @@
|
|
1
|
+
#include "lwes_ruby.h"
|
2
|
+
|
3
|
+
void lwesrb_dump_type(LWES_BYTE type, LWES_BYTE_P buf, size_t *off)
|
4
|
+
{
|
5
|
+
if (marshall_BYTE(type, buf, MAX_MSG_SIZE, off) > 0)
|
6
|
+
return;
|
7
|
+
rb_raise(rb_eRuntimeError, "failed to dump type=%02x", (unsigned)type);
|
8
|
+
}
|
9
|
+
|
10
|
+
LWES_U_INT_16 lwesrb_uint16(VALUE val)
|
11
|
+
{
|
12
|
+
int32_t tmp = NUM2INT(val);
|
13
|
+
|
14
|
+
if (tmp != (LWES_U_INT_16)tmp) {
|
15
|
+
const char *s = tmp < 0 ? "negative" : "too big";
|
16
|
+
rb_raise(rb_eRangeError, ":uint16 %s: %d", s, tmp);
|
17
|
+
}
|
18
|
+
return (LWES_U_INT_16)tmp;
|
19
|
+
}
|
20
|
+
|
21
|
+
LWES_INT_16 lwesrb_int16(VALUE val)
|
22
|
+
{
|
23
|
+
int32_t tmp = NUM2INT(val);
|
24
|
+
|
25
|
+
if (tmp != (LWES_INT_16)tmp) {
|
26
|
+
const char *s = tmp < 0 ? "small" : "big";
|
27
|
+
rb_raise(rb_eRangeError, ":int16 too %s: %d", s, tmp);
|
28
|
+
}
|
29
|
+
return (LWES_INT_16)tmp;
|
30
|
+
}
|
31
|
+
|
32
|
+
LWES_U_INT_32 lwesrb_uint32(VALUE val)
|
33
|
+
{
|
34
|
+
LONG_LONG tmp = NUM2LL(val);
|
35
|
+
|
36
|
+
if (tmp != (LWES_U_INT_32)tmp) {
|
37
|
+
const char *s = tmp < 0 ? "negative" : "too big";
|
38
|
+
rb_raise(rb_eRangeError, ":uint32 %s: %lli", s, tmp);
|
39
|
+
}
|
40
|
+
return (LWES_U_INT_32)tmp;
|
41
|
+
}
|
42
|
+
|
43
|
+
LWES_INT_32 lwesrb_int32(VALUE val)
|
44
|
+
{
|
45
|
+
LONG_LONG tmp = NUM2LL(val);
|
46
|
+
|
47
|
+
if (tmp != (LWES_INT_32)tmp) {
|
48
|
+
const char *s = tmp < 0 ? "small" : "big";
|
49
|
+
rb_raise(rb_eRangeError, ":int32 too %s: %lli", s, tmp);
|
50
|
+
}
|
51
|
+
return (LWES_INT_32)tmp;
|
52
|
+
}
|
53
|
+
|
54
|
+
LWES_U_INT_64 lwesrb_uint64(VALUE val)
|
55
|
+
{
|
56
|
+
unsigned LONG_LONG tmp = NUM2ULL(val); /* can raise RangeError */
|
57
|
+
ID type = TYPE(val);
|
58
|
+
|
59
|
+
if ((type == T_FIXNUM && FIX2LONG(val) < 0) ||
|
60
|
+
(type == T_BIGNUM && RTEST(rb_funcall(val, '<', 1, INT2FIX(0))))) {
|
61
|
+
volatile VALUE raise_inspect;
|
62
|
+
|
63
|
+
rb_raise(rb_eRangeError, ":uint64 negative: %s",
|
64
|
+
RAISE_INSPECT(val));
|
65
|
+
}
|
66
|
+
return (LWES_U_INT_64)tmp;
|
67
|
+
}
|
68
|
+
|
69
|
+
LWES_IP_ADDR lwesrb_ip_addr(VALUE val)
|
70
|
+
{
|
71
|
+
LWES_IP_ADDR addr;
|
72
|
+
volatile VALUE raise_inspect;
|
73
|
+
|
74
|
+
switch (TYPE(val)) {
|
75
|
+
case T_STRING:
|
76
|
+
addr.s_addr = inet_addr(StringValueCStr(val));
|
77
|
+
break;
|
78
|
+
case T_FIXNUM:
|
79
|
+
case T_BIGNUM:
|
80
|
+
addr.s_addr = htonl(NUM2UINT(val));
|
81
|
+
break;
|
82
|
+
default:
|
83
|
+
rb_raise(rb_eTypeError,
|
84
|
+
":ip_addr address must be String or Integer: %s",
|
85
|
+
RAISE_INSPECT(val));
|
86
|
+
}
|
87
|
+
|
88
|
+
return addr;
|
89
|
+
}
|
90
|
+
|
91
|
+
LWES_BOOLEAN lwesrb_boolean(VALUE val)
|
92
|
+
{
|
93
|
+
if (val == Qtrue) return TRUE;
|
94
|
+
if (val != Qfalse) {
|
95
|
+
volatile VALUE raise_inspect;
|
96
|
+
rb_raise(rb_eTypeError, "non-boolean: %s", RAISE_INSPECT(val));
|
97
|
+
}
|
98
|
+
return FALSE;
|
99
|
+
}
|
@@ -2,48 +2,38 @@
|
|
2
2
|
|
3
3
|
VALUE cLWES_TypeDB;
|
4
4
|
|
5
|
-
struct _tdb {
|
6
|
-
struct lwes_event_type_db *db;
|
7
|
-
};
|
8
|
-
|
9
5
|
static void tdb_free(void *ptr)
|
10
6
|
{
|
11
|
-
struct
|
7
|
+
struct lwes_event_type_db *db = ptr;
|
12
8
|
|
13
|
-
if (
|
14
|
-
lwes_event_type_db_destroy(
|
15
|
-
xfree(ptr);
|
9
|
+
if (db)
|
10
|
+
lwes_event_type_db_destroy(db);
|
16
11
|
}
|
17
12
|
|
18
13
|
static VALUE tdb_alloc(VALUE klass)
|
19
14
|
{
|
20
|
-
|
21
|
-
|
22
|
-
return Data_Make_Struct(klass, struct _tdb, NULL, tdb_free, tdb);
|
15
|
+
return Data_Wrap_Struct(klass, NULL, tdb_free, NULL);
|
23
16
|
}
|
24
17
|
|
25
18
|
static VALUE tdb_init(VALUE self, VALUE path)
|
26
19
|
{
|
27
|
-
struct
|
20
|
+
struct lwes_event_type_db *db = DATA_PTR(self);
|
28
21
|
int gc_retry = 1;
|
22
|
+
char *cpath = StringValueCStr(path);
|
29
23
|
|
30
|
-
if (
|
31
|
-
rb_raise(rb_eArgError, "path must be a string");
|
32
|
-
|
33
|
-
Data_Get_Struct(self, struct _tdb, tdb);
|
34
|
-
if (tdb->db)
|
24
|
+
if (db)
|
35
25
|
rb_raise(rb_eRuntimeError, "ESF already initialized");
|
36
26
|
retry:
|
37
|
-
|
38
|
-
if (!
|
27
|
+
db = lwes_event_type_db_create(cpath);
|
28
|
+
if (!db) {
|
39
29
|
if (--gc_retry == 0) {
|
40
30
|
rb_gc();
|
41
31
|
goto retry;
|
42
32
|
}
|
43
33
|
rb_raise(rb_eRuntimeError,
|
44
|
-
"failed to create type DB for LWES file %s",
|
45
|
-
RSTRING_PTR(path));
|
34
|
+
"failed to create type DB for LWES file %s", cpath);
|
46
35
|
}
|
36
|
+
DATA_PTR(self) = db;
|
47
37
|
|
48
38
|
return Qnil;
|
49
39
|
}
|
@@ -100,28 +90,26 @@ static VALUE event_def_ary(struct lwes_hash *hash)
|
|
100
90
|
|
101
91
|
struct lwes_event_type_db * lwesrb_get_type_db(VALUE self)
|
102
92
|
{
|
103
|
-
struct
|
93
|
+
struct lwes_event_type_db *db = DATA_PTR(self);
|
104
94
|
|
105
|
-
|
106
|
-
if (! tdb->db) {
|
95
|
+
if (!db) {
|
107
96
|
volatile VALUE raise_inspect;
|
108
97
|
rb_raise(rb_eRuntimeError,
|
109
98
|
"couldn't get lwes_type_db from %s",
|
110
99
|
RAISE_INSPECT(self));
|
111
100
|
}
|
112
|
-
return
|
101
|
+
return db;
|
113
102
|
}
|
114
103
|
|
115
104
|
static VALUE tdb_to_hash(VALUE self)
|
116
105
|
{
|
117
|
-
struct
|
106
|
+
struct lwes_event_type_db *db = DATA_PTR(self);
|
118
107
|
VALUE rv = rb_hash_new();
|
119
108
|
struct lwes_hash *events;
|
120
109
|
struct lwes_hash_enumeration e;
|
121
110
|
|
122
|
-
|
123
|
-
|
124
|
-
events = tdb->db->events;
|
111
|
+
assert(db && db->events && "tdb not initialized");
|
112
|
+
events = db->events;
|
125
113
|
|
126
114
|
if (!lwes_hash_keys(events, &e))
|
127
115
|
rb_raise(rb_eRuntimeError, "couldn't get type_db events");
|
@@ -151,7 +139,7 @@ void lwesrb_init_type_db(void)
|
|
151
139
|
{
|
152
140
|
VALUE mLWES = rb_define_module("LWES");
|
153
141
|
cLWES_TypeDB = rb_define_class_under(mLWES, "TypeDB", rb_cObject);
|
154
|
-
|
142
|
+
rb_define_private_method(cLWES_TypeDB, "initialize", tdb_init, 1);
|
155
143
|
rb_define_method(cLWES_TypeDB, "to_hash", tdb_to_hash, 0);
|
156
144
|
rb_define_alloc_func(cLWES_TypeDB, tdb_alloc);
|
157
145
|
}
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# :stopdoc:
|
2
|
+
# internal class
|
3
|
+
module LWES::ClassMaker
|
4
|
+
def type_db(options)
|
5
|
+
options[:db] || begin
|
6
|
+
file = options[:file] or
|
7
|
+
raise ArgumentError, "TypeDB :db or ESF :file missing"
|
8
|
+
File.readable?(file) or
|
9
|
+
raise ArgumentError, "file #{file.inspect} not readable"
|
10
|
+
LWES::TypeDB.new(file)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def class_for(options, dump)
|
15
|
+
klass = options[:class] || begin
|
16
|
+
# make it easier to deal with single event files
|
17
|
+
events = (dump.keys - [ :MetaEventInfo ])
|
18
|
+
events.size > 1 and
|
19
|
+
raise RuntimeError,
|
20
|
+
"multiple event defs available: #{events.inspect}\n" \
|
21
|
+
"pick one with :class"
|
22
|
+
events.first
|
23
|
+
end
|
24
|
+
name = options[:name] || klass.to_s
|
25
|
+
event_def = dump[name.to_sym] or
|
26
|
+
raise RuntimeError, "#{name.inspect} not defined in #{file}"
|
27
|
+
[ klass, name, event_def ]
|
28
|
+
end
|
29
|
+
|
30
|
+
def set_constants(tmp, db, klass, name, options)
|
31
|
+
tmp.const_set :TYPE_DB, db
|
32
|
+
tmp.const_set :NAME, name.to_s.dup.freeze
|
33
|
+
defaults = options[:defaults] || {}
|
34
|
+
tmp.const_set :DEFAULTS, defaults.dup
|
35
|
+
parent = options.include?(:parent) ? options[:parent] : Object
|
36
|
+
parent or return
|
37
|
+
components = klass.to_s.split(/::/)
|
38
|
+
components.each_with_index do |component, i|
|
39
|
+
if i == (components.size - 1)
|
40
|
+
tmp = parent.const_set(component, tmp)
|
41
|
+
else
|
42
|
+
parent = begin
|
43
|
+
parent.const_get(component)
|
44
|
+
rescue NameError
|
45
|
+
parent.const_set component, Module.new
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
data/lib/lwes/event.rb
CHANGED
@@ -1,7 +1,57 @@
|
|
1
|
-
#
|
2
|
-
#
|
1
|
+
# Used for mapping LWES events in in an ESF file to a Ruby object.
|
2
|
+
# LWES::Event-derived classes are more memory efficient if your event
|
3
|
+
# definitions have many unused fields.
|
4
|
+
#
|
5
|
+
# LWES::TypeDB.create_classes! with +:sparse+ set to +true+
|
3
6
|
class LWES::Event
|
7
|
+
SYM2ATTR = Hash.new { |h,k| h[k] = k.to_s.freeze } # :nodoc:
|
8
|
+
|
9
|
+
# used to cache classes for LWES::Event.parse
|
10
|
+
CLASSES = {} # :nodoc:
|
11
|
+
extend LWES::ClassMaker
|
12
|
+
|
13
|
+
def self.subclass(options, &block)
|
14
|
+
db = type_db(options)
|
15
|
+
dump = db.to_hash
|
16
|
+
klass, name, event_def = class_for(options, dump)
|
17
|
+
tmp = Class.new(self)
|
18
|
+
set_constants(tmp, db, klass, name, options)
|
19
|
+
tmp.class_eval(&block) if block_given?
|
20
|
+
|
21
|
+
meta = dump[:MetaEventInfo] || []
|
22
|
+
methods = meta + event_def
|
23
|
+
methods = methods.inject("") do |str, (k,_)|
|
24
|
+
str << "def #{k}; self[:#{k}]; end\n"
|
25
|
+
str << "def #{k}= val; self[:#{k}] = val; end\n"
|
26
|
+
end
|
27
|
+
methods << "def initialize(src = nil); merge!(DEFAULTS); super; end\n"
|
28
|
+
tmp.class_eval methods
|
29
|
+
CLASSES[name] = tmp
|
30
|
+
end
|
31
|
+
|
4
32
|
def inspect
|
5
|
-
|
33
|
+
klass = self.class
|
34
|
+
if LWES::Event == klass
|
35
|
+
"#<#{klass}:#{to_hash.inspect}>"
|
36
|
+
else
|
37
|
+
"#<#{klass}(event:#{klass.const_get(:NAME)}):#{to_hash.inspect}>"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def merge! src
|
42
|
+
src.to_hash.each { |k,v| self[k] = v }
|
43
|
+
self
|
44
|
+
end
|
45
|
+
|
46
|
+
alias_method :initialize_copy, :merge!
|
47
|
+
|
48
|
+
def merge src
|
49
|
+
dup.merge! src
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def initialize(src = nil)
|
55
|
+
src and merge! src
|
6
56
|
end
|
7
57
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
#
|
2
|
+
# This class is only supported on Ruby 1.9
|
3
|
+
#
|
4
|
+
# listener = LWES::Listener.new :address => "224.1.1.11", :port => 12345
|
5
|
+
# listener.each do |event|
|
6
|
+
# p event
|
7
|
+
# end
|
8
|
+
#
|
9
|
+
class LWES::Listener
|
10
|
+
|
11
|
+
# we disallow dup-ing objects since GC could double-free otherwise
|
12
|
+
def dup
|
13
|
+
self
|
14
|
+
end
|
15
|
+
|
16
|
+
alias clone dup
|
17
|
+
|
18
|
+
# process each LWES::Event object as it is received
|
19
|
+
def each
|
20
|
+
begin
|
21
|
+
yield recv
|
22
|
+
rescue Errno::EINTR
|
23
|
+
end while true
|
24
|
+
self
|
25
|
+
end
|
26
|
+
end
|