statsrb 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/ext/statsrb/extconf.rb +3 -0
- data/ext/statsrb/statsrb.c +450 -0
- data/lib/statsrb.rb +37 -0
- metadata +49 -0
@@ -0,0 +1,450 @@
|
|
1
|
+
#include <ruby.h>
|
2
|
+
#include <stdio.h>
|
3
|
+
#include <string.h>
|
4
|
+
#include <stdlib.h>
|
5
|
+
|
6
|
+
/**
|
7
|
+
* Loads a file and filters on a specified namespace.
|
8
|
+
*/
|
9
|
+
static VALUE statsrb_query(VALUE self, VALUE logfile, VALUE query_ns, VALUE query_limit, VALUE query_start, VALUE query_end) {
|
10
|
+
FILE * file;
|
11
|
+
int line_size = 256;
|
12
|
+
char *line = (char *) malloc(line_size);
|
13
|
+
const char *filepath = RSTRING_PTR(logfile);
|
14
|
+
const char *query_ns_char = RSTRING_PTR(query_ns);
|
15
|
+
|
16
|
+
// @data hash key symbols.
|
17
|
+
VALUE statsrb_key_ts = rb_iv_get(self, "@key_ts");
|
18
|
+
VALUE statsrb_key_ns = rb_iv_get(self, "@key_ns");
|
19
|
+
VALUE statsrb_key_v = rb_iv_get(self, "@key_v");
|
20
|
+
// Create an empty string for comparison.
|
21
|
+
VALUE statsrb_str_empty = rb_str_new2("");
|
22
|
+
|
23
|
+
// Convert into an int that ruby understands.
|
24
|
+
int limit = NUM2INT(query_limit);
|
25
|
+
int qstart = NUM2INT(query_start);
|
26
|
+
int qend = NUM2INT(query_end);
|
27
|
+
|
28
|
+
// Return array instantiation.
|
29
|
+
VALUE statsrb_data = rb_iv_get(self, "@data");
|
30
|
+
// @TODO does this garbage collect all of the old hash data?
|
31
|
+
rb_ary_resize(statsrb_data, 0);
|
32
|
+
|
33
|
+
file = fopen(filepath, "r");
|
34
|
+
if (file == NULL) {
|
35
|
+
fprintf(stderr, "File error: could not open file %s for reading.", filepath);
|
36
|
+
return;
|
37
|
+
}
|
38
|
+
|
39
|
+
int count = 0;
|
40
|
+
|
41
|
+
while (NULL != fgets(line, line_size, file) && count < limit) {
|
42
|
+
// strstr doesn't work with newline chars.
|
43
|
+
size_t len = strlen(line) - 1;
|
44
|
+
if (line[len] == '\n');
|
45
|
+
line[len] = '\0';
|
46
|
+
|
47
|
+
// If the namespace is in the row, explode it.
|
48
|
+
if (line[0] != '\0' && line[0] != '\n' && strchr(line, query_ns_char[0]) && strstr(line, query_ns_char)) {
|
49
|
+
VALUE statsrb_event = rb_hash_new();
|
50
|
+
|
51
|
+
// I tried sscanf for convenience, but it was predictably slower.
|
52
|
+
//int statsrb_ts, statsrb_v;
|
53
|
+
//sscanf(line, "%d\t%*s\t%d", &statsrb_ts, &statsrb_v);
|
54
|
+
|
55
|
+
// @TODO this should something more robust than atoi.
|
56
|
+
int statsrb_ts = atoi(strtok(line, "\t"));
|
57
|
+
|
58
|
+
if (statsrb_ts != NULL && (qstart == 0 || statsrb_ts >= qstart) && (qend == 0 || statsrb_ts <= qend)) {
|
59
|
+
// @TODO this should probably use the actual namespace if we do wildcard queries.
|
60
|
+
VALUE statsrb_str_ns = rb_str_new2(strtok(NULL, "\t"));
|
61
|
+
//strtok(NULL, "\t");
|
62
|
+
int statsrb_v = atoi(strtok(NULL, "\0"));
|
63
|
+
|
64
|
+
// @TODO this should really query the namespace exactly instead of just relying on strstr.
|
65
|
+
//if (rb_str_cmp(query_ns, statsrb_str_empty) == 0 || rb_str_cmp(query_ns, statsrb_str_ns) == 0) {
|
66
|
+
if (statsrb_ts && (statsrb_v || statsrb_v == 0)) {
|
67
|
+
rb_hash_aset(statsrb_event, statsrb_key_ts, INT2NUM(statsrb_ts));
|
68
|
+
rb_hash_aset(statsrb_event, statsrb_key_ns, statsrb_str_ns);
|
69
|
+
//rb_hash_aset(statsrb_event, statsrb_key_ns, query_ns);
|
70
|
+
rb_hash_aset(statsrb_event, statsrb_key_v, INT2NUM(statsrb_v));
|
71
|
+
rb_ary_push(statsrb_data, statsrb_event);
|
72
|
+
count++;
|
73
|
+
}
|
74
|
+
}
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
// terminate
|
79
|
+
fclose (file);
|
80
|
+
free (line);
|
81
|
+
|
82
|
+
//return statsrb_data;
|
83
|
+
//rb_iv_set(self, "@data", statsrb_data);
|
84
|
+
|
85
|
+
return self;
|
86
|
+
}
|
87
|
+
|
88
|
+
/**
|
89
|
+
* Implementation of quicksort algorithm.
|
90
|
+
*/
|
91
|
+
void time_sort(int left, int right, VALUE ary, VALUE statsrb_key_ts) {
|
92
|
+
int i = left;
|
93
|
+
int j = right;
|
94
|
+
int p = (i + j) / 2;
|
95
|
+
int pv = NUM2INT(rb_hash_aref(rb_ary_entry(ary, p), statsrb_key_ts));
|
96
|
+
VALUE tmp;
|
97
|
+
|
98
|
+
while (i <= j) {
|
99
|
+
while (NUM2INT(rb_hash_aref(rb_ary_entry(ary, i), statsrb_key_ts)) < pv) {
|
100
|
+
i++;
|
101
|
+
}
|
102
|
+
while (NUM2INT(rb_hash_aref(rb_ary_entry(ary, j), statsrb_key_ts)) > pv) {
|
103
|
+
j--;
|
104
|
+
}
|
105
|
+
if (i <= j) {
|
106
|
+
tmp = rb_ary_entry(ary, i);
|
107
|
+
rb_ary_store(ary, i, rb_ary_entry(ary, j));
|
108
|
+
rb_ary_store(ary, j, tmp);
|
109
|
+
i++;
|
110
|
+
j--;
|
111
|
+
}
|
112
|
+
}
|
113
|
+
|
114
|
+
if (left < j) {
|
115
|
+
time_sort(left, j, ary, statsrb_key_ts);
|
116
|
+
}
|
117
|
+
if (i < right) {
|
118
|
+
time_sort(i, right, ary, statsrb_key_ts);
|
119
|
+
}
|
120
|
+
}
|
121
|
+
|
122
|
+
/**
|
123
|
+
* Sort the internal data using a quicksort algorithm based on the hash element's timestamp.
|
124
|
+
*/
|
125
|
+
static VALUE statsrb_sort(VALUE self) {
|
126
|
+
VALUE statsrb_data = rb_iv_get(self, "@data");
|
127
|
+
int len = RARRAY_LEN(statsrb_data);
|
128
|
+
if (len > 0) {
|
129
|
+
VALUE statsrb_key_ts = rb_iv_get(self, "@key_ts");
|
130
|
+
time_sort(0, len - 1, statsrb_data, statsrb_key_ts);
|
131
|
+
}
|
132
|
+
return statsrb_data;
|
133
|
+
}
|
134
|
+
|
135
|
+
/**
|
136
|
+
* Write the in-memory data to a file.
|
137
|
+
*/
|
138
|
+
static VALUE statsrb_write(VALUE self, VALUE logfile, VALUE mode) {
|
139
|
+
FILE * file;
|
140
|
+
const char *filepath = RSTRING_PTR(logfile);
|
141
|
+
const char *filemode = RSTRING_PTR(mode);
|
142
|
+
VALUE statsrb_data = rb_iv_get(self, "@data");
|
143
|
+
int data_length = RARRAY_LEN(statsrb_data);
|
144
|
+
int i;
|
145
|
+
int line_size = 256;
|
146
|
+
int tmp_ts, tmp_v;
|
147
|
+
const char *tmp_ns = (char *) malloc(line_size);
|
148
|
+
|
149
|
+
// @data hash key symbols.
|
150
|
+
VALUE statsrb_key_ts = rb_iv_get(self, "@key_ts");
|
151
|
+
VALUE statsrb_key_ns = rb_iv_get(self, "@key_ns");
|
152
|
+
VALUE statsrb_key_v = rb_iv_get(self, "@key_v");
|
153
|
+
|
154
|
+
file = fopen(filepath, filemode);
|
155
|
+
if (file==NULL) {
|
156
|
+
fprintf(stderr, "File error: could not open file %s mode %s.", filepath, filemode);
|
157
|
+
return;
|
158
|
+
}
|
159
|
+
|
160
|
+
// Iterate through the data array, writing the data as we go.
|
161
|
+
for (i = 0; i < data_length; i++) {
|
162
|
+
// @TODO make sure that these values are not empty before writing.
|
163
|
+
//VALUE tmp_line = rb_str_tmp_new(line_size);
|
164
|
+
tmp_ts = NUM2INT(rb_hash_aref(rb_ary_entry(statsrb_data, i), statsrb_key_ts));
|
165
|
+
tmp_ns = RSTRING_PTR(rb_hash_aref(rb_ary_entry(statsrb_data, i), statsrb_key_ns));
|
166
|
+
tmp_v = NUM2INT(rb_hash_aref(rb_ary_entry(statsrb_data, i), statsrb_key_v));
|
167
|
+
fprintf(file, "%d\t%s\t%d\n", tmp_ts, tmp_ns, tmp_v);
|
168
|
+
//rb_str_free(tmp_line);
|
169
|
+
}
|
170
|
+
|
171
|
+
fclose (file);
|
172
|
+
return self;
|
173
|
+
}
|
174
|
+
|
175
|
+
/**
|
176
|
+
* A method to split unique namespaces from internal memory and write them to individual files.
|
177
|
+
*/
|
178
|
+
static VALUE statsrb_split_write(VALUE self, VALUE logdir, VALUE mode) {
|
179
|
+
VALUE statsrb_data = rb_iv_get(self, "@data");
|
180
|
+
int len = RARRAY_LEN(statsrb_data);
|
181
|
+
int i, ii, ns_len;
|
182
|
+
|
183
|
+
// @data hash key symbols.
|
184
|
+
VALUE statsrb_key_ts = rb_iv_get(self, "@key_ts");
|
185
|
+
VALUE statsrb_key_ns = rb_iv_get(self, "@key_ns");
|
186
|
+
VALUE statsrb_key_v = rb_iv_get(self, "@key_v");
|
187
|
+
|
188
|
+
VALUE ns_list = rb_ary_new();
|
189
|
+
|
190
|
+
for (i = 0; i < len; i++) {
|
191
|
+
if (!rb_ary_includes(ns_list, rb_hash_aref(rb_ary_entry(statsrb_data, i), statsrb_key_ns))) {
|
192
|
+
rb_ary_push(ns_list, rb_hash_aref(rb_ary_entry(statsrb_data, i), statsrb_key_ns));
|
193
|
+
}
|
194
|
+
}
|
195
|
+
|
196
|
+
ns_len = RARRAY_LEN(ns_list);
|
197
|
+
|
198
|
+
for (i = 0; i < ns_len; i++) {
|
199
|
+
VALUE tmp = rb_obj_dup(self);
|
200
|
+
VALUE tmp_data = rb_ary_new();
|
201
|
+
for (ii = 0; ii < len; ii++) {
|
202
|
+
if (rb_str_cmp(rb_ary_entry(ns_list, i), rb_hash_aref(rb_ary_entry(statsrb_data, ii), statsrb_key_ns)) == 0) {
|
203
|
+
rb_ary_push(tmp_data, rb_ary_entry(statsrb_data, ii));
|
204
|
+
}
|
205
|
+
}
|
206
|
+
//fputs (RSTRING_PTR(rb_obj_as_string(INT2NUM(RARRAY_LEN(tmp_data)))),stderr);
|
207
|
+
rb_iv_set(tmp, "@data", tmp_data);
|
208
|
+
|
209
|
+
// @todo, throw an exception if no trailing slash... or add one
|
210
|
+
statsrb_write(tmp, rb_str_plus(logdir, rb_ary_entry(ns_list, i)), mode);
|
211
|
+
}
|
212
|
+
|
213
|
+
return self;
|
214
|
+
}
|
215
|
+
|
216
|
+
/**
|
217
|
+
* Parses the query string parameters.
|
218
|
+
*
|
219
|
+
* @param char * qs
|
220
|
+
* The location of the query string.
|
221
|
+
*
|
222
|
+
* @return VALUE
|
223
|
+
* The ruby hash containing the query string keys and values.
|
224
|
+
*/
|
225
|
+
static VALUE statsrb_parse_qs(char *qs) {
|
226
|
+
char *qsk, *qsv;
|
227
|
+
VALUE query_string_tmp = rb_ary_new();
|
228
|
+
VALUE query_string = rb_hash_new();
|
229
|
+
qsk = strtok(qs, "&\0");
|
230
|
+
while (qsk != NULL) {
|
231
|
+
rb_ary_push(query_string_tmp, rb_str_new2(qsk));
|
232
|
+
qsk = strtok(NULL, "&\0");
|
233
|
+
}
|
234
|
+
int qslen = RARRAY_LEN(query_string_tmp);
|
235
|
+
int qsi;
|
236
|
+
for (qsi = 0; qsi < qslen; qsi++) {
|
237
|
+
qsk = strtok(RSTRING_PTR(rb_ary_entry(query_string_tmp, qsi)), "=\0");
|
238
|
+
qsv = strtok(NULL, "\0");
|
239
|
+
if (qsv != NULL) {
|
240
|
+
rb_hash_aset(query_string, rb_str_new2(qsk), rb_str_new2(qsv));
|
241
|
+
}
|
242
|
+
else if(qsk != NULL && qsv != NULL) {
|
243
|
+
rb_hash_aset(query_string, rb_str_new2(qsk), rb_str_new2(""));
|
244
|
+
}
|
245
|
+
}
|
246
|
+
|
247
|
+
return query_string;
|
248
|
+
}
|
249
|
+
|
250
|
+
/**
|
251
|
+
* A method that is compatible with the rack api.
|
252
|
+
*/
|
253
|
+
static VALUE statsrb_rack_call(VALUE self, VALUE env) {
|
254
|
+
VALUE response = rb_ary_new();
|
255
|
+
VALUE headers = rb_hash_new();
|
256
|
+
VALUE body = rb_ary_new();
|
257
|
+
VALUE statsrb_data = rb_iv_get(self, "@data");
|
258
|
+
VALUE statsrb_hash = rb_hash_new();
|
259
|
+
|
260
|
+
// @data hash key symbols.
|
261
|
+
VALUE statsrb_key_ts = rb_iv_get(self, "@key_ts");
|
262
|
+
VALUE statsrb_key_ns = rb_iv_get(self, "@key_ns");
|
263
|
+
VALUE statsrb_key_v = rb_iv_get(self, "@key_v");
|
264
|
+
|
265
|
+
char *path = RSTRING_PTR(rb_hash_aref(env, rb_str_new2("PATH_INFO")));
|
266
|
+
|
267
|
+
rb_hash_aset(headers, rb_str_new2("Content-Type"), rb_str_new2("text/json"));
|
268
|
+
|
269
|
+
// Parse the query string
|
270
|
+
char *qs = RSTRING_PTR(rb_hash_aref(env, rb_str_new2("QUERY_STRING")));
|
271
|
+
VALUE query_string = statsrb_parse_qs(qs);
|
272
|
+
|
273
|
+
//const char *method = RSTRING_PTR(rb_hash_aref(env, rb_str_new2("REQUEST_METHOD")));
|
274
|
+
// @TODO consider moving the request method to the proper REQUEST_METHOD
|
275
|
+
const char *method_get = "GET";
|
276
|
+
const char *method_put = "PUT";
|
277
|
+
// Remove the leading /
|
278
|
+
path++;
|
279
|
+
const char *method = strtok(path, "/\0");
|
280
|
+
if (method && strcmp(method, method_put) == 0) {
|
281
|
+
long int statsrb_ts, statsrb_v;
|
282
|
+
|
283
|
+
// Get the timestamp, default to now.
|
284
|
+
VALUE statsrb_ts_qs = rb_hash_aref(query_string, rb_str_new("time", 4));
|
285
|
+
if (statsrb_ts_qs != Qnil) {
|
286
|
+
statsrb_ts = atoi(RSTRING_PTR(statsrb_ts_qs ));
|
287
|
+
}
|
288
|
+
else {
|
289
|
+
statsrb_ts = (long int)time(NULL);
|
290
|
+
}
|
291
|
+
|
292
|
+
// Get the namespace.
|
293
|
+
VALUE statsrb_ns = rb_hash_aref(query_string, rb_str_new("name", 4));
|
294
|
+
if (statsrb_ns == Qnil) {
|
295
|
+
statsrb_ns = NULL;
|
296
|
+
}
|
297
|
+
|
298
|
+
if (statsrb_ns) {
|
299
|
+
// Get the value.
|
300
|
+
statsrb_v= 0;
|
301
|
+
VALUE statsrb_v_qs = rb_hash_aref(query_string, rb_str_new("value", 5));
|
302
|
+
if (statsrb_v_qs != Qnil) {
|
303
|
+
statsrb_v = atoi(RSTRING_PTR(statsrb_v_qs));
|
304
|
+
}
|
305
|
+
|
306
|
+
rb_hash_aset(statsrb_hash, statsrb_key_ts, INT2NUM(statsrb_ts));
|
307
|
+
rb_hash_aset(statsrb_hash, statsrb_key_ns, statsrb_ns);
|
308
|
+
rb_hash_aset(statsrb_hash, statsrb_key_v, INT2NUM(statsrb_v));
|
309
|
+
rb_ary_push(statsrb_data, statsrb_hash);
|
310
|
+
|
311
|
+
int data_length = RARRAY_LEN(statsrb_data);
|
312
|
+
rb_ary_push(body, rb_obj_as_string(INT2NUM(RARRAY_LEN(statsrb_data))));
|
313
|
+
if (data_length > 9) {
|
314
|
+
statsrb_sort(self);
|
315
|
+
statsrb_split_write(self, rb_iv_get(self, "@split_file_dir"), rb_str_new2("a+"));
|
316
|
+
rb_ary_resize(statsrb_data, 0);
|
317
|
+
}
|
318
|
+
|
319
|
+
rb_ary_push(body, statsrb_ns);
|
320
|
+
}
|
321
|
+
}
|
322
|
+
else if (method && strcmp(method, method_get) == 0) {
|
323
|
+
const char * statsrb_str_ns = strtok(NULL, "/\0");
|
324
|
+
if (statsrb_str_ns == NULL) {
|
325
|
+
statsrb_str_ns = "data";
|
326
|
+
}
|
327
|
+
|
328
|
+
VALUE jsoncallback = rb_hash_aref(query_string, rb_str_new("jsoncallback", 12));
|
329
|
+
if (jsoncallback != Qnil) {
|
330
|
+
rb_ary_push(body, rb_str_plus(jsoncallback, rb_str_new("(", 1)));
|
331
|
+
}
|
332
|
+
char json_start[256];
|
333
|
+
sprintf(json_start, "{\"%s\":[", statsrb_str_ns);
|
334
|
+
rb_ary_push(body, rb_str_new2(json_start));
|
335
|
+
|
336
|
+
// If they didn't specify a namespace, bail out immediately.
|
337
|
+
if (statsrb_str_ns) {
|
338
|
+
VALUE statsrb_ns = rb_str_new2(statsrb_str_ns);
|
339
|
+
long int query_limit, query_start, query_end;
|
340
|
+
|
341
|
+
// Get the query limit.
|
342
|
+
query_limit = 100;
|
343
|
+
VALUE query_limit_qs = rb_hash_aref(query_string, rb_str_new("limit", 5));
|
344
|
+
if (query_limit_qs != Qnil) {
|
345
|
+
query_limit = atoi(RSTRING_PTR(query_limit_qs));
|
346
|
+
}
|
347
|
+
|
348
|
+
// Get the query start.
|
349
|
+
query_start = 0;
|
350
|
+
VALUE query_start_qs = rb_hash_aref(query_string, rb_str_new("start", 5));
|
351
|
+
if (query_start_qs != Qnil) {
|
352
|
+
query_start = atoi(RSTRING_PTR(query_start_qs));
|
353
|
+
}
|
354
|
+
|
355
|
+
// Get the query end.
|
356
|
+
query_end = 0;
|
357
|
+
VALUE query_end_qs = rb_hash_aref(query_string, rb_str_new("end", 3));
|
358
|
+
if (query_end_qs != Qnil) {
|
359
|
+
query_end = atoi(RSTRING_PTR(query_end_qs));
|
360
|
+
}
|
361
|
+
|
362
|
+
// Get the past N seconds of data.
|
363
|
+
// @TODO the query method fails if we query for data newer than the last entry.
|
364
|
+
VALUE query_recent = rb_hash_aref(query_string, rb_str_new("recent", 6));
|
365
|
+
if (query_recent != Qnil) {
|
366
|
+
query_end = (long int)time(NULL);
|
367
|
+
long int history = atoi(RSTRING_PTR(query_recent));
|
368
|
+
query_start = query_end - history;
|
369
|
+
}
|
370
|
+
|
371
|
+
// Create a new Statsrb object to query from.
|
372
|
+
// @todo we probably need to assign a new array to @data to avoid messing up the pointers.
|
373
|
+
VALUE tmp = rb_obj_dup(self);
|
374
|
+
VALUE tmp_data = rb_ary_new();
|
375
|
+
rb_iv_set(tmp, "@data", tmp_data);
|
376
|
+
statsrb_query(tmp, rb_str_plus(rb_iv_get(self, "@split_file_dir"), statsrb_ns), statsrb_ns, INT2NUM(query_limit), INT2NUM(query_start), INT2NUM(query_end));
|
377
|
+
statsrb_sort(tmp);
|
378
|
+
|
379
|
+
int i, data_length = RARRAY_LEN(tmp_data);
|
380
|
+
|
381
|
+
for (i = 0; i < data_length; i++) {
|
382
|
+
rb_ary_push(body, rb_str_new("[", 1));
|
383
|
+
rb_ary_push(body, rb_obj_as_string(rb_hash_aref(rb_ary_entry(tmp_data, i), statsrb_key_ts )));
|
384
|
+
rb_ary_push(body, rb_str_new(",", 1));
|
385
|
+
rb_ary_push(body, rb_obj_as_string(rb_hash_aref(rb_ary_entry(tmp_data, i), statsrb_key_v )));
|
386
|
+
rb_ary_push(body, rb_str_new("]", 1));
|
387
|
+
if (i < data_length - 1) {
|
388
|
+
rb_ary_push(body, rb_str_new(",", 1));
|
389
|
+
}
|
390
|
+
rb_ary_push(body, rb_str_new("\n", 1));
|
391
|
+
}
|
392
|
+
rb_ary_resize(tmp_data, 0);
|
393
|
+
}
|
394
|
+
rb_ary_push(body, rb_str_new("]}", 2));
|
395
|
+
if (jsoncallback != Qnil) {
|
396
|
+
rb_ary_push(body, rb_str_new(")", 1));
|
397
|
+
}
|
398
|
+
}
|
399
|
+
else {
|
400
|
+
rb_ary_push(response, INT2NUM(404));
|
401
|
+
rb_ary_push(response, headers);
|
402
|
+
rb_ary_push(response, body);
|
403
|
+
return response;
|
404
|
+
}
|
405
|
+
|
406
|
+
rb_ary_push(response, INT2NUM(200));
|
407
|
+
rb_ary_push(response, headers);
|
408
|
+
rb_ary_push(response, body);
|
409
|
+
|
410
|
+
return response;
|
411
|
+
}
|
412
|
+
|
413
|
+
/**
|
414
|
+
* Class constructor, sets up an instance variable.
|
415
|
+
*/
|
416
|
+
static VALUE statsrb_constructor(VALUE self) {
|
417
|
+
VALUE statsrb_data = rb_ary_new();
|
418
|
+
rb_iv_set(self, "@data", statsrb_data);
|
419
|
+
VALUE statsrb_split_file_dir = rb_str_new("/tmp", 4);
|
420
|
+
rb_iv_set(self, "@split_file_dir", statsrb_split_file_dir);
|
421
|
+
|
422
|
+
// Internal symbols for :ts, :ns and :v.
|
423
|
+
VALUE statsrb_key_ts = rb_str_intern(rb_str_new2("ts"));
|
424
|
+
rb_iv_set(self, "@key_ts", statsrb_key_ts);
|
425
|
+
VALUE statsrb_key_ns = rb_str_intern(rb_str_new2("ns"));
|
426
|
+
rb_iv_set(self, "@key_ns", statsrb_key_ns);
|
427
|
+
VALUE statsrb_key_v = rb_str_intern(rb_str_new2("v"));
|
428
|
+
rb_iv_set(self, "@key_v", statsrb_key_v);
|
429
|
+
|
430
|
+
return self;
|
431
|
+
}
|
432
|
+
|
433
|
+
/**
|
434
|
+
* Init the Statsrb class.
|
435
|
+
*/
|
436
|
+
void Init_statsrb(void) {
|
437
|
+
VALUE klass = rb_define_class("Statsrb", rb_cObject);
|
438
|
+
|
439
|
+
// Instance methods and properties.
|
440
|
+
rb_define_method(klass, "initialize", statsrb_constructor, 0);
|
441
|
+
rb_define_method(klass, "query", statsrb_query, 5);
|
442
|
+
rb_define_method(klass, "sort", statsrb_sort, 0);
|
443
|
+
rb_define_method(klass, "write", statsrb_write, 2);
|
444
|
+
rb_define_method(klass, "split_write", statsrb_split_write, 2);
|
445
|
+
rb_define_method(klass, "call", statsrb_rack_call, 1);
|
446
|
+
// Define :attr_accessor (read/write instance var)
|
447
|
+
// Note that this must correspond with a call to rb_iv_self() and it's string name must be @data.
|
448
|
+
rb_define_attr(klass, "data", 1, 1);
|
449
|
+
rb_define_attr(klass, "split_file_dir", 1, 1);
|
450
|
+
}
|
data/lib/statsrb.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'statsrb/statsrb'
|
2
|
+
|
3
|
+
# @author Kevin Hankens
|
4
|
+
class Statsrb
|
5
|
+
# [!{:ts => Time.now.to_i, :ns => "test", :v => 33}]
|
6
|
+
attr_accessor :data
|
7
|
+
|
8
|
+
# Writes the @data in memory to a specified file.
|
9
|
+
# @param filepath [String]
|
10
|
+
# @param filemode [String]
|
11
|
+
# @return Statsrb
|
12
|
+
def write filepath, filemode
|
13
|
+
end
|
14
|
+
|
15
|
+
# Splits namespaces in @data in memory to a separate files.
|
16
|
+
# @param filepath [String]
|
17
|
+
# @param filemode [String]
|
18
|
+
# @return Statsrb
|
19
|
+
def split_write filepath, filemode
|
20
|
+
end
|
21
|
+
|
22
|
+
# Locates data from a specified file and loads into @data.
|
23
|
+
# @param filepath [String]
|
24
|
+
# @param namespace [String]
|
25
|
+
# @param limit [Number]
|
26
|
+
# @param start_time [Number]
|
27
|
+
# @param end_time [Number]
|
28
|
+
# @return Statsrb
|
29
|
+
def query filepath, namespace, limit, start_time, end_time
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns a rack-compatable response.
|
33
|
+
# @param env [Hash]
|
34
|
+
def sort env
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
metadata
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: statsrb
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Kevin Hankens
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-06-08 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: A ruby stats repository.
|
15
|
+
email: email@kevinhankens.com
|
16
|
+
executables: []
|
17
|
+
extensions:
|
18
|
+
- ext/statsrb/extconf.rb
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- lib/statsrb.rb
|
22
|
+
- ext/statsrb/statsrb.c
|
23
|
+
- ext/statsrb/extconf.rb
|
24
|
+
homepage: https://github.com/kevinhankens/statsrb
|
25
|
+
licenses: []
|
26
|
+
post_install_message:
|
27
|
+
rdoc_options: []
|
28
|
+
require_paths:
|
29
|
+
- lib
|
30
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ! '>='
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: '0'
|
36
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
37
|
+
none: false
|
38
|
+
requirements:
|
39
|
+
- - ! '>='
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
requirements: []
|
43
|
+
rubyforge_project:
|
44
|
+
rubygems_version: 1.8.25
|
45
|
+
signing_key:
|
46
|
+
specification_version: 3
|
47
|
+
summary: Statsrb
|
48
|
+
test_files: []
|
49
|
+
has_rdoc:
|