durable_rules 0.34.57 → 2.00.001

Sign up to get free protection for your applications and to get access to all the features.
data/deps/hiredis/win32.h DELETED
@@ -1,42 +0,0 @@
1
- #ifndef _WIN32_HELPER_INCLUDE
2
- #define _WIN32_HELPER_INCLUDE
3
- #ifdef _MSC_VER
4
-
5
- #ifndef inline
6
- #define inline __inline
7
- #endif
8
-
9
- #ifndef va_copy
10
- #define va_copy(d,s) ((d) = (s))
11
- #endif
12
-
13
- #ifndef snprintf
14
- #define snprintf c99_snprintf
15
-
16
- __inline int c99_vsnprintf(char* str, size_t size, const char* format, va_list ap)
17
- {
18
- int count = -1;
19
-
20
- if (size != 0)
21
- count = _vsnprintf_s(str, size, _TRUNCATE, format, ap);
22
- if (count == -1)
23
- count = _vscprintf(format, ap);
24
-
25
- return count;
26
- }
27
-
28
- __inline int c99_snprintf(char* str, size_t size, const char* format, ...)
29
- {
30
- int count;
31
- va_list ap;
32
-
33
- va_start(ap, format);
34
- count = c99_vsnprintf(str, size, format, ap);
35
- va_end(ap);
36
-
37
- return count;
38
- }
39
- #endif
40
-
41
- #endif
42
- #endif
data/librb/interface.rb DELETED
@@ -1,126 +0,0 @@
1
- require "sinatra"
2
- require "json"
3
-
4
- module Interface
5
- class Application < Sinatra::Base
6
- set :bind, "0.0.0.0"
7
-
8
- @@host = nil
9
-
10
- def self.set_host(value)
11
- @@host = value
12
- end
13
-
14
- get "/:ruleset_name/state/:sid" do
15
- begin
16
- JSON.generate @@host.get_state(params["ruleset_name"], params["sid"])
17
- rescue Exception => e
18
- status 404
19
- e.to_s
20
- end
21
- end
22
-
23
- post "/:ruleset_name/state/:sid" do
24
- begin
25
- request.body.rewind
26
- state = JSON.parse request.body.read
27
- state["id"] = params["sid"]
28
- result = @@host.patch_state(params["ruleset_name"], state)
29
- JSON.generate({:outcome => result})
30
- rescue Exception => e
31
- status 500
32
- e.to_s
33
- end
34
- end
35
-
36
- get "/:ruleset_name/state" do
37
- begin
38
- JSON.generate @@host.get_state(params["ruleset_name"], "0")
39
- rescue Exception => e
40
- status 404
41
- e.to_s
42
- end
43
- end
44
-
45
- post "/:ruleset_name/state" do
46
- begin
47
- request.body.rewind
48
- state = JSON.parse request.body.read
49
- result = @@host.patch_state(params["ruleset_name"], state)
50
- JSON.generate({:outcome => result})
51
- rescue Exception => e
52
- status 500
53
- e.to_s
54
- end
55
- end
56
-
57
- post "/:ruleset_name/events/:sid" do
58
- begin
59
- request.body.rewind
60
- message = JSON.parse request.body.read
61
- message["sid"] = params["sid"]
62
- result = @@host.post(params["ruleset_name"], message)
63
- JSON.generate({:outcome => result})
64
- rescue Exception => e
65
- status 500
66
- e.to_s
67
- end
68
- end
69
-
70
- post "/:ruleset_name/events" do
71
- begin
72
- request.body.rewind
73
- message = JSON.parse request.body.read
74
- result = @@host.post(params["ruleset_name"], message)
75
- JSON.generate({:outcome => result})
76
- rescue Exception => e
77
- status 500
78
- e.to_s
79
- end
80
- end
81
-
82
- post "/:ruleset_name/facts/:sid" do
83
- begin
84
- request.body.rewind
85
- message = JSON.parse request.body.read
86
- message["sid"] = params["sid"]
87
- result = @@host.assert(params["ruleset_name"], message)
88
- JSON.generate({:outcome => result})
89
- rescue Exception => e
90
- status 500
91
- e.to_s
92
- end
93
- end
94
-
95
- post "/:ruleset_name/facts" do
96
- begin
97
- request.body.rewind
98
- message = JSON.parse request.body.read
99
- result = @@host.assert(params["ruleset_name"], message)
100
- JSON.generate({:outcome => result})
101
- rescue Exception => e
102
- status 500
103
- e.to_s
104
- end
105
- end
106
-
107
- get "/:ruleset_name/definition" do
108
- begin
109
- @@host.get_ruleset(params["ruleset_name"]).to_json
110
- rescue Exception => e
111
- status 404
112
- e.to_s
113
- end
114
- end
115
-
116
- post "/:ruleset_name/definition" do
117
- begin
118
- request.body.rewind
119
- @@host.set_ruleset params["ruleset_name"], JSON.parse(request.body.read)
120
- rescue Exception => e
121
- status 500
122
- e.to_s
123
- end
124
- end
125
- end
126
- end
data/src/rules/net.c DELETED
@@ -1,3257 +0,0 @@
1
- #include <stdio.h>
2
- #include <stdlib.h>
3
- #include <string.h>
4
- #include <errno.h>
5
- #ifndef _WIN32
6
- #include <time.h> /* for struct timeval */
7
- #else
8
- #include <WinSock2.h>
9
- #endif
10
- #include "net.h"
11
- #include "rules.h"
12
- #include "json.h"
13
-
14
- #define VERIFY(result, origin) do { \
15
- if (result != REDIS_OK) { \
16
- return ERR_REDIS_ERROR; \
17
- } \
18
- redisReply *reply; \
19
- result = tryGetReply(reContext, &reply); \
20
- if (result != RULES_OK) { \
21
- return result; \
22
- } \
23
- if (reply->type == REDIS_REPLY_ERROR) { \
24
- printf(origin); \
25
- printf(" err string %s\n", reply->str); \
26
- freeReplyObject(reply); \
27
- return ERR_REDIS_ERROR; \
28
- } \
29
- freeReplyObject(reply);\
30
- } while(0)
31
-
32
- #define GET_REPLY(result, origin, reply) do { \
33
- if (result != REDIS_OK) { \
34
- return ERR_REDIS_ERROR; \
35
- } \
36
- result = tryGetReply(reContext, &reply); \
37
- if (result != RULES_OK) { \
38
- return result; \
39
- } \
40
- if (reply->type == REDIS_REPLY_ERROR) { \
41
- printf(origin); \
42
- printf(" err string %s\n", reply->str); \
43
- freeReplyObject(reply); \
44
- return ERR_REDIS_ERROR; \
45
- } \
46
- } while(0)
47
-
48
- #ifdef _WIN32
49
- int asprintf(char** ret, char* format, ...){
50
- va_list args;
51
- *ret = NULL;
52
- if (!format) return 0;
53
- va_start(args, format);
54
- int size = _vscprintf(format, args);
55
- if (size == 0) {
56
- *ret = (char*)malloc(1);
57
- **ret = 0;
58
- }
59
- else {
60
- size++; //for null
61
- *ret = (char*)malloc(size + 2);
62
- if (*ret) {
63
- _vsnprintf(*ret, size, format, args);
64
- }
65
- else {
66
- return -1;
67
- }
68
- }
69
-
70
- va_end(args);
71
- return size;
72
- }
73
- #endif
74
-
75
- static unsigned int tryGetReply(redisContext *reContext,
76
- redisReply **reply) {
77
-
78
- if (redisGetReply(reContext, (void**)reply) != REDIS_OK) {
79
- printf("getReply err %d, %d, %s\n", reContext->err, errno, reContext->errstr);
80
- #ifndef _WIN32
81
- if (redisReconnect(reContext) != REDIS_OK) {
82
- printf("reconnect err %d, %d, %s\n", reContext->err, errno, reContext->errstr);
83
- return ERR_REDIS_ERROR;
84
- }
85
- return ERR_TRY_AGAIN;
86
- #else
87
- return ERR_REDIS_ERROR;
88
- #endif
89
- }
90
-
91
- return RULES_OK;
92
- }
93
-
94
- static unsigned int createIdiom(ruleset *tree, jsonValue *newValue, char **idiomString) {
95
- char *rightProperty;
96
- char *rightAlias;
97
- char *valueString;
98
- idiom *newIdiom;
99
- switch (newValue->type) {
100
- case JSON_EVENT_PROPERTY:
101
- rightProperty = &tree->stringPool[newValue->value.property.nameOffset];
102
- rightAlias = &tree->stringPool[newValue->value.property.idOffset];
103
- if (asprintf(idiomString, "frame[\"%s\"][\"%s\"]", rightAlias, rightProperty) == -1) {
104
- return ERR_OUT_OF_MEMORY;
105
- }
106
- break;
107
- case JSON_EVENT_LOCAL_PROPERTY:
108
- rightProperty = &tree->stringPool[newValue->value.property.nameOffset];
109
- if (asprintf(idiomString, "message[\"%s\"]", rightProperty) == -1) {
110
- return ERR_OUT_OF_MEMORY;
111
- }
112
- break;
113
- case JSON_EVENT_LOCAL_IDIOM:
114
- case JSON_EVENT_IDIOM:
115
- newIdiom = &tree->idiomPool[newValue->value.idiomOffset];
116
- char *op = "";
117
- switch (newIdiom->operator) {
118
- case OP_ADD:
119
- op = "+";
120
- break;
121
- case OP_SUB:
122
- op = "-";
123
- break;
124
- case OP_MUL:
125
- op = "*";
126
- break;
127
- case OP_DIV:
128
- op = "/";
129
- break;
130
- }
131
-
132
- char *rightIdiomString = NULL;
133
- unsigned int result = createIdiom(tree, &newIdiom->right, &rightIdiomString);
134
- if (result != RULES_OK) {
135
- return result;
136
- }
137
-
138
- char *leftIdiomString = NULL;
139
- result = createIdiom(tree, &newIdiom->left, &leftIdiomString);
140
- if (result != RULES_OK) {
141
- return result;
142
- }
143
-
144
- if (asprintf(idiomString, "(%s %s %s)", leftIdiomString, op, rightIdiomString) == -1) {
145
- return ERR_OUT_OF_MEMORY;
146
- }
147
-
148
- free(rightIdiomString);
149
- free(leftIdiomString);
150
- break;
151
- case JSON_STRING:
152
- valueString = &tree->stringPool[newValue->value.stringOffset];
153
- if (asprintf(idiomString, "%s", valueString) == -1) {
154
- return ERR_OUT_OF_MEMORY;
155
- }
156
- break;
157
- case JSON_INT:
158
- if (asprintf(idiomString, "%ld", newValue->value.i) == -1) {
159
- return ERR_OUT_OF_MEMORY;
160
- }
161
- break;
162
- case JSON_DOUBLE:
163
- if (asprintf(idiomString, "%g", newValue->value.d) == -1) {
164
- return ERR_OUT_OF_MEMORY;
165
- }
166
- break;
167
- case JSON_BOOL:
168
- if (newValue->value.b == 0) {
169
- if (asprintf(idiomString, "false") == -1) {
170
- return ERR_OUT_OF_MEMORY;
171
- }
172
- }
173
- else {
174
- if (asprintf(idiomString, "true") == -1) {
175
- return ERR_OUT_OF_MEMORY;
176
- }
177
- }
178
- break;
179
- }
180
-
181
- return RULES_OK;
182
- }
183
-
184
- static unsigned int createTest(ruleset *tree, expression *expr, char **test, char **primaryKey, char **primaryFrameKey) {
185
- char *comp = NULL;
186
- char *compStack[32];
187
- unsigned char compTop = 0;
188
- unsigned char first = 1;
189
- unsigned char setPrimaryKey = 0;
190
- *primaryKey = NULL;
191
- *primaryFrameKey = NULL;
192
- *test = (char*)calloc(1, sizeof(char));
193
- if (!*test) {
194
- return ERR_OUT_OF_MEMORY;
195
- }
196
-
197
- for (unsigned short i = 0; i < expr->termsLength; ++i) {
198
- unsigned int currentNodeOffset = tree->nextPool[expr->t.termsOffset + i];
199
- node *currentNode = &tree->nodePool[currentNodeOffset];
200
- if (currentNode->value.a.operator == OP_AND) {
201
- char *oldTest = *test;
202
- if (first) {
203
- setPrimaryKey = 1;
204
- if (asprintf(test, "%s(", *test) == -1) {
205
- return ERR_OUT_OF_MEMORY;
206
- }
207
- } else {
208
- if (asprintf(test, "%s %s (", *test, comp) == -1) {
209
- return ERR_OUT_OF_MEMORY;
210
- }
211
- }
212
- free(oldTest);
213
-
214
- compStack[compTop] = comp;
215
- ++compTop;
216
- comp = "and";
217
- first = 1;
218
- } else if (currentNode->value.a.operator == OP_OR) {
219
- char *oldTest = *test;
220
- if (first) {
221
- if (asprintf(test, "%s(", *test) == -1) {
222
- return ERR_OUT_OF_MEMORY;
223
- }
224
- } else {
225
- setPrimaryKey = 0;
226
- if (asprintf(test, "%s %s (", *test, comp) == -1) {
227
- return ERR_OUT_OF_MEMORY;
228
- }
229
- }
230
- free(oldTest);
231
-
232
- compStack[compTop] = comp;
233
- ++compTop;
234
- comp = "or";
235
- first = 1;
236
- } else if (currentNode->value.a.operator == OP_END) {
237
- --compTop;
238
- comp = compStack[compTop];
239
-
240
- char *oldTest = *test;
241
- if (asprintf(test, "%s)", *test) == -1) {
242
- return ERR_OUT_OF_MEMORY;
243
- }
244
- free(oldTest);
245
- } else if (currentNode->value.a.operator == OP_IALL || currentNode->value.a.operator == OP_IANY) {
246
- char *oldTest = *test;
247
- char *leftProperty = &tree->stringPool[currentNode->nameOffset];
248
- idiom *newIdiom = &tree->idiomPool[currentNode->value.a.right.value.idiomOffset];
249
- char *op = "";
250
- switch (newIdiom->operator) {
251
- case OP_LT:
252
- op = "0";
253
- break;
254
- case OP_LTE:
255
- op = "1";
256
- break;
257
- case OP_GT:
258
- op = "2";
259
- break;
260
- case OP_GTE:
261
- op = "3";
262
- break;
263
- case OP_EQ:
264
- op = "4";
265
- break;
266
- case OP_NEQ:
267
- op = "5";
268
- break;
269
- }
270
-
271
- char *par = "";
272
- if (currentNode->value.a.operator == OP_IALL) {
273
- par = "true";
274
- } else {
275
- par = "false";
276
- }
277
-
278
- char *idiomString = NULL;
279
- unsigned int result = createIdiom(tree, &newIdiom->right, &idiomString);
280
- if (result != RULES_OK) {
281
- return result;
282
- }
283
-
284
- if (first) {
285
- if (expr->distinct) {
286
- if (asprintf(test, "is_distinct_message(frame, message) and %scompare_array(message[\"%s\"], %s, %s, %s)", *test, leftProperty, idiomString, op, par) == -1) {
287
- return ERR_OUT_OF_MEMORY;
288
- }
289
- } else {
290
- if (asprintf(test, "%scompare_array(message[\"%s\"], %s, %s, %s)", *test, leftProperty, idiomString, op, par) == -1) {
291
- return ERR_OUT_OF_MEMORY;
292
- }
293
- }
294
-
295
- first = 0;
296
- } else {
297
- if (asprintf(test, "%s %s compare_array(message[\"%s\"], %s, %s, %s)", *test, comp, leftProperty, idiomString, op, par) == -1) {
298
- return ERR_OUT_OF_MEMORY;
299
- }
300
-
301
- first = 0;
302
- }
303
-
304
- free(idiomString);
305
- free(oldTest);
306
-
307
- } else {
308
- char *leftProperty = &tree->stringPool[currentNode->nameOffset];
309
- char *op = "";
310
- switch (currentNode->value.a.operator) {
311
- case OP_LT:
312
- op = "<";
313
- break;
314
- case OP_LTE:
315
- op = "<=";
316
- break;
317
- case OP_GT:
318
- op = ">";
319
- break;
320
- case OP_GTE:
321
- op = ">=";
322
- break;
323
- case OP_EQ:
324
- op = "==";
325
- break;
326
- case OP_NEQ:
327
- op = "~=";
328
- break;
329
- }
330
-
331
- char *idiomString = NULL;
332
- unsigned int result = createIdiom(tree, &currentNode->value.a.right, &idiomString);
333
- if (result != RULES_OK) {
334
- return result;
335
- }
336
-
337
- char *oldTest = *test;
338
- if (first) {
339
- if (expr->distinct) {
340
- if (asprintf(test, "is_distinct_message(frame, message) and %smessage[\"%s\"] %s %s", *test, leftProperty, op, idiomString) == -1) {
341
- return ERR_OUT_OF_MEMORY;
342
- }
343
- } else {
344
- if (asprintf(test, "%smessage[\"%s\"] %s %s", *test, leftProperty, op, idiomString) == -1) {
345
- return ERR_OUT_OF_MEMORY;
346
- }
347
- }
348
-
349
- first = 0;
350
- } else {
351
- if (asprintf(test, "%s %s message[\"%s\"] %s %s", *test, comp, leftProperty, op, idiomString) == -1) {
352
- return ERR_OUT_OF_MEMORY;
353
- }
354
- }
355
-
356
- if (setPrimaryKey && currentNode->value.a.operator == OP_EQ) {
357
- if (*primaryKey == NULL) {
358
- if (asprintf(primaryKey,
359
- " if not message[\"%s\"] then\n"
360
- " return \"\"\n"
361
- " else\n"
362
- " result = result .. tostring(message[\"%s\"])\n"
363
- " end\n",
364
- leftProperty,
365
- leftProperty) == -1) {
366
- return ERR_OUT_OF_MEMORY;
367
- }
368
-
369
- if (asprintf(primaryFrameKey,
370
- " if not %s then\n"
371
- " return \"\"\n"
372
- " else\n"
373
- " result = result .. tostring(%s)\n"
374
- " end\n",
375
- idiomString,
376
- idiomString) == -1) {
377
- return ERR_OUT_OF_MEMORY;
378
- }
379
- }
380
- else {
381
- char *oldKey = *primaryKey;
382
- if (asprintf(primaryKey,
383
- "%s if not message[\"%s\"] then\n"
384
- " return \"\"\n"
385
- " else\n"
386
- " result = result .. tostring(message[\"%s\"])\n"
387
- " end\n",
388
- *primaryKey,
389
- leftProperty,
390
- leftProperty) == -1) {
391
- return ERR_OUT_OF_MEMORY;
392
- }
393
- free(oldKey);
394
- oldKey = *primaryFrameKey;
395
- if (asprintf(primaryFrameKey,
396
- "%s if not %s then\n"
397
- " return \"\"\n"
398
- " else\n"
399
- " result = result .. tostring(%s)\n"
400
- " end\n",
401
- *primaryFrameKey,
402
- idiomString,
403
- idiomString) == -1) {
404
- return ERR_OUT_OF_MEMORY;
405
- }
406
- free(oldKey);
407
- }
408
- }
409
-
410
- free(idiomString);
411
- free(oldTest);
412
- }
413
- }
414
-
415
- if (first) {
416
- free(*test);
417
- if (asprintf(test, "1") == -1) {
418
- return ERR_OUT_OF_MEMORY;
419
- }
420
- }
421
-
422
- if (*primaryKey == NULL) {
423
- *primaryKey = (char*)calloc(1, sizeof(char));
424
- if (!*primaryKey) {
425
- return ERR_OUT_OF_MEMORY;
426
- }
427
-
428
- *primaryFrameKey = (char*)calloc(1, sizeof(char));
429
- if (!*primaryFrameKey) {
430
- return ERR_OUT_OF_MEMORY;
431
- }
432
- }
433
- return RULES_OK;
434
- }
435
-
436
- static unsigned int loadPartitionCommand(ruleset *tree, binding *rulesBinding) {
437
- char *name = &tree->stringPool[tree->nameOffset];
438
- redisContext *reContext = rulesBinding->reContext;
439
- redisReply *reply;
440
- char *lua = NULL;
441
- if (asprintf(&lua,
442
- "local partition_key = \"%s!p\"\n"
443
- "local res = redis.call(\"hget\", partition_key, ARGV[1])\n"
444
- "if (not res) then\n"
445
- " res = redis.call(\"hincrby\", partition_key, \"index\", 1)\n"
446
- " res = res %% tonumber(ARGV[2])\n"
447
- " redis.call(\"hset\", partition_key, ARGV[1], res)\n"
448
- "end\n"
449
- "return tonumber(res)\n", name) == -1) {
450
- return ERR_OUT_OF_MEMORY;
451
- }
452
-
453
- unsigned int result = redisAppendCommand(reContext, "SCRIPT LOAD %s", lua);
454
- GET_REPLY(result, "loadPartitionCommand", reply);
455
-
456
- strncpy(rulesBinding->partitionHash, reply->str, 40);
457
- rulesBinding->partitionHash[40] = '\0';
458
- freeReplyObject(reply);
459
- free(lua);
460
- return RULES_OK;
461
- }
462
-
463
- static unsigned int loadRemoveActionCommand(ruleset *tree, binding *rulesBinding) {
464
- char *name = &tree->stringPool[tree->nameOffset];
465
- redisContext *reContext = rulesBinding->reContext;
466
- redisReply *reply;
467
- char *lua = NULL;
468
- if (asprintf(&lua,
469
- "local delete_frame = function(key, action_key)\n"
470
- " local rule_action_key = redis.call(\"lpop\", key)\n"
471
- " local raw_count = redis.call(\"lpop\", key)\n"
472
- " if raw_count then"
473
- " local count = tonumber(string.sub(raw_count, 3))\n"
474
- " for i = 0, count - 1, 1 do\n"
475
- " local packed_frame = redis.call(\"rpop\", rule_action_key)\n"
476
- " end\n"
477
- " end\n"
478
- " return (redis.call(\"llen\", key) > 0)\n"
479
- "end\n"
480
- "local sid = ARGV[1]\n"
481
- "local max_score = tonumber(ARGV[2])\n"
482
- "local action_key = \"%s!a\"\n"
483
- "if delete_frame(action_key .. \"!\" .. sid, action_key) then\n"
484
- " redis.call(\"zadd\", action_key , max_score, sid)\n"
485
- "else\n"
486
- " redis.call(\"zrem\", action_key, sid)\n"
487
- "end\n", name) == -1) {
488
- return ERR_OUT_OF_MEMORY;
489
- }
490
-
491
- unsigned int result = redisAppendCommand(reContext, "SCRIPT LOAD %s", lua);
492
- GET_REPLY(result, "loadRemoveActionCommand", reply);
493
- strncpy(rulesBinding->removeActionHash, reply->str, 40);
494
- rulesBinding->removeActionHash[40] = '\0';
495
- freeReplyObject(reply);
496
- free(lua);
497
- return RULES_OK;
498
- }
499
-
500
- static unsigned int loadTimerCommand(ruleset *tree, binding *rulesBinding) {
501
- char *name = &tree->stringPool[tree->nameOffset];
502
- redisContext *reContext = rulesBinding->reContext;
503
- redisReply *reply;
504
- char *lua = NULL;
505
- if (asprintf(&lua,
506
- "local timer_key = \"%s!t\"\n"
507
- "local timestamp = tonumber(ARGV[1])\n"
508
- "local res = redis.call(\"zrangebyscore\", timer_key, 0, timestamp, \"limit\", 0, 50)\n"
509
- "if #res > 0 then\n"
510
- " for i = 1, #res, 1 do\n"
511
- " redis.call(\"zincrby\", timer_key, 10, tostring(res[i]))\n"
512
- " end\n"
513
- " return res\n"
514
- "end\n"
515
- "return 0\n", name) == -1) {
516
- return ERR_OUT_OF_MEMORY;
517
- }
518
-
519
- unsigned int result = redisAppendCommand(reContext, "SCRIPT LOAD %s", lua);
520
- GET_REPLY(result, "loadTimerCommand", reply);
521
-
522
- strncpy(rulesBinding->timersHash, reply->str, 40);
523
- rulesBinding->timersHash[40] = '\0';
524
- freeReplyObject(reply);
525
- free(lua);
526
- return RULES_OK;
527
- }
528
-
529
- static unsigned int loadRemoveTimerCommand(ruleset *tree, binding *rulesBinding) {
530
- char *name = &tree->stringPool[tree->nameOffset];
531
- redisContext *reContext = rulesBinding->reContext;
532
- redisReply *reply;
533
- char *lua = NULL;
534
- if (asprintf(&lua,
535
- "local timer_key = \"%s!t\"\n"
536
- "local sid = ARGV[1]\n"
537
- "local timer_name = ARGV[2]\n"
538
- "local res = redis.call(\"zrange\", timer_key, 0, -1)\n"
539
- "for i = 1, #res, 1 do\n"
540
- " if string.find(res[i], \"\\\"%%$t\\\"%%s*:%%s*\\\"\" .. timer_name .. \"\\\"\") then\n"
541
- " if string.find(res[i], \"\\\"sid\\\"%%s*:%%s*\\\"\" .. sid .. \"\\\"\") then\n"
542
- " redis.call(\"zrem\", timer_key, res[i])\n"
543
- " end\n"
544
- " end\n"
545
- "end\n"
546
- "return 0\n", name) == -1) {
547
- return ERR_OUT_OF_MEMORY;
548
- }
549
-
550
- unsigned int result = redisAppendCommand(reContext, "SCRIPT LOAD %s", lua);
551
- GET_REPLY(result, "loadRemoveTimerCommand", reply);
552
-
553
- strncpy(rulesBinding->removeTimerHash, reply->str, 40);
554
- rulesBinding->removeTimerHash[40] = '\0';
555
- freeReplyObject(reply);
556
- free(lua);
557
- return RULES_OK;
558
- }
559
-
560
- static unsigned int loadUpdateActionCommand(ruleset *tree, binding *rulesBinding) {
561
- char *name = &tree->stringPool[tree->nameOffset];
562
- redisContext *reContext = rulesBinding->reContext;
563
- redisReply *reply;
564
- char *lua = NULL;
565
- if (asprintf(&lua,
566
- "local actions_key = \"%s!a\"\n"
567
- "local score = tonumber(ARGV[2])\n"
568
- "local sid = ARGV[1]\n"
569
- "if redis.call(\"zscore\", actions_key, sid) then\n"
570
- " redis.call(\"zadd\", actions_key , score, sid)\n"
571
- "end\n", name) == -1) {
572
- return ERR_OUT_OF_MEMORY;
573
- }
574
-
575
- unsigned int result = redisAppendCommand(reContext, "SCRIPT LOAD %s", lua);
576
- GET_REPLY(result, "loadUpdateActionCommand", reply);
577
-
578
- strncpy(rulesBinding->updateActionHash, reply->str, 40);
579
- rulesBinding->updateActionHash[40] = '\0';
580
- freeReplyObject(reply);
581
- free(lua);
582
- return RULES_OK;
583
- }
584
-
585
- static unsigned int loadDeleteSessionCommand(ruleset *tree, binding *rulesBinding) {
586
- char *name = &tree->stringPool[tree->nameOffset];
587
- redisContext *reContext = rulesBinding->reContext;
588
- redisReply *reply;
589
- char *lua = NULL;
590
- char *deleteSessionLua = NULL;
591
- deleteSessionLua = (char*)calloc(1, sizeof(char));
592
- if (!deleteSessionLua) {
593
- return ERR_OUT_OF_MEMORY;
594
- }
595
-
596
- for (unsigned int i = 0; i < tree->nodeOffset; ++i) {
597
- node *currentNode = &tree->nodePool[i];
598
-
599
- if (currentNode->type == NODE_ACTION) {
600
- char *actionName = &tree->stringPool[currentNode->nameOffset];
601
- char *oldDeleteSessionLua = NULL;
602
- for (unsigned int ii = 0; ii < currentNode->value.c.joinsLength; ++ii) {
603
- unsigned int currentJoinOffset = tree->nextPool[currentNode->value.c.joinsOffset + ii];
604
- join *currentJoin = &tree->joinPool[currentJoinOffset];
605
-
606
- oldDeleteSessionLua = deleteSessionLua;
607
- if (asprintf(&deleteSessionLua,
608
- "%sredis.call(\"del\", \"%s!%d!r!\" .. sid)\n"
609
- "redis.call(\"del\", \"%s!%d!r!\" .. sid .. \"!d\")\n",
610
- deleteSessionLua,
611
- actionName,
612
- ii,
613
- actionName,
614
- ii) == -1) {
615
- return ERR_OUT_OF_MEMORY;
616
- }
617
- free(oldDeleteSessionLua);
618
-
619
- for (unsigned int iii = 0; iii < currentJoin->expressionsLength; ++iii) {
620
- unsigned int expressionOffset = tree->nextPool[currentJoin->expressionsOffset + iii];
621
- expression *expr = &tree->expressionPool[expressionOffset];
622
- char *currentKey = &tree->stringPool[expr->nameOffset];
623
-
624
- oldDeleteSessionLua = deleteSessionLua;
625
- if (asprintf(&deleteSessionLua,
626
- "%sdelete_message_keys(\"%s!f!\" .. sid)\n"
627
- "delete_message_keys(\"%s!e!\" .. sid)\n"
628
- "delete_closure_keys(\"%s!c!\" .. sid)\n"
629
- "delete_closure_keys(\"%s!i!\" .. sid)\n",
630
- deleteSessionLua,
631
- currentKey,
632
- currentKey,
633
- currentKey,
634
- currentKey) == -1) {
635
- return ERR_OUT_OF_MEMORY;
636
- }
637
- free(oldDeleteSessionLua);
638
- }
639
- }
640
- }
641
- }
642
-
643
-
644
- if (asprintf(&lua,
645
- "local sid = ARGV[1]\n"
646
- "local delete_message_keys = function(events_key)\n"
647
- " local all_keys = redis.call(\"keys\", events_key .. \"!m!*\")\n"
648
- " for i = 1, #all_keys, 1 do\n"
649
- " redis.call(\"del\", all_keys[i])\n"
650
- " end\n"
651
- " redis.call(\"del\", events_key)\n"
652
- "end\n"
653
- "local delete_closure_keys = function(closure_key)\n"
654
- " local all_keys = redis.call(\"keys\", closure_key .. \"!*\")\n"
655
- " for i = 1, #all_keys, 1 do\n"
656
- " redis.call(\"del\", all_keys[i])\n"
657
- " end\n"
658
- "end\n"
659
- "local partition_key = \"%s!p\"\n"
660
- "redis.call(\"hdel\", partition_key, ARGV[2])\n"
661
- "if redis.call(\"hlen\", partition_key) == 1 then\n"
662
- " redis.call(\"hdel\", partition_key, \"index\")\n"
663
- "end\n"
664
- "redis.call(\"hdel\", \"%s!c\", sid)\n"
665
- "redis.call(\"hdel\", \"%s!s\", sid)\n"
666
- "redis.call(\"hdel\", \"%s!s!v\", sid)\n"
667
- "redis.call(\"zrem\", \"%s!a\", sid)\n"
668
- "redis.call(\"del\", \"%s!a!\" .. sid)\n"
669
- "redis.call(\"del\", \"%s!e!\" .. sid)\n"
670
- "redis.call(\"del\", \"%s!f!\" .. sid)\n"
671
- "redis.call(\"del\", \"%s!v!\" .. sid)\n%s",
672
- name,
673
- name,
674
- name,
675
- name,
676
- name,
677
- name,
678
- name,
679
- name,
680
- name,
681
- deleteSessionLua) == -1) {
682
- return ERR_OUT_OF_MEMORY;
683
- }
684
-
685
- free(deleteSessionLua);
686
- unsigned int result = redisAppendCommand(reContext, "SCRIPT LOAD %s", lua);
687
- GET_REPLY(result, "loadDeleteSessionCommand", reply);
688
-
689
- strncpy(rulesBinding->deleteSessionHash, reply->str, 40);
690
- rulesBinding->deleteSessionHash[40] = '\0';
691
- freeReplyObject(reply);
692
- free(lua);
693
- return RULES_OK;
694
-
695
- }
696
- static unsigned int loadAddMessageCommand(ruleset *tree, binding *rulesBinding) {
697
- char *name = &tree->stringPool[tree->nameOffset];
698
- redisContext *reContext = rulesBinding->reContext;
699
- redisReply *reply;
700
- char *lua = NULL;
701
- char *addMessageLua = NULL;
702
- addMessageLua = (char*)calloc(1, sizeof(char));
703
- if (!addMessageLua) {
704
- return ERR_OUT_OF_MEMORY;
705
- }
706
-
707
- for (unsigned int i = 0; i < tree->nodeOffset; ++i) {
708
- node *currentNode = &tree->nodePool[i];
709
-
710
- if (currentNode->type == NODE_ACTION) {
711
- char *oldAddMessageLua = NULL;
712
- for (unsigned int ii = 0; ii < currentNode->value.c.joinsLength; ++ii) {
713
- unsigned int currentJoinOffset = tree->nextPool[currentNode->value.c.joinsOffset + ii];
714
- join *currentJoin = &tree->joinPool[currentJoinOffset];
715
-
716
- for (unsigned int iii = 0; iii < currentJoin->expressionsLength; ++iii) {
717
- unsigned int expressionOffset = tree->nextPool[currentJoin->expressionsOffset + iii];
718
- expression *expr = &tree->expressionPool[expressionOffset];
719
- char *currentKey = &tree->stringPool[expr->nameOffset];
720
- if (iii == 0) {
721
- oldAddMessageLua = addMessageLua;
722
- if (!addMessageLua) {
723
- addMessageLua = "";
724
- }
725
-
726
- if (asprintf(&addMessageLua,
727
- "%sif input_keys[\"%s\"] then\n"
728
- " primary_message_keys[\"%s\"] = function(message)\n"
729
- " return \"\"\n"
730
- " end\n"
731
- "end\n",
732
- addMessageLua,
733
- currentKey,
734
- currentKey) == -1) {
735
- return ERR_OUT_OF_MEMORY;
736
- }
737
- free(oldAddMessageLua);
738
- } else {
739
- char *test = NULL;
740
- char *primaryKeyLua = NULL;
741
- char *primaryFrameKeyLua = NULL;
742
- unsigned int result = createTest(tree, expr, &test, &primaryKeyLua, &primaryFrameKeyLua);
743
- if (result != RULES_OK) {
744
- return result;
745
- }
746
-
747
- oldAddMessageLua = addMessageLua;
748
- if (asprintf(&addMessageLua,
749
- "%sif input_keys[\"%s\"] then\n"
750
- " primary_message_keys[\"%s\"] = function(message)\n"
751
- " local result = \"\"\n%s"
752
- " return result\n"
753
- " end\n"
754
- "end\n",
755
- addMessageLua,
756
- currentKey,
757
- currentKey,
758
- primaryKeyLua) == -1) {
759
- return ERR_OUT_OF_MEMORY;
760
- }
761
- free(oldAddMessageLua);
762
- free(test);
763
- free(primaryKeyLua);
764
- free(primaryFrameKeyLua);
765
- }
766
- }
767
- }
768
- }
769
- }
770
-
771
- if (asprintf(&lua,
772
- "local sid = ARGV[1]\n"
773
- "local assert_fact = tonumber(ARGV[2])\n"
774
- // when mark visited is set to 0, it means eval will be called immedately
775
- // with the same message. In that case, the function will avid setting
776
- // the visited bit (for events), storing the message and increasing the
777
- // mid count (for the case of auto generated mid)
778
- "local mark_visited = tonumber(ARGV[3])\n"
779
- "local keys_count = tonumber(ARGV[4])\n"
780
- "local events_hashset = \"%s!e!\" .. sid\n"
781
- "local facts_hashset = \"%s!f!\" .. sid\n"
782
- "local visited_hashset = \"%s!v!\" .. sid\n"
783
- "local mid_count_hashset = \"%s!c\"\n"
784
- "local message = {}\n"
785
- "local primary_message_keys = {}\n"
786
- "local input_keys = {}\n"
787
- "local is_distinct_message = function(frame, message)\n"
788
- " for name, frame_message in pairs(frame) do\n"
789
- " if frame_message[\"id\"] == message[\"id\"] then\n"
790
- " return false\n"
791
- " end\n"
792
- " end\n"
793
- " return true\n"
794
- "end\n"
795
- "local compare_array = function(left_array, right_value, op, compare_all)\n"
796
- " if not left_array or type(left_array) ~= \"table\" then\n"
797
- " return false\n"
798
- " end\n"
799
- " for i = 1, #left_array, 1 do\n"
800
- " local comparison = false\n"
801
- " if op == 0 then\n"
802
- " comparison = (left_array[i] < right_value)\n"
803
- " elseif op == 1 then\n"
804
- " comparison = (left_array[i] <= right_value)\n"
805
- " elseif op == 2 then\n"
806
- " comparison = (left_array[i] > right_value)\n"
807
- " elseif op == 3 then\n"
808
- " comparison = (left_array[i] >= right_value)\n"
809
- " elseif op == 4 then\n"
810
- " comparison = (left_array[i] == right_value)\n"
811
- " elseif op == 5 then\n"
812
- " comparison = (left_array[i] ~= right_value)\n"
813
- " end\n"
814
- " if not compare_all and comparison then\n"
815
- " return true\n"
816
- " end\n"
817
- " if compare_all and not comparison then\n"
818
- " return false\n"
819
- " end\n"
820
- " end"
821
- " if compare_all then\n"
822
- " return true\n"
823
- " end\n"
824
- " return false\n"
825
- "end\n"
826
- "local save_message = function(current_key, message, events_key, messages_key, save_hashset)\n"
827
- " if save_hashset == 1 then\n"
828
- " redis.call(\"hsetnx\", messages_key, message[\"id\"], cmsgpack.pack(message))\n"
829
- " end\n"
830
- " local primary_key = primary_message_keys[current_key](message)\n"
831
- " redis.call(\"lpush\", events_key .. \"!m!\" .. primary_key, message[\"id\"])\n"
832
- "end\n"
833
- "for index = 5 + keys_count, #ARGV, 3 do\n"
834
- " if ARGV[index + 2] == \"1\" then\n"
835
- " message[ARGV[index]] = ARGV[index + 1]\n"
836
- " elseif ARGV[index + 2] == \"2\" or ARGV[index + 2] == \"3\" then\n"
837
- " message[ARGV[index]] = tonumber(ARGV[index + 1])\n"
838
- " elseif ARGV[index + 2] == \"4\" then\n"
839
- " if ARGV[index + 1] == \"true\" then\n"
840
- " message[ARGV[index]] = true\n"
841
- " else\n"
842
- " message[ARGV[index]] = false\n"
843
- " end\n"
844
- " elseif ARGV[index + 2] == \"5\" then\n"
845
- " message[ARGV[index]] = cjson.decode(ARGV[index + 1])\n"
846
- " elseif ARGV[index + 2] == \"7\" then\n"
847
- " message[ARGV[index]] = \"$null\"\n"
848
- " end\n"
849
- "end\n"
850
- "local mid = message[\"id\"]\n"
851
- "if mid == \"\" then\n"
852
- " if mark_visited == 0 then\n"
853
- " mid = \"$m-\" .. redis.call(\"hget\", mid_count_hashset, sid) + 1\n"
854
- " else\n"
855
- " mid = \"$m-\" .. redis.call(\"hincrby\", mid_count_hashset, sid, 1)\n"
856
- " end\n"
857
- " message[\"id\"] = mid\n"
858
- "else\n"
859
- " if assert_fact == 1 then\n"
860
- " if redis.call(\"hexists\", facts_hashset, mid) == 1 then\n"
861
- " return %d\n"
862
- " end\n"
863
- " else\n"
864
- " if mark_visited == 1 then\n"
865
- " if redis.call(\"hsetnx\", visited_hashset, mid, 1) == 0 then\n"
866
- " return %d\n"
867
- " end\n"
868
- " elseif redis.call(\"hexists\", visited_hashset, mid) == 1 then \n"
869
- " return %d\n"
870
- " end\n"
871
- " end\n"
872
- "end\n"
873
- "for index = 5, 4 + keys_count, 1 do\n"
874
- " input_keys[ARGV[index]] = true\n"
875
- "end\n"
876
- "%sif assert_fact == 1 then\n"
877
- " message[\"$f\"] = 1\n"
878
- " for index = 5, 4 + keys_count, 1 do\n"
879
- " local key = ARGV[index]\n"
880
- " save_message(key, message, key .. \"!f!\" .. sid, facts_hashset, mark_visited)\n"
881
- " end\n"
882
- "else\n"
883
- " for index = 5, 4 + keys_count, 1 do\n"
884
- " local key = ARGV[index]\n"
885
- " save_message(key, message, key .. \"!e!\" .. sid, events_hashset, mark_visited)\n"
886
- " end\n"
887
- "end\n",
888
- name,
889
- name,
890
- name,
891
- name,
892
- ERR_EVENT_OBSERVED,
893
- ERR_EVENT_OBSERVED,
894
- ERR_EVENT_OBSERVED,
895
- addMessageLua) == -1) {
896
- return ERR_OUT_OF_MEMORY;
897
- }
898
-
899
- free(addMessageLua);
900
- unsigned int result = redisAppendCommand(reContext, "SCRIPT LOAD %s", lua);
901
- GET_REPLY(result, "loadAddMessageCommand", reply);
902
-
903
- strncpy(rulesBinding->addMessageHash, reply->str, 40);
904
- rulesBinding->addMessageHash[40] = '\0';
905
- freeReplyObject(reply);
906
- free(lua);
907
- return RULES_OK;
908
- }
909
-
910
- static unsigned int loadPeekActionCommand(ruleset *tree, binding *rulesBinding) {
911
- char *name = &tree->stringPool[tree->nameOffset];
912
- redisContext *reContext = rulesBinding->reContext;
913
- redisReply *reply;
914
- char *lua = NULL;
915
-
916
- char *peekActionLua = NULL;
917
- peekActionLua = (char*)calloc(1, sizeof(char));
918
- if (!peekActionLua) {
919
- return ERR_OUT_OF_MEMORY;
920
- }
921
-
922
- for (unsigned int i = 0; i < tree->nodeOffset; ++i) {
923
- char *oldPeekActionLua;
924
- node *currentNode = &tree->nodePool[i];
925
-
926
- if (currentNode->type == NODE_ACTION) {
927
- char *unpackFrameLua = NULL;
928
- char *oldUnpackFrameLua = NULL;
929
- char *actionName = &tree->stringPool[currentNode->nameOffset];
930
- for (unsigned int ii = 0; ii < currentNode->value.c.joinsLength; ++ii) {
931
- unsigned int currentJoinOffset = tree->nextPool[currentNode->value.c.joinsOffset + ii];
932
- join *currentJoin = &tree->joinPool[currentJoinOffset];
933
-
934
- oldPeekActionLua = peekActionLua;
935
- if (asprintf(&peekActionLua,
936
- "%sif input_keys[\"%s!%d!r!\"] then\n"
937
- "local context = {}\n"
938
- "context_directory[\"%s!%d!r!\"] = context\n"
939
- "reviewers = {}\n"
940
- "context[\"reviewers\"] = reviewers\n"
941
- "keys = {}\n"
942
- "context[\"keys\"] = keys\n"
943
- "primary_frame_keys = {}\n"
944
- "context[\"primary_frame_keys\"] = primary_frame_keys\n",
945
- peekActionLua,
946
- actionName,
947
- ii,
948
- actionName,
949
- ii) == -1) {
950
- return ERR_OUT_OF_MEMORY;
951
- }
952
- free(oldPeekActionLua);
953
-
954
- for (unsigned int iii = 0; iii < currentJoin->expressionsLength; ++iii) {
955
- unsigned int expressionOffset = tree->nextPool[currentJoin->expressionsOffset + iii];
956
- expression *expr = &tree->expressionPool[expressionOffset];
957
- char *currentKey = &tree->stringPool[expr->nameOffset];
958
- char *currentAlias = &tree->stringPool[expr->aliasOffset];
959
-
960
-
961
- if (iii == 0) {
962
- if (expr->not) {
963
- if (asprintf(&unpackFrameLua,
964
- " result[\"%s\"] = \"$n\"\n",
965
- currentAlias) == -1) {
966
- return ERR_OUT_OF_MEMORY;
967
- }
968
-
969
- oldPeekActionLua = peekActionLua;
970
- if (!peekActionLua) {
971
- peekActionLua = "";
972
- }
973
-
974
- if (asprintf(&peekActionLua,
975
- "%skeys[1] = \"%s\"\n"
976
- "reviewers[1] = function(message, frame, index)\n"
977
- " if not message then\n"
978
- " return true\n"
979
- " end\n"
980
- " return false\n"
981
- "end\n"
982
- "primary_frame_keys[1] = function(frame)\n"
983
- " return \"\"\n"
984
- "end\n",
985
- peekActionLua,
986
- currentKey) == -1) {
987
- return ERR_OUT_OF_MEMORY;
988
- }
989
- free(oldPeekActionLua);
990
- } else {
991
- if (asprintf(&unpackFrameLua,
992
- " message = fetch_message(frame[1])\n"
993
- " if not message then\n"
994
- " return nil\n"
995
- " end\n"
996
- " result[\"%s\"] = message\n",
997
- currentAlias) == -1) {
998
- return ERR_OUT_OF_MEMORY;
999
- }
1000
-
1001
- }
1002
- } else {
1003
- if (expr->not) {
1004
- char *test = NULL;
1005
- char *primaryKeyLua = NULL;
1006
- char *primaryFrameKeyLua = NULL;
1007
- unsigned int result = createTest(tree, expr, &test, &primaryKeyLua, &primaryFrameKeyLua);
1008
- if (result != RULES_OK) {
1009
- return result;
1010
- }
1011
-
1012
- oldUnpackFrameLua = unpackFrameLua;
1013
- if (asprintf(&unpackFrameLua,
1014
- "%s result[\"%s\"] = \"$n\"\n",
1015
- unpackFrameLua,
1016
- currentAlias) == -1) {
1017
- return ERR_OUT_OF_MEMORY;
1018
- }
1019
- free(oldUnpackFrameLua);
1020
-
1021
- oldPeekActionLua = peekActionLua;
1022
- if (asprintf(&peekActionLua,
1023
- "%skeys[%d] = \"%s\"\n"
1024
- "reviewers[%d] = function(message, frame, index)\n"
1025
- " if not message or not (%s) then\n"
1026
- " return true\n"
1027
- " end\n"
1028
- " return false\n"
1029
- "end\n"
1030
- "primary_frame_keys[%d] = function(frame)\n"
1031
- " local result = \"\"\n%s"
1032
- " return result\n"
1033
- "end\n",
1034
- peekActionLua,
1035
- iii + 1,
1036
- currentKey,
1037
- iii + 1,
1038
- test,
1039
- iii + 1,
1040
- primaryFrameKeyLua) == -1) {
1041
- return ERR_OUT_OF_MEMORY;
1042
- }
1043
- free(oldPeekActionLua);
1044
- free(test);
1045
- free(primaryKeyLua);
1046
- free(primaryFrameKeyLua);
1047
- } else {
1048
- oldUnpackFrameLua = unpackFrameLua;
1049
- if (asprintf(&unpackFrameLua,
1050
- "%s message = fetch_message(frame[%d])\n"
1051
- " if not message then\n"
1052
- " return nil\n"
1053
- " end\n"
1054
- " result[\"%s\"] = message\n",
1055
- unpackFrameLua,
1056
- iii + 1,
1057
- currentAlias) == -1) {
1058
- return ERR_OUT_OF_MEMORY;
1059
- }
1060
- free(oldUnpackFrameLua);
1061
- }
1062
- }
1063
- }
1064
-
1065
- oldPeekActionLua = peekActionLua;
1066
- if (asprintf(&peekActionLua,
1067
- "%scontext[\"frame_restore\"] = function(frame, result)\n"
1068
- " local message\n%s"
1069
- " return true\n"
1070
- "end\n"
1071
- "return context\n"
1072
- "end\n",
1073
- peekActionLua,
1074
- unpackFrameLua) == -1) {
1075
- return ERR_OUT_OF_MEMORY;
1076
- }
1077
- free(oldPeekActionLua);
1078
-
1079
- }
1080
-
1081
- free(unpackFrameLua);
1082
- }
1083
- }
1084
-
1085
- if (asprintf(&lua,
1086
- "local facts_key = \"%s!f!\"\n"
1087
- "local events_key = \"%s!e!\"\n"
1088
- "local visited_key = \"%s!v!\"\n"
1089
- "local action_key = \"%s!a\"\n"
1090
- "local state_key = \"%s!s\"\n"
1091
- "local timers_key = \"%s!t\"\n"
1092
- "local context_directory = {}\n"
1093
- "local keys\n"
1094
- "local reviewers\n"
1095
- "local primary_frame_keys\n"
1096
- "local facts_hashset\n"
1097
- "local events_hashset\n"
1098
- "local events_message_cache = {}\n"
1099
- "local facts_message_cache = {}\n"
1100
- "local facts_mids_cache = {}\n"
1101
- "local events_mids_cache = {}\n"
1102
- "local get_context\n"
1103
- "local is_distinct_message = function(frame, message)\n"
1104
- " for name, frame_message in pairs(frame) do\n"
1105
- " if frame_message[\"id\"] == message[\"id\"] then\n"
1106
- " return false\n"
1107
- " end\n"
1108
- " end\n"
1109
- " return true\n"
1110
- "end\n"
1111
- "local compare_array = function(left_array, right_value, op, compare_all)\n"
1112
- " if not left_array or type(left_array) ~= \"table\" then\n"
1113
- " return false\n"
1114
- " end\n"
1115
- " for i = 1, #left_array, 1 do\n"
1116
- " local comparison = false\n"
1117
- " if op == 0 then\n"
1118
- " comparison = (left_array[i] < right_value)\n"
1119
- " elseif op == 1 then\n"
1120
- " comparison = (left_array[i] <= right_value)\n"
1121
- " elseif op == 2 then\n"
1122
- " comparison = (left_array[i] > right_value)\n"
1123
- " elseif op == 3 then\n"
1124
- " comparison = (left_array[i] >= right_value)\n"
1125
- " elseif op == 4 then\n"
1126
- " comparison = (left_array[i] == right_value)\n"
1127
- " elseif op == 5 then\n"
1128
- " comparison = (left_array[i] ~= right_value)\n"
1129
- " end\n"
1130
- " if not compare_all and comparison then\n"
1131
- " return true\n"
1132
- " end\n"
1133
- " if compare_all and not comparison then\n"
1134
- " return false\n"
1135
- " end\n"
1136
- " end"
1137
- " if compare_all then\n"
1138
- " return true\n"
1139
- " end\n"
1140
- " return false\n"
1141
- "end\n"
1142
- "local get_mids = function(index, frame, events_key, messages_key, mids_cache, message_cache)\n"
1143
- " local event_mids = mids_cache[events_key]\n"
1144
- " local primary_key = primary_frame_keys[index](frame)\n"
1145
- " local new_mids = nil\n"
1146
- " if not event_mids then\n"
1147
- " event_mids = {}\n"
1148
- " mids_cache[events_key] = event_mids\n"
1149
- " else\n"
1150
- " new_mids = event_mids[primary_key]\n"
1151
- " end\n"
1152
- " if not new_mids then\n"
1153
- " new_mids = redis.call(\"lrange\", events_key .. \"!m!\" .. primary_key, 0, -1)\n"
1154
- " event_mids[primary_key] = new_mids\n"
1155
- " end\n"
1156
- " return new_mids\n"
1157
- "end\n"
1158
- "local get_message = function(new_mid, messages_key, message_cache)\n"
1159
- " local message = false\n"
1160
- " new_mid = tostring(new_mid)\n"
1161
- " if message_cache[new_mid] ~= nil then\n"
1162
- " message = message_cache[new_mid]\n"
1163
- " else\n"
1164
- " local packed_message = redis.call(\"hget\", messages_key, new_mid)\n"
1165
- " if packed_message then\n"
1166
- " message = cmsgpack.unpack(packed_message)\n"
1167
- " end\n"
1168
- " message_cache[new_mid] = message\n"
1169
- " end\n"
1170
- " return message\n"
1171
- "end\n"
1172
- "local fetch_message = function(new_mid)\n"
1173
- " if type(new_mid) == \"table\" then\n"
1174
- " return new_mid\n"
1175
- " end\n"
1176
- " return get_message(new_mid, facts_hashset, facts_message_cache)\n"
1177
- "end\n"
1178
- "local validate_frame_for_key = function(frame, index, events_list_key, messages_key, mids_cache, message_cache, sid)\n"
1179
- " local new_mids = get_mids(index, frame, events_list_key, messages_key, mids_cache, message_cache)\n"
1180
- " for i = 1, #new_mids, 1 do\n"
1181
- " local message = get_message(new_mids[i], messages_key, message_cache)\n"
1182
- " if message and not reviewers[index](message, frame, index) then\n"
1183
- " return false\n"
1184
- " end\n"
1185
- " end\n"
1186
- " return true\n"
1187
- "end\n"
1188
- "local validate_frame = function(frame, index, sid)\n"
1189
- " local first_result = validate_frame_for_key(frame, index, keys[index] .. \"!e!\" .. sid, events_hashset, events_mids_cache, events_message_cache, sid)\n"
1190
- " local second_result = validate_frame_for_key(frame, index, keys[index] ..\"!f!\" .. sid, facts_hashset, facts_mids_cache, facts_message_cache, sid)\n"
1191
- " return first_result and second_result\n"
1192
- "end\n"
1193
- "local review_frame = function(frame, rule_action_key, sid, max_score)\n"
1194
- " local indexes = {}\n"
1195
- " local action_id = string.sub(rule_action_key, 1, (string.len(sid) + 1) * -1)\n"
1196
- " local context = get_context(action_id)\n"
1197
- " local full_frame = {}\n"
1198
- " local cancel = false\n"
1199
- " events_hashset = events_key .. sid\n"
1200
- " facts_hashset = facts_key .. sid\n"
1201
- " keys = context[\"keys\"]\n"
1202
- " reviewers = context[\"reviewers\"]\n"
1203
- " primary_frame_keys = context[\"primary_frame_keys\"]\n"
1204
- " if not context[\"frame_restore\"](frame, full_frame) then\n"
1205
- " cancel = true\n"
1206
- " else\n"
1207
- " for i = 1, #frame, 1 do\n"
1208
- " if frame[i] == \"$n\" then\n"
1209
- " if not validate_frame(full_frame, i, sid) then\n"
1210
- " cancel = true\n"
1211
- " break\n"
1212
- " end\n"
1213
- " end\n"
1214
- " end\n"
1215
- " end\n"
1216
- " if cancel then\n"
1217
- " for i = 1, #frame, 1 do\n"
1218
- " if type(frame[i]) == \"table\" then\n"
1219
- " redis.call(\"hdel\", visited_key .. sid, frame[i][\"id\"])\n"
1220
- " redis.call(\"zadd\", timers_key, max_score, \"p:\" .. cjson.encode(frame[i]))\n"
1221
- " end\n"
1222
- " end\n"
1223
- " full_frame = nil\n"
1224
- " end\n"
1225
- " return full_frame\n"
1226
- "end\n"
1227
- "local load_frame_from_rule = function(rule_action_key, raw_count, sid, max_score)\n"
1228
- " local frames = {}\n"
1229
- " local packed_frames = {}\n"
1230
- " local count = tonumber(string.sub(raw_count, 3))\n"
1231
- " local window = false\n"
1232
- " if string.find(raw_count, \"$w\") == 1 then\n"
1233
- " window = true\n"
1234
- " end\n"
1235
- " for i = 0, count - 1, 1 do\n"
1236
- " local packed_frame = redis.call(\"rpop\", rule_action_key)\n"
1237
- " if not packed_frame then\n"
1238
- " break\n"
1239
- " else\n"
1240
- " local frame = review_frame(cmsgpack.unpack(packed_frame), rule_action_key, sid, max_score)\n"
1241
- " if frame then\n"
1242
- " table.insert(frames, frame)\n"
1243
- " table.insert(packed_frames, packed_frame)\n"
1244
- " end\n"
1245
- " end\n"
1246
- " end\n"
1247
- " for i = #packed_frames, 1, -1 do\n"
1248
- " redis.call(\"rpush\", rule_action_key, packed_frames[i])\n"
1249
- " end\n"
1250
- " if #packed_frames == 0 or (window and (#packed_frames ~= count)) then\n"
1251
- " return nil, nil\n"
1252
- " end\n"
1253
- " local last_name = string.find(rule_action_key, \"!\") - 1\n"
1254
- " if window and count == 1 then\n"
1255
- " return string.sub(rule_action_key, 1, last_name), frames[1]\n"
1256
- " else\n"
1257
- " return string.sub(rule_action_key, 1, last_name), frames\n"
1258
- " end\n"
1259
- "end\n"
1260
- "local load_frame_from_sid = function(sid, max_score)\n"
1261
- " local action_list = action_key .. \"!\" .. sid\n"
1262
- " local rule_action_key = redis.call(\"lpop\", action_list)\n"
1263
- " if not rule_action_key then\n"
1264
- " return nil, nil\n"
1265
- " end\n"
1266
- " local count = redis.call(\"lpop\", action_list)\n"
1267
- " local name, frame = load_frame_from_rule(rule_action_key, count, sid, max_score)\n"
1268
- " while not frame do\n"
1269
- " rule_action_key = redis.call(\"lpop\", action_list)\n"
1270
- " if not rule_action_key then\n"
1271
- " return nil, nil\n"
1272
- " end\n"
1273
- " count = redis.call(\"lpop\", action_list)\n"
1274
- " name, frame = load_frame_from_rule(rule_action_key, count, sid, max_score)\n"
1275
- " end\n"
1276
- " redis.call(\"lpush\", action_list, count)\n"
1277
- " redis.call(\"lpush\", action_list, rule_action_key)\n"
1278
- " return name, frame\n"
1279
- "end\n"
1280
- "local load_frame = function(max_score)\n"
1281
- " local current_action = redis.call(\"zrange\", action_key, 0, 0, \"withscores\")\n"
1282
- " if (#current_action == 0) or (tonumber(current_action[2]) > (max_score + 5)) then\n"
1283
- " return nil, nil, nil\n"
1284
- " end\n"
1285
- " local sid = current_action[1]\n"
1286
- " local name, frame = load_frame_from_sid(sid, max_score)\n"
1287
- " while not frame do\n"
1288
- " redis.call(\"zremrangebyrank\", action_key, 0, 0)\n"
1289
- " current_action = redis.call(\"zrange\", action_key, 0, 0, \"withscores\")\n"
1290
- " if #current_action == 0 or (tonumber(current_action[2]) > (max_score + 5)) then\n"
1291
- " return nil, nil, nil\n"
1292
- " end\n"
1293
- " sid = current_action[1]\n"
1294
- " name, frame = load_frame_from_sid(sid, max_score)\n"
1295
- " end\n"
1296
- " return sid, name, frame\n"
1297
- "end\n"
1298
- "local fixup_frame = function(frame)\n"
1299
- " local new_frame = {}\n"
1300
- " for message_name, message in pairs(frame) do\n"
1301
- " if message_name == 1 then\n"
1302
- " return frame\n"
1303
- " end\n"
1304
- " local start\n"
1305
- " local name\n"
1306
- " local next\n"
1307
- " local new_message = {}\n"
1308
- " if message == \"$n\" then\n"
1309
- " new_message = message\n"
1310
- " else\n"
1311
- " for key, value in pairs(message) do\n"
1312
- " local sub_message = new_message\n"
1313
- " start = 1\n"
1314
- " name = key\n"
1315
- " next = nil\n"
1316
- " repeat\n"
1317
- " next = string.find(key, \"%%.\", start)\n"
1318
- " if next then\n"
1319
- " name = string.sub(key, start, next - 1)\n"
1320
- " if sub_message[name] then\n"
1321
- " sub_message = sub_message[name]\n"
1322
- " else\n"
1323
- " local new_sub_message = {}\n"
1324
- " sub_message[name] = new_sub_message\n"
1325
- " sub_message = new_sub_message\n"
1326
- " end\n"
1327
- " start = next + 1\n"
1328
- " else\n"
1329
- " name = string.sub(key, start)\n"
1330
- " end\n"
1331
- " until not next\n"
1332
- " if value == \"$null\" then\n"
1333
- " sub_message[name] = cjson.null\n"
1334
- " elseif name ~= \"id\" or type(value) ~= \"string\" or string.sub(value, 1, 1) ~= \"$\" then\n"
1335
- " if name ~= \"$f\" then \n"
1336
- " sub_message[name] = value\n"
1337
- " end\n"
1338
- " end\n"
1339
- " end\n"
1340
- " end\n"
1341
- " local sub_frame = new_frame\n"
1342
- " name = message_name\n"
1343
- " next = nil\n"
1344
- " start = 1\n"
1345
- " repeat\n"
1346
- " next = string.find(message_name, \"%%.\", start)\n"
1347
- " if next then\n"
1348
- " name = string.sub(message_name, start, next - 1)\n"
1349
- " if sub_frame[name] then\n"
1350
- " sub_frame = sub_frame[name]\n"
1351
- " else\n"
1352
- " local new_sub_frame = {}\n"
1353
- " sub_frame[name] = new_sub_frame\n"
1354
- " sub_frame = new_sub_frame\n"
1355
- " end\n"
1356
- " start = next + 1\n"
1357
- " else\n"
1358
- " name = string.sub(message_name, start)\n"
1359
- " end\n"
1360
- " until not next\n"
1361
- " sub_frame[name] = new_message\n"
1362
- " end\n"
1363
- " return new_frame\n"
1364
- "end\n"
1365
- "get_context = function(action_key)\n"
1366
- " if context_directory[action_key] then\n"
1367
- " return context_directory[action_key]\n"
1368
- " end\n"
1369
- " local input_keys = {[action_key] = true}\n%s"
1370
- "end\n"
1371
- "local new_sid, action_name, frame\n"
1372
- "if #ARGV == 3 then\n"
1373
- " new_sid = ARGV[3]\n"
1374
- " action_name, frame = load_frame_from_sid(new_sid, tonumber(ARGV[2]))\n"
1375
- "else\n"
1376
- " new_sid, action_name, frame = load_frame(tonumber(ARGV[2]))\n"
1377
- "end\n"
1378
- "if frame then\n"
1379
- " redis.call(\"zadd\", action_key, tonumber(ARGV[1]), new_sid)\n"
1380
- " if #ARGV == 2 then\n"
1381
- " local state = redis.call(\"hget\", state_key, new_sid)\n"
1382
- " return {new_sid, state, cjson.encode({[action_name] = fixup_frame(frame)})}\n"
1383
- " else\n"
1384
- " return {new_sid, cjson.encode({[action_name] = fixup_frame(frame)})}\n"
1385
- " end\n"
1386
- "end\n",
1387
- name,
1388
- name,
1389
- name,
1390
- name,
1391
- name,
1392
- name,
1393
- peekActionLua) == -1) {
1394
- return ERR_OUT_OF_MEMORY;
1395
- }
1396
- free(peekActionLua);
1397
- unsigned int result = redisAppendCommand(reContext, "SCRIPT LOAD %s", lua);
1398
- GET_REPLY(result, "loadPeekActionCommand", reply);
1399
-
1400
- strncpy(rulesBinding->peekActionHash, reply->str, 40);
1401
- rulesBinding->peekActionHash[40] = '\0';
1402
- freeReplyObject(reply);
1403
- free(lua);
1404
- return RULES_OK;
1405
- }
1406
-
1407
- static void sortActions(ruleset *tree, node **sortedActions, unsigned int *actionCount) {
1408
- *actionCount = 0;
1409
- for (unsigned int i = 0; i < tree->nodeOffset; ++i) {
1410
- node *currentNode = &tree->nodePool[i];
1411
- if (currentNode->type == NODE_ACTION) {
1412
- unsigned int index = *actionCount;
1413
- while (index > 0 && currentNode->value.c.priority < sortedActions[index - 1]->value.c.priority) {
1414
- sortedActions[index] = sortedActions[index - 1];
1415
- --index;
1416
- }
1417
-
1418
- sortedActions[index] = currentNode;
1419
- ++*actionCount;
1420
- }
1421
- }
1422
- }
1423
-
1424
- static unsigned int loadEvalMessageCommand(ruleset *tree, binding *rulesBinding) {
1425
- char *name = &tree->stringPool[tree->nameOffset];
1426
- int nameLength = strlen(name);
1427
- redisContext *reContext = rulesBinding->reContext;
1428
- redisReply *reply;
1429
- char *lua = NULL;
1430
- char *oldLua;
1431
- unsigned int actionCount = 0;
1432
-
1433
- #ifdef _WIN32
1434
- char *actionKey = (char *)_alloca(sizeof(char) * (nameLength + 3));
1435
- sprintf_s(actionKey, sizeof(char) * (nameLength + 3), "%s!a", name);
1436
- node **sortedActions = (node **)_alloca(sizeof(node *) * tree->nodeOffset);
1437
- #else
1438
- char actionKey[nameLength + 3];
1439
- snprintf(actionKey, sizeof(char) * (nameLength + 3), "%s!a", name);
1440
- node *sortedActions[tree->nodeOffset];
1441
- #endif
1442
-
1443
- lua = (char*)calloc(1, sizeof(char));
1444
- if (!lua) {
1445
- return ERR_OUT_OF_MEMORY;
1446
- }
1447
-
1448
- sortActions(tree, sortedActions, &actionCount);
1449
- for (unsigned int i = 0; i < actionCount; ++i) {
1450
- node *currentNode = sortedActions[i];
1451
- char *packFrameLua = NULL;
1452
- char *unpackFrameLua = NULL;
1453
- char *oldPackFrameLua = NULL;
1454
- char *oldUnpackFrameLua = NULL;
1455
- char *actionName = &tree->stringPool[currentNode->nameOffset];
1456
- char *actionLastName = strchr(actionName, '!');
1457
- #ifdef _WIN32
1458
- char *actionAlias = (char *)_alloca(sizeof(char)*(actionLastName - actionName + 1));
1459
- #else
1460
- char actionAlias[actionLastName - actionName + 1];
1461
- #endif
1462
-
1463
- strncpy(actionAlias, actionName, actionLastName - actionName);
1464
- actionAlias[actionLastName - actionName] = '\0';
1465
-
1466
- for (unsigned int ii = 0; ii < currentNode->value.c.joinsLength; ++ii) {
1467
- unsigned int currentJoinOffset = tree->nextPool[currentNode->value.c.joinsOffset + ii];
1468
- join *currentJoin = &tree->joinPool[currentJoinOffset];
1469
- for (unsigned int iii = 0; iii < currentJoin->expressionsLength; ++iii) {
1470
- unsigned int expressionOffset = tree->nextPool[currentJoin->expressionsOffset + iii];
1471
- expression *expr = &tree->expressionPool[expressionOffset];
1472
- char *currentKey = &tree->stringPool[expr->nameOffset];
1473
- char *currentAlias = &tree->stringPool[expr->aliasOffset];
1474
- unsigned int nextExpressionOffset = 0;
1475
- if (iii == (currentJoin->expressionsLength - 1)) {
1476
- nextExpressionOffset = tree->nextPool[currentJoin->expressionsOffset];
1477
- } else {
1478
- nextExpressionOffset = tree->nextPool[currentJoin->expressionsOffset + iii + 1];
1479
- }
1480
-
1481
- expression *nextExpr = &tree->expressionPool[nextExpressionOffset];
1482
- if (iii == 0) {
1483
- if (expr->not) {
1484
- if (asprintf(&packFrameLua,
1485
- " result[1] = \"$n\"\n") == -1) {
1486
- return ERR_OUT_OF_MEMORY;
1487
- }
1488
-
1489
- if (asprintf(&unpackFrameLua,
1490
- " result[\"%s\"] = \"$n\"\n",
1491
- currentAlias) == -1) {
1492
- return ERR_OUT_OF_MEMORY;
1493
- }
1494
-
1495
- oldLua = lua;
1496
- if (asprintf(&lua,
1497
- "%sfunction_tree[\"%s\"] = function(key, context)\n"
1498
- " if not context then\n"
1499
- " context = create_context()\n"
1500
- " context[\"results_key\"] = \"%s!%d!r!\" .. sid\n"
1501
- " context[\"expressions_count\"] = %d\n"
1502
- " end\n"
1503
- " context[\"keys\"][1] = \"%s\"\n"
1504
- " context[\"inverse_directory\"][1] = true\n"
1505
- " context[\"directory\"][\"%s\"] = 1\n"
1506
- " context[\"reviewers\"][1] = function(message, frame, index)\n"
1507
- " if not message then\n"
1508
- " frame[\"%s\"] = \"$n\"\n"
1509
- " return true\n"
1510
- " end\n"
1511
- " return false\n"
1512
- " end\n"
1513
- " context[\"frame_packers\"][1] = function(frame, full_encode)\n"
1514
- " local result = {}\n%s"
1515
- " return cmsgpack.pack(result)\n"
1516
- " end\n"
1517
- " context[\"frame_unpackers\"][1] = function(packed_frame)\n"
1518
- " local frame = cmsgpack.unpack(packed_frame)\n"
1519
- " local result = {}\n%s"
1520
- " return result\n"
1521
- " end\n"
1522
- " context[\"primary_message_keys\"][1] = function(message)\n"
1523
- " return \"\"\n"
1524
- " end\n"
1525
- " context[\"primary_frame_keys\"][1] = function(frame)\n"
1526
- " return \"\"\n"
1527
- " end\n",
1528
- lua,
1529
- &tree->stringPool[nextExpr->nameOffset],
1530
- actionName,
1531
- ii,
1532
- currentJoin->expressionsLength,
1533
- currentKey,
1534
- currentKey,
1535
- currentAlias,
1536
- packFrameLua,
1537
- unpackFrameLua) == -1) {
1538
- return ERR_OUT_OF_MEMORY;
1539
- }
1540
- free(oldLua);
1541
- // not (expr->not)
1542
- } else {
1543
-
1544
- if (asprintf(&packFrameLua,
1545
- " message = frame[\"%s\"]\n"
1546
- " if full_encode and not message[\"$f\"] then\n"
1547
- " result[1] = message\n"
1548
- " else\n"
1549
- " result[1] = message[\"id\"]\n"
1550
- " end\n",
1551
- currentAlias) == -1) {
1552
- return ERR_OUT_OF_MEMORY;
1553
- }
1554
-
1555
- if (asprintf(&unpackFrameLua,
1556
- " message = fetch_message(frame[1])\n"
1557
- " if not message then\n"
1558
- " return nil\n"
1559
- " end\n"
1560
- " result[\"%s\"] = message\n",
1561
- currentAlias) == -1) {
1562
- return ERR_OUT_OF_MEMORY;
1563
- }
1564
-
1565
- oldLua = lua;
1566
- if (asprintf(&lua,
1567
- "%sfunction_tree[\"%s\"] = function(key, context)\n"
1568
- " if not context then\n"
1569
- " context = create_context()\n"
1570
- " context[\"results_key\"] = \"%s!%d!r!\" .. sid\n"
1571
- " context[\"expressions_count\"] = %d\n"
1572
- " end\n"
1573
- " context[\"keys\"][1] = \"%s\"\n"
1574
- " context[\"inverse_directory\"][1] = true\n"
1575
- " context[\"directory\"][\"%s\"] = 1\n"
1576
- " context[\"reviewers\"][1] = function(message, frame, index)\n"
1577
- " if message then\n"
1578
- " frame[\"%s\"] = message\n"
1579
- " return true\n"
1580
- " end\n"
1581
- " return false\n"
1582
- " end\n"
1583
- " context[\"frame_packers\"][1] = function(frame, full_encode)\n"
1584
- " local result = {}\n"
1585
- " local message\n%s"
1586
- " return cmsgpack.pack(result)\n"
1587
- " end\n"
1588
- " context[\"frame_unpackers\"][1] = function(packed_frame)\n"
1589
- " local frame = cmsgpack.unpack(packed_frame)\n"
1590
- " local result = {}\n"
1591
- " local message\n%s"
1592
- " return result\n"
1593
- " end\n"
1594
- " context[\"primary_message_keys\"][1] = function(message)\n"
1595
- " return \"\"\n"
1596
- " end\n"
1597
- " context[\"primary_frame_keys\"][1] = function(frame)\n"
1598
- " return \"\"\n"
1599
- " end\n",
1600
- lua,
1601
- &tree->stringPool[nextExpr->nameOffset],
1602
- actionName,
1603
- ii,
1604
- currentJoin->expressionsLength,
1605
- currentKey,
1606
- currentKey,
1607
- currentAlias,
1608
- packFrameLua,
1609
- unpackFrameLua) == -1) {
1610
- return ERR_OUT_OF_MEMORY;
1611
- }
1612
- free(oldLua);
1613
- }
1614
- // not (iii == 0)
1615
- } else {
1616
- if (iii < (currentJoin->expressionsLength - 1)) {
1617
- oldLua = lua;
1618
- if (asprintf(&lua,
1619
- "%s function_tree[\"%s\"](key, context)\n"
1620
- "end\n"
1621
- "function_tree[\"%s\"] = function(key, context)\n",
1622
- lua,
1623
- &tree->stringPool[nextExpr->nameOffset],
1624
- &tree->stringPool[nextExpr->nameOffset]) == -1) {
1625
- return ERR_OUT_OF_MEMORY;
1626
- }
1627
- free(oldLua);
1628
- }
1629
-
1630
- char *test = NULL;
1631
- char *primaryKeyLua = NULL;
1632
- char *primaryFrameKeyLua = NULL;
1633
-
1634
- unsigned int result = createTest(tree, expr, &test, &primaryKeyLua, &primaryFrameKeyLua);
1635
- if (result != RULES_OK) {
1636
- return result;
1637
- }
1638
-
1639
- if (expr->not) {
1640
- oldPackFrameLua = packFrameLua;
1641
- if (asprintf(&packFrameLua,
1642
- "%s result[%d] = \"$n\"\n",
1643
- packFrameLua,
1644
- iii + 1) == -1) {
1645
- return ERR_OUT_OF_MEMORY;
1646
- }
1647
- free(oldPackFrameLua);
1648
-
1649
- oldUnpackFrameLua = unpackFrameLua;
1650
- if (asprintf(&unpackFrameLua,
1651
- "%s result[\"%s\"] = \"$n\"\n",
1652
- unpackFrameLua,
1653
- currentAlias) == -1) {
1654
- return ERR_OUT_OF_MEMORY;
1655
- }
1656
- free(oldUnpackFrameLua);
1657
-
1658
- oldLua = lua;
1659
- if (asprintf(&lua,
1660
- "%s if not context then\n"
1661
- " context = create_context()\n"
1662
- " context[\"results_key\"] = \"%s!%d!r!\" .. sid\n"
1663
- " context[\"expressions_count\"] = %d\n"
1664
- " end\n"
1665
- " context[\"keys\"][%d] = \"%s\"\n"
1666
- " context[\"inverse_directory\"][%d] = true\n"
1667
- " context[\"directory\"][\"%s\"] = %d\n"
1668
- " context[\"reviewers\"][%d] = function(message, frame, index)\n"
1669
- " if not message or not (%s) then\n"
1670
- " frame[\"%s\"] = \"$n\"\n"
1671
- " return true\n"
1672
- " end\n"
1673
- " return false\n"
1674
- " end\n"
1675
- " context[\"frame_packers\"][%d] = function(frame, full_encode)\n"
1676
- " local result = {}\n"
1677
- " local message\n%s"
1678
- " return cmsgpack.pack(result)\n"
1679
- " end\n"
1680
- " context[\"frame_unpackers\"][%d] = function(packed_frame)\n"
1681
- " local frame = cmsgpack.unpack(packed_frame)\n"
1682
- " local result = {}\n"
1683
- " local message\n%s"
1684
- " return result\n"
1685
- " end\n"
1686
- " context[\"primary_message_keys\"][%d] = function(message)\n"
1687
- " local result = \"\"\n%s"
1688
- " return result\n"
1689
- " end\n"
1690
- " context[\"primary_frame_keys\"][%d] = function(frame)\n"
1691
- " local result = \"\"\n%s"
1692
- " return result\n"
1693
- " end\n",
1694
- lua,
1695
- actionName,
1696
- ii,
1697
- currentJoin->expressionsLength,
1698
- iii + 1,
1699
- currentKey,
1700
- iii + 1,
1701
- currentKey,
1702
- iii + 1,
1703
- iii + 1,
1704
- test,
1705
- currentAlias,
1706
- iii + 1,
1707
- packFrameLua,
1708
- iii + 1,
1709
- unpackFrameLua,
1710
- iii + 1,
1711
- primaryKeyLua,
1712
- iii + 1,
1713
- primaryFrameKeyLua) == -1) {
1714
- return ERR_OUT_OF_MEMORY;
1715
- }
1716
- free(oldLua);
1717
-
1718
- // not (expr->not)
1719
- } else {
1720
- oldPackFrameLua = packFrameLua;
1721
- if (asprintf(&packFrameLua,
1722
- "%s message = frame[\"%s\"]\n"
1723
- " if full_encode and not message[\"$f\"] then\n"
1724
- " result[%d] = message\n"
1725
- " else\n"
1726
- " result[%d] = message[\"id\"]\n"
1727
- " end\n",
1728
- packFrameLua,
1729
- currentAlias,
1730
- iii + 1,
1731
- iii + 1) == -1) {
1732
- return ERR_OUT_OF_MEMORY;
1733
- }
1734
- free(oldPackFrameLua);
1735
-
1736
- oldUnpackFrameLua = unpackFrameLua;
1737
- if (asprintf(&unpackFrameLua,
1738
- "%s message = fetch_message(frame[%d])\n"
1739
- " if not message then\n"
1740
- " return nil\n"
1741
- " end\n"
1742
- " result[\"%s\"] = message\n",
1743
- unpackFrameLua,
1744
- iii + 1,
1745
- currentAlias) == -1) {
1746
- return ERR_OUT_OF_MEMORY;
1747
- }
1748
- free(oldUnpackFrameLua);
1749
-
1750
- oldLua = lua;
1751
- if (asprintf(&lua,
1752
- "%s if not context then\n"
1753
- " context = create_context()\n"
1754
- " context[\"results_key\"] = \"%s!%d!r!\" .. sid\n"
1755
- " context[\"expressions_count\"] = %d\n"
1756
- " end\n"
1757
- " context[\"keys\"][%d] = \"%s\"\n"
1758
- " context[\"directory\"][\"%s\"] = %d\n"
1759
- " context[\"reviewers\"][%d] = function(message, frame, index)\n"
1760
- " if message and %s then\n"
1761
- " frame[\"%s\"] = message\n"
1762
- " return true\n"
1763
- " end\n"
1764
- " return false\n"
1765
- " end\n"
1766
- " context[\"frame_packers\"][%d] = function(frame, full_encode)\n"
1767
- " local result = {}\n"
1768
- " local message\n%s"
1769
- " return cmsgpack.pack(result)\n"
1770
- " end\n"
1771
- " context[\"frame_unpackers\"][%d] = function(packed_frame)\n"
1772
- " local frame = cmsgpack.unpack(packed_frame)\n"
1773
- " local result = {}\n"
1774
- " local message\n%s"
1775
- " return result\n"
1776
- " end\n"
1777
- " context[\"primary_message_keys\"][%d] = function(message)\n"
1778
- " local result = \"\"\n%s"
1779
- " return result\n"
1780
- " end\n"
1781
- " context[\"primary_frame_keys\"][%d] = function(frame)\n"
1782
- " local result = \"\"\n%s"
1783
- " return result\n"
1784
- " end\n",
1785
- lua,
1786
- actionName,
1787
- ii,
1788
- currentJoin->expressionsLength,
1789
- iii + 1,
1790
- currentKey,
1791
- currentKey,
1792
- iii + 1,
1793
- iii + 1,
1794
- test,
1795
- currentAlias,
1796
- iii + 1,
1797
- packFrameLua,
1798
- iii + 1,
1799
- unpackFrameLua,
1800
- iii + 1,
1801
- primaryKeyLua,
1802
- iii + 1,
1803
- primaryFrameKeyLua) == -1) {
1804
- return ERR_OUT_OF_MEMORY;
1805
- }
1806
- free(oldLua);
1807
- // done not (expr->not)
1808
- }
1809
- free(test);
1810
- free(primaryKeyLua);
1811
- free(primaryFrameKeyLua);
1812
- // done not (iii == 0)
1813
- }
1814
- }
1815
-
1816
- if (currentNode->value.c.cap > 0) {
1817
- oldLua = lua;
1818
- if (asprintf(&lua,
1819
- "%s context[\"process_key\"] = process_key_with_cap\n"
1820
- " context[\"process_key_count\"] = %d\n"
1821
- " return process_message(message, key, context)\n"
1822
- "end\n",
1823
- lua,
1824
- currentNode->value.c.cap) == -1) {
1825
- return ERR_OUT_OF_MEMORY;
1826
- }
1827
- free(oldLua);
1828
-
1829
- } else {
1830
- oldLua = lua;
1831
- if (asprintf(&lua,
1832
- "%s context[\"process_key\"] = process_key_with_window\n"
1833
- " context[\"process_key_count\"] = %d\n"
1834
- " return process_message(message, key, context)\n"
1835
- "end\n",
1836
- lua,
1837
- currentNode->value.c.count) == -1) {
1838
- return ERR_OUT_OF_MEMORY;
1839
- }
1840
- free(oldLua);
1841
- }
1842
-
1843
- unsigned int firstExpressionOffset = tree->nextPool[currentJoin->expressionsOffset];
1844
- unsigned int secondExpressionOffset = tree->nextPool[currentJoin->expressionsOffset + 1];
1845
- expression *firstExpr = &tree->expressionPool[firstExpressionOffset];
1846
- expression *secondExpr = &tree->expressionPool[secondExpressionOffset];
1847
- if (currentJoin->expressionsLength > 1) {
1848
- oldLua = lua;
1849
- if (asprintf(&lua,
1850
- "%sfunction_tree[\"%s\"] = function_tree[\"%s\"]\n",
1851
- lua,
1852
- &tree->stringPool[firstExpr->nameOffset],
1853
- &tree->stringPool[secondExpr->nameOffset]) == -1) {
1854
- return ERR_OUT_OF_MEMORY;
1855
- }
1856
- free(oldLua);
1857
- }
1858
- }
1859
-
1860
- free(unpackFrameLua);
1861
- free(packFrameLua);
1862
- }
1863
-
1864
- oldLua = lua;
1865
- if (asprintf(&lua,
1866
- "local sid = ARGV[1]\n"
1867
- "local mid = ARGV[2]\n"
1868
- "local score = tonumber(ARGV[3])\n"
1869
- "local assert_fact = tonumber(ARGV[4])\n"
1870
- "local keys_count = tonumber(ARGV[5])\n"
1871
- "local events_hashset = \"%s!e!\" .. sid\n"
1872
- "local facts_hashset = \"%s!f!\" .. sid\n"
1873
- "local visited_hashset = \"%s!v!\" .. sid\n"
1874
- "local actions_key = \"%s!a\"\n"
1875
- "local state_key = \"%s!s\"\n"
1876
- "local mid_count_hashset = \"%s!c\"\n"
1877
- "local facts_message_cache = {}\n"
1878
- "local events_message_cache = {}\n"
1879
- "local facts_mids_cache = {}\n"
1880
- "local events_mids_cache = {}\n"
1881
- "local input_keys = {}\n"
1882
- "local function_tree = {}\n"
1883
- "local results\n"
1884
- "local is_distinct_message = function(frame, message)\n"
1885
- " for name, frame_message in pairs(frame) do\n"
1886
- " if frame_message[\"id\"] == message[\"id\"] then\n"
1887
- " return false\n"
1888
- " end\n"
1889
- " end\n"
1890
- " return true\n"
1891
- "end\n"
1892
- "local compare_array = function(left_array, right_value, op, compare_all)\n"
1893
- " if not left_array or type(left_array) ~= \"table\" then\n"
1894
- " return false\n"
1895
- " end\n"
1896
- " for i = 1, #left_array, 1 do\n"
1897
- " local comparison = false\n"
1898
- " if op == 0 then\n"
1899
- " comparison = (left_array[i] < right_value)\n"
1900
- " elseif op == 1 then\n"
1901
- " comparison = (left_array[i] <= right_value)\n"
1902
- " elseif op == 2 then\n"
1903
- " comparison = (left_array[i] > right_value)\n"
1904
- " elseif op == 3 then\n"
1905
- " comparison = (left_array[i] >= right_value)\n"
1906
- " elseif op == 4 then\n"
1907
- " comparison = (left_array[i] == right_value)\n"
1908
- " elseif op == 5 then\n"
1909
- " comparison = (left_array[i] ~= right_value)\n"
1910
- " end\n"
1911
- " if not compare_all and comparison then\n"
1912
- " return true\n"
1913
- " end\n"
1914
- " if compare_all and not comparison then\n"
1915
- " return false\n"
1916
- " end\n"
1917
- " end"
1918
- " if compare_all then\n"
1919
- " return true\n"
1920
- " end\n"
1921
- " return false\n"
1922
- "end\n"
1923
- "local cleanup_mids = function(index, frame, events_key, messages_key, mids_cache, message_cache, context)\n"
1924
- " local event_mids = mids_cache[events_key]\n"
1925
- " local primary_key = context[\"primary_frame_keys\"][index](frame)\n"
1926
- " local new_mids = event_mids[primary_key]\n"
1927
- " local result_mids = {}\n"
1928
- " for i = 1, #new_mids, 1 do\n"
1929
- " local new_mid = new_mids[i]\n"
1930
- " if message_cache[new_mid] ~= false then\n"
1931
- " table.insert(result_mids, new_mid)\n"
1932
- " end\n"
1933
- " end\n"
1934
- " event_mids[primary_key] = result_mids\n"
1935
- " redis.call(\"del\", events_key .. \"!m!\" .. primary_key)\n"
1936
- " for i = 1, #result_mids, 1 do\n"
1937
- " redis.call(\"rpush\", events_key .. \"!m!\" .. primary_key, result_mids[i])\n"
1938
- " end\n"
1939
- "end\n"
1940
- "local get_mids = function(index, frame, events_key, messages_key, mids_cache, message_cache, context)\n"
1941
- " local event_mids = mids_cache[events_key]\n"
1942
- " local primary_key = context[\"primary_frame_keys\"][index](frame)\n"
1943
- " local new_mids = nil\n"
1944
- " if not event_mids then\n"
1945
- " event_mids = {}\n"
1946
- " mids_cache[events_key] = event_mids\n"
1947
- " else\n"
1948
- " new_mids = event_mids[primary_key]\n"
1949
- " end\n"
1950
- " if not new_mids then\n"
1951
- " new_mids = redis.call(\"lrange\", events_key .. \"!m!\" .. primary_key, 0, -1)\n"
1952
- " event_mids[primary_key] = new_mids\n"
1953
- " end\n"
1954
- " return new_mids\n"
1955
- "end\n"
1956
- "local get_message = function(new_mid, messages_key, message_cache)\n"
1957
- " local message = false\n"
1958
- " new_mid = tostring(new_mid)\n"
1959
- " if message_cache[new_mid] ~= nil then\n"
1960
- " message = message_cache[new_mid]\n"
1961
- " else\n"
1962
- " local packed_message = redis.call(\"hget\", messages_key, new_mid)\n"
1963
- " if packed_message then\n"
1964
- " message = cmsgpack.unpack(packed_message)\n"
1965
- " end\n"
1966
- " message_cache[new_mid] = message\n"
1967
- " end\n"
1968
- " return message\n"
1969
- "end\n"
1970
- "local fetch_message = function(new_mid)\n"
1971
- " local message = get_message(new_mid, events_hashset, events_message_cache)\n"
1972
- " if not message then\n"
1973
- " message = get_message(new_mid, facts_hashset, facts_message_cache)\n"
1974
- " end\n"
1975
- " return message\n"
1976
- "end\n"
1977
- "local save_message = function(index, message, events_key, messages_key, context)\n"
1978
- " redis.call(\"hsetnx\", messages_key, message[\"id\"], cmsgpack.pack(message))\n"
1979
- " local primary_key = context[\"primary_message_keys\"][index](message)\n"
1980
- " redis.call(\"lpush\", events_key .. \"!m!\" .. primary_key, message[\"id\"])\n"
1981
- "end\n"
1982
- "local save_result = function(frame, index, context)\n"
1983
- " table.insert(results, 1, context[\"frame_packers\"][index](frame, true))\n"
1984
- " for name, message in pairs(frame) do\n"
1985
- " if message ~= \"$n\" and not message[\"$f\"] then\n"
1986
- " redis.call(\"hdel\", events_hashset, message[\"id\"])\n"
1987
- // message cache always looked up using strings
1988
- " events_message_cache[tostring(message[\"id\"])] = false\n"
1989
- " end\n"
1990
- " end\n"
1991
- "end\n"
1992
- "local is_pure_fact = function(frame, index)\n"
1993
- " local message_count = 0\n"
1994
- " for name, message in pairs(frame) do\n"
1995
- " if message ~= 1 and message[\"$f\"] ~= 1 then\n"
1996
- " return false\n"
1997
- " end\n"
1998
- " message_count = message_count + 1\n"
1999
- " end\n"
2000
- " return (message_count == index - 1)\n"
2001
- "end\n"
2002
- "local process_frame\n"
2003
- "local process_event_and_frame = function(message, frame, index, use_facts, context)\n"
2004
- " local result = 0\n"
2005
- " local new_frame = {}\n"
2006
- " for name, new_message in pairs(frame) do\n"
2007
- " new_frame[name] = new_message\n"
2008
- " end\n"
2009
- " if context[\"reviewers\"][index](message, new_frame, index) then\n"
2010
- " if (index == context[\"expressions_count\"]) then\n"
2011
- " save_result(new_frame, index, context)\n"
2012
- " return 1\n"
2013
- " else\n"
2014
- " result = process_frame(new_frame, index + 1, use_facts, context)\n"
2015
- " if result == 0 or use_facts then\n"
2016
- " local frames_key\n"
2017
- " local primary_key = context[\"primary_frame_keys\"][index + 1](new_frame)\n"
2018
- " frames_key = context[\"keys\"][index + 1] .. \"!c!\" .. sid .. \"!\" .. primary_key\n"
2019
- " redis.call(\"rpush\", frames_key, context[\"frame_packers\"][index](new_frame))\n"
2020
- " end\n"
2021
- " end\n"
2022
- " end\n"
2023
- " return result\n"
2024
- "end\n"
2025
- "local process_frame_for_key = function(frame, index, events_key, use_facts, context)\n"
2026
- " local result = nil\n"
2027
- " local inverse = context[\"inverse_directory\"][index]\n"
2028
- " local messages_key = events_hashset\n"
2029
- " local message_cache = events_message_cache\n"
2030
- " local mids_cache = events_mids_cache\n"
2031
- " local cleanup = false\n"
2032
- " if use_facts then\n"
2033
- " messages_key = facts_hashset\n"
2034
- " message_cache = facts_message_cache\n"
2035
- " mids_cache = facts_mids_cache\n"
2036
- " end\n"
2037
- " if inverse then\n"
2038
- " local new_frame = {}\n"
2039
- " for name, new_message in pairs(frame) do\n"
2040
- " new_frame[name] = new_message\n"
2041
- " end\n"
2042
- " local new_mids = get_mids(index, frame, events_key, messages_key, mids_cache, message_cache, context)\n"
2043
- " for i = 1, #new_mids, 1 do\n"
2044
- " local message = get_message(new_mids[i], messages_key, message_cache)\n"
2045
- " if not message then\n"
2046
- " cleanup = true\n"
2047
- " elseif not context[\"reviewers\"][index](message, new_frame, index) then\n"
2048
- " local frames_key = context[\"keys\"][index] .. \"!i!\" .. sid .. \"!\" .. new_mids[i]\n"
2049
- " redis.call(\"rpush\", frames_key, context[\"frame_packers\"][index - 1](new_frame))\n"
2050
- " result = 0\n"
2051
- " break\n"
2052
- " end\n"
2053
- " end\n"
2054
- " else\n"
2055
- " local new_mids = get_mids(index, frame, events_key, messages_key, mids_cache, message_cache, context)\n"
2056
- " for i = 1, #new_mids, 1 do\n"
2057
- " local message = get_message(new_mids[i], messages_key, message_cache)\n"
2058
- " if not message then\n"
2059
- " cleanup = true\n"
2060
- " else\n"
2061
- " local count = process_event_and_frame(message, frame, index, use_facts, context)\n"
2062
- " if not result then\n"
2063
- " result = 0\n"
2064
- " end\n"
2065
- " result = result + count\n"
2066
- " if not is_pure_fact(frame, index) then\n"
2067
- // the mid list might not be cleaned up if the first mid is always valid.
2068
- " if (#new_mids == 1) or ((#new_mids %% 10) == 0) then\n"
2069
- " cleanup = true\n"
2070
- " end\n"
2071
- " break\n"
2072
- " end\n"
2073
- " end\n"
2074
- " end\n"
2075
- " end\n"
2076
- " if cleanup then\n"
2077
- " cleanup_mids(index, frame, events_key, messages_key, mids_cache, message_cache, context)\n"
2078
- " end\n"
2079
- " return result\n"
2080
- "end\n"
2081
- "process_frame = function(frame, index, use_facts, context)\n"
2082
- " local first_result = process_frame_for_key(frame, index, context[\"keys\"][index] .. \"!e!\" .. sid, false, context)\n"
2083
- " local second_result = process_frame_for_key(frame, index, context[\"keys\"][index] .. \"!f!\" .. sid, true, context)\n"
2084
- " if not first_result and not second_result then\n"
2085
- " return process_event_and_frame(nil, frame, index, use_facts, context)\n"
2086
- " elseif not first_result then\n"
2087
- " return second_result\n"
2088
- " elseif not second_result then\n"
2089
- " return first_result\n"
2090
- " else\n"
2091
- " return first_result + second_result\n"
2092
- " end\n"
2093
- "end\n"
2094
- "local process_inverse_event = function(message, index, events_key, use_facts, context)\n"
2095
- " local result = 0\n"
2096
- " local messages_key = events_hashset\n"
2097
- " if use_facts then\n"
2098
- " messages_key = facts_hashset\n"
2099
- " end\n"
2100
- " redis.call(\"hdel\", messages_key, mid)\n"
2101
- " if index == 1 then\n"
2102
- " result = process_frame({}, 1, use_facts, context)\n"
2103
- " else\n"
2104
- " local frames_key = context[\"keys\"][index] .. \"!i!\" .. sid .. \"!\" .. mid\n"
2105
- " local packed_frames_len = redis.call(\"llen\", frames_key)\n"
2106
- " for i = 1, packed_frames_len, 1 do\n"
2107
- " local packed_frame = redis.call(\"rpop\", frames_key)\n"
2108
- " local frame = context[\"frame_unpackers\"][index - 1](packed_frame)\n"
2109
- " if frame then\n"
2110
- " result = result + process_frame(frame, index, use_facts, context)\n"
2111
- " end\n"
2112
- " end\n"
2113
- " end\n"
2114
- " return result\n"
2115
- "end\n"
2116
- "local process_event = function(message, index, events_key, use_facts, context)\n"
2117
- " local result = 0\n"
2118
- " local messages_key = events_hashset\n"
2119
- " if use_facts then\n"
2120
- " messages_key = facts_hashset\n"
2121
- " end\n"
2122
- " if index == 1 then\n"
2123
- " result = process_event_and_frame(message, {}, 1, use_facts, context)\n"
2124
- " else\n"
2125
- " local frames_key\n"
2126
- " local primary_key = context[\"primary_message_keys\"][index](message)\n"
2127
- " if primary_key then\n"
2128
- " frames_key = context[\"keys\"][index] .. \"!c!\" .. sid .. \"!\" .. primary_key\n"
2129
- " else\n"
2130
- " frames_key = context[\"keys\"][index] .. \"!c!\" .. sid\n"
2131
- " end\n"
2132
- " local packed_frames_len = redis.call(\"llen\", frames_key)\n"
2133
- " for i = 1, packed_frames_len, 1 do\n"
2134
- " local packed_frame = redis.call(\"rpop\", frames_key)\n"
2135
- " local frame = context[\"frame_unpackers\"][index - 1](packed_frame)\n"
2136
- " if frame then\n"
2137
- " local count = process_event_and_frame(message, frame, index, use_facts, context)\n"
2138
- " result = result + count\n"
2139
- " if count == 0 or use_facts then\n"
2140
- " redis.call(\"lpush\", frames_key, packed_frame)\n"
2141
- " else\n"
2142
- " break\n"
2143
- " end\n"
2144
- " end\n"
2145
- " end\n"
2146
- " end\n"
2147
- " if result == 0 or use_facts then\n"
2148
- " save_message(index, message, events_key, messages_key, context)\n"
2149
- " end\n"
2150
- " return result\n"
2151
- "end\n"
2152
- "local process_key_with_cap = function(message, cap, key, context)\n"
2153
- " local index = context[\"directory\"][key]\n"
2154
- " local result_recorded = false\n"
2155
- " if index then\n"
2156
- " local count = 0\n"
2157
- " if not message then\n"
2158
- " if assert_fact == 0 then\n"
2159
- " count = process_inverse_event(message, index, context[\"keys\"][index] .. \"!e!\" .. sid, false, context)\n"
2160
- " else\n"
2161
- " count = process_inverse_event(message, index, context[\"keys\"][index] .. \"!f!\" .. sid, true, context)\n"
2162
- " end\n"
2163
- " else\n"
2164
- " if assert_fact == 0 then\n"
2165
- " count = process_event(message, index, context[\"keys\"][index] .. \"!e!\" .. sid, false, context)\n"
2166
- " else\n"
2167
- " count = process_event(message, index, context[\"keys\"][index] .. \"!f!\" .. sid, true, context)\n"
2168
- " end\n"
2169
- " end\n"
2170
- " if (count > 0) then\n"
2171
- " result_recorded = true\n"
2172
- " for i = #results, 1, -1 do\n"
2173
- " redis.call(\"lpush\", context[\"results_key\"], results[i])\n"
2174
- " end\n"
2175
- " local diff\n"
2176
- " local new_count, new_remain = math.modf(#results / cap)\n"
2177
- " local new_remain = #results %% cap\n"
2178
- " if new_count > 0 then\n"
2179
- " for i = 1, new_count, 1 do\n"
2180
- " redis.call(\"rpush\", actions_key .. \"!\" .. sid, context[\"results_key\"])\n"
2181
- " redis.call(\"rpush\", actions_key .. \"!\" .. sid, \"$c\" .. cap)\n"
2182
- " end\n"
2183
- " end\n"
2184
- " if new_remain > 0 then\n"
2185
- " redis.call(\"rpush\", actions_key .. \"!\" .. sid, context[\"results_key\"])\n"
2186
- " redis.call(\"rpush\", actions_key .. \"!\" .. sid, \"$c\" .. new_remain)\n"
2187
- " end\n"
2188
- " if new_remain > 0 or new_count > 0 then\n"
2189
- " if not redis.call(\"zscore\", actions_key, sid) then\n"
2190
- " redis.call(\"zadd\", actions_key , score, sid)\n"
2191
- " end\n"
2192
- " end\n"
2193
- " end\n"
2194
- " end\n"
2195
- " return result_recorded\n"
2196
- "end\n"
2197
- "local process_key_with_window = function(message, window, key, context)\n"
2198
- " local index = context[\"directory\"][key]\n"
2199
- " local result_recorded = false\n"
2200
- " if index then\n"
2201
- " local count = 0\n"
2202
- " if not message then\n"
2203
- " if assert_fact == 0 then\n"
2204
- " count = process_inverse_event(message, index, context[\"keys\"][index] .. \"!e!\" .. sid, false, context)\n"
2205
- " else\n"
2206
- " count = process_inverse_event(message, index, context[\"keys\"][index] .. \"!f!\" .. sid, true, context)\n"
2207
- " end\n"
2208
- " else\n"
2209
- " if assert_fact == 0 then\n"
2210
- " count = process_event(message, index, context[\"keys\"][index] .. \"!e!\" .. sid, false, context)\n"
2211
- " else\n"
2212
- " count = process_event(message, index, context[\"keys\"][index] .. \"!f!\" .. sid, true, context)\n"
2213
- " end\n"
2214
- " end\n"
2215
- " if (count > 0) then\n"
2216
- " result_recorded = true\n"
2217
- " for i = #results, 1, -1 do\n"
2218
- " redis.call(\"lpush\", context[\"results_key\"], results[i])\n"
2219
- " end\n"
2220
- " local diff\n"
2221
- " local length = redis.call(\"llen\", context[\"results_key\"])\n"
2222
- " local prev_count, prev_remain = math.modf((length - count) / window)\n"
2223
- " local new_count, prev_remain = math.modf(length / window)\n"
2224
- " diff = new_count - prev_count\n"
2225
- " if diff > 0 then\n"
2226
- " for i = 0, diff - 1, 1 do\n"
2227
- " redis.call(\"rpush\", actions_key .. \"!\" .. sid, context[\"results_key\"])\n"
2228
- " redis.call(\"rpush\", actions_key .. \"!\" .. sid, \"$w\" .. window)\n"
2229
- " end\n"
2230
- " if not redis.call(\"zscore\", actions_key, sid) then\n"
2231
- " redis.call(\"zadd\", actions_key , score, sid)\n"
2232
- " end\n"
2233
- " end\n"
2234
- " end\n"
2235
- " end\n"
2236
- " return result_recorded\n"
2237
- "end\n"
2238
- "local process_message = function(message, key, context)\n"
2239
- " results = {}\n"
2240
- " local process_key = context[\"process_key\"]\n"
2241
- " local process_key_count = context[\"process_key_count\"]\n"
2242
- " local result_recorded = process_key(message, process_key_count, key, context)\n"
2243
- " if assert_fact == 0 and result_recorded then\n"
2244
- " return false\n"
2245
- " end\n"
2246
- " return true\n"
2247
- "end\n"
2248
- "local create_context = function()\n"
2249
- " local context = {}\n"
2250
- " context[\"reviewers\"] = {}\n"
2251
- " context[\"frame_packers\"] = {}\n"
2252
- " context[\"frame_unpackers\"] = {}\n"
2253
- " context[\"primary_message_keys\"] = {}\n"
2254
- " context[\"primary_frame_keys\"] = {}\n"
2255
- " context[\"keys\"] = {}\n"
2256
- " context[\"inverse_directory\"] = {}\n"
2257
- " context[\"directory\"] = {[\"0\"] = 1}\n"
2258
- " return context\n"
2259
- "end\n"
2260
- "local message = nil\n"
2261
- "if #ARGV > (6 + keys_count) then\n"
2262
- " message = {}\n"
2263
- " for index = 6 + keys_count, #ARGV, 3 do\n"
2264
- " if ARGV[index + 2] == \"1\" then\n"
2265
- " message[ARGV[index]] = ARGV[index + 1]\n"
2266
- " elseif ARGV[index + 2] == \"2\" or ARGV[index + 2] == \"3\" then\n"
2267
- " message[ARGV[index]] = tonumber(ARGV[index + 1])\n"
2268
- " elseif ARGV[index + 2] == \"4\" then\n"
2269
- " if ARGV[index + 1] == \"true\" then\n"
2270
- " message[ARGV[index]] = true\n"
2271
- " else\n"
2272
- " message[ARGV[index]] = false\n"
2273
- " end\n"
2274
- " elseif ARGV[index + 2] == \"5\" then\n"
2275
- " message[ARGV[index]] = cjson.decode(ARGV[index + 1])\n"
2276
- " elseif ARGV[index + 2] == \"7\" then\n"
2277
- " message[ARGV[index]] = \"$null\"\n"
2278
- " end\n"
2279
- " end\n"
2280
- " if assert_fact == 1 then\n"
2281
- " message[\"$f\"] = 1\n"
2282
- " end\n"
2283
- "end\n"
2284
- "if mid == \"\" then\n"
2285
- " mid = \"$m-\" .. redis.call(\"hincrby\", mid_count_hashset, sid, 1)\n"
2286
- " if message then\n"
2287
- " message[\"id\"] = mid\n"
2288
- " end\n"
2289
- "else\n"
2290
- " if assert_fact == 1 then\n"
2291
- " if message and redis.call(\"hexists\", facts_hashset, mid) == 1 then\n"
2292
- " return %d\n"
2293
- " end\n"
2294
- " else\n"
2295
- " if message and redis.call(\"hsetnx\", visited_hashset, mid, 1) == 0 then\n"
2296
- " return %d\n"
2297
- " end\n"
2298
- " end\n"
2299
- "end\n"
2300
- "for index = 6, 5 + keys_count, 1 do\n"
2301
- " input_keys[ARGV[index]] = true\n"
2302
- "end\n"
2303
- "%s"
2304
- "for index = 6, 5 + keys_count, 1 do\n"
2305
- " if function_tree[ARGV[index]](ARGV[index], nil) == false then\n"
2306
- " return\n"
2307
- " end\n"
2308
- "end\n",
2309
- name,
2310
- name,
2311
- name,
2312
- name,
2313
- name,
2314
- name,
2315
- ERR_EVENT_OBSERVED,
2316
- ERR_EVENT_OBSERVED,
2317
- lua) == -1) {
2318
- return ERR_OUT_OF_MEMORY;
2319
- }
2320
-
2321
- //printf("%s\n", lua);
2322
- free(oldLua);
2323
- unsigned int result = redisAppendCommand(reContext, "SCRIPT LOAD %s", lua);
2324
- GET_REPLY(result, "loadEvalMessageCommand", reply);
2325
-
2326
- strncpy(rulesBinding->evalMessageHash, reply->str, 40);
2327
- rulesBinding->evalMessageHash[40] = '\0';
2328
- freeReplyObject(reply);
2329
- free(lua);
2330
- return RULES_OK;
2331
- }
2332
-
2333
- static unsigned int setNames(ruleset *tree, binding *rulesBinding) {
2334
- char *name = &tree->stringPool[tree->nameOffset];
2335
- int nameLength = strlen(name);
2336
- char *sessionHashset = malloc((nameLength + 3) * sizeof(char));
2337
- if (!sessionHashset) {
2338
- return ERR_OUT_OF_MEMORY;
2339
- }
2340
-
2341
- strncpy(sessionHashset, name, nameLength);
2342
- sessionHashset[nameLength] = '!';
2343
- sessionHashset[nameLength + 1] = 's';
2344
- sessionHashset[nameLength + 2] = '\0';
2345
- rulesBinding->sessionHashset = sessionHashset;
2346
-
2347
- char *factsHashset = malloc((nameLength + 3) * sizeof(char));
2348
- if (!factsHashset) {
2349
- return ERR_OUT_OF_MEMORY;
2350
- }
2351
-
2352
- strncpy(factsHashset, name, nameLength);
2353
- factsHashset[nameLength] = '!';
2354
- factsHashset[nameLength + 1] = 'f';
2355
- factsHashset[nameLength + 2] = '\0';
2356
- rulesBinding->factsHashset = factsHashset;
2357
-
2358
- char *eventsHashset = malloc((nameLength + 3) * sizeof(char));
2359
- if (!eventsHashset) {
2360
- return ERR_OUT_OF_MEMORY;
2361
- }
2362
-
2363
- strncpy(eventsHashset, name, nameLength);
2364
- eventsHashset[nameLength] = '!';
2365
- eventsHashset[nameLength + 1] = 'e';
2366
- eventsHashset[nameLength + 2] = '\0';
2367
- rulesBinding->eventsHashset = eventsHashset;
2368
-
2369
- char *partitionHashset = malloc((nameLength + 3) * sizeof(char));
2370
- if (!partitionHashset) {
2371
- return ERR_OUT_OF_MEMORY;
2372
- }
2373
-
2374
- strncpy(partitionHashset, name, nameLength);
2375
- partitionHashset[nameLength] = '!';
2376
- partitionHashset[nameLength + 1] = 'p';
2377
- partitionHashset[nameLength + 2] = '\0';
2378
- rulesBinding->partitionHashset = partitionHashset;
2379
-
2380
- char *timersSortedset = malloc((nameLength + 3) * sizeof(char));
2381
- if (!timersSortedset) {
2382
- return ERR_OUT_OF_MEMORY;
2383
- }
2384
-
2385
- strncpy(timersSortedset, name, nameLength);
2386
- timersSortedset[nameLength] = '!';
2387
- timersSortedset[nameLength + 1] = 't';
2388
- timersSortedset[nameLength + 2] = '\0';
2389
- rulesBinding->timersSortedset = timersSortedset;
2390
- return RULES_OK;
2391
- }
2392
-
2393
- static unsigned int loadCommands(ruleset *tree, binding *rulesBinding) {
2394
- unsigned int result = loadPartitionCommand(tree, rulesBinding);
2395
- if (result != RULES_OK) {
2396
- return result;
2397
- }
2398
-
2399
- // client queues have no commands to load,
2400
- if (!tree->stringPool) {
2401
- return RULES_OK;
2402
- }
2403
-
2404
- result = loadTimerCommand(tree, rulesBinding);
2405
- if (result != RULES_OK) {
2406
- return result;
2407
- }
2408
-
2409
- result = loadRemoveTimerCommand(tree, rulesBinding);
2410
- if (result != RULES_OK) {
2411
- return result;
2412
- }
2413
-
2414
- result = loadEvalMessageCommand(tree, rulesBinding);
2415
- if (result != RULES_OK) {
2416
- return result;
2417
- }
2418
-
2419
- result = loadAddMessageCommand(tree, rulesBinding);
2420
- if (result != RULES_OK) {
2421
- return result;
2422
- }
2423
-
2424
- result = loadPeekActionCommand(tree, rulesBinding);
2425
- if (result != RULES_OK) {
2426
- return result;
2427
- }
2428
-
2429
- result = loadUpdateActionCommand(tree, rulesBinding);
2430
- if (result != RULES_OK) {
2431
- return result;
2432
- }
2433
-
2434
- result = loadRemoveActionCommand(tree, rulesBinding);
2435
- if (result != RULES_OK) {
2436
- return result;
2437
- }
2438
-
2439
- result = loadDeleteSessionCommand(tree, rulesBinding);
2440
- if (result != RULES_OK) {
2441
- return result;
2442
- }
2443
-
2444
- result = setNames(tree, rulesBinding);
2445
- if (result != RULES_OK) {
2446
- return result;
2447
- }
2448
-
2449
- return RULES_OK;
2450
- }
2451
-
2452
- unsigned int bindRuleset(unsigned int handle,
2453
- char *host,
2454
- unsigned int port,
2455
- char *password,
2456
- unsigned char db) {
2457
- ruleset *tree;
2458
- RESOLVE_HANDLE(handle, &tree);
2459
-
2460
- bindingsList *list;
2461
- if (tree->bindingsList) {
2462
- list = tree->bindingsList;
2463
- }
2464
- else {
2465
- list = malloc(sizeof(bindingsList));
2466
- if (!list) {
2467
- return ERR_OUT_OF_MEMORY;
2468
- }
2469
-
2470
- list->bindings = NULL;
2471
- list->bindingsLength = 0;
2472
- list->lastBinding = 0;
2473
- list->lastTimersBinding = 0;
2474
- tree->bindingsList = list;
2475
- }
2476
-
2477
- redisContext *reContext;
2478
- if (port == 0) {
2479
- reContext = redisConnectUnix(host);
2480
- } else {
2481
- reContext = redisConnect(host, port);
2482
- }
2483
-
2484
- if (reContext->err) {
2485
- redisFree(reContext);
2486
- return ERR_CONNECT_REDIS;
2487
- }
2488
-
2489
- int result = REDIS_OK;
2490
-
2491
- #ifndef _WIN32
2492
- struct timeval tv;
2493
- tv.tv_sec = 10;
2494
- tv.tv_usec = 0;
2495
- result = redisSetTimeout(reContext, tv);
2496
- if (result != REDIS_OK) {
2497
- return ERR_REDIS_ERROR;
2498
- }
2499
- #endif
2500
-
2501
- if (password != NULL) {
2502
- result = redisAppendCommand(reContext, "auth %s", password);
2503
- VERIFY(result, "bindRuleset");
2504
- }
2505
-
2506
- if (db) {
2507
- result = redisAppendCommand(reContext, "select %d", db);
2508
- VERIFY(result, "bindRuleset");
2509
- }
2510
-
2511
- if (!list->bindings) {
2512
- list->bindings = malloc(sizeof(binding));
2513
- }
2514
- else {
2515
- list->bindings = realloc(list->bindings, sizeof(binding) * (list->bindingsLength + 1));
2516
- }
2517
-
2518
- if (!list->bindings) {
2519
- redisFree(reContext);
2520
- return ERR_OUT_OF_MEMORY;
2521
- }
2522
- list->bindings[list->bindingsLength].reContext = reContext;
2523
- ++list->bindingsLength;
2524
- return loadCommands(tree, &list->bindings[list->bindingsLength -1]);
2525
- }
2526
-
2527
- unsigned int deleteBindingsList(ruleset *tree) {
2528
- bindingsList *list = tree->bindingsList;
2529
- if (tree->bindingsList != NULL) {
2530
- for (unsigned int i = 0; i < list->bindingsLength; ++i) {
2531
- binding *currentBinding = &list->bindings[i];
2532
- redisFree(currentBinding->reContext);
2533
- free(currentBinding->timersSortedset);
2534
- free(currentBinding->sessionHashset);
2535
- free(currentBinding->factsHashset);
2536
- free(currentBinding->eventsHashset);
2537
- }
2538
-
2539
- free(list->bindings);
2540
- free(list);
2541
- }
2542
- return RULES_OK;
2543
- }
2544
-
2545
- unsigned int getBindingIndex(ruleset *tree, unsigned int sidHash, unsigned int *bindingIndex) {
2546
- bindingsList *list = tree->bindingsList;
2547
- binding *firstBinding = &list->bindings[0];
2548
- redisContext *reContext = firstBinding->reContext;
2549
-
2550
- int result = redisAppendCommand(reContext,
2551
- "evalsha %s 0 %u %d",
2552
- firstBinding->partitionHash,
2553
- sidHash,
2554
- list->bindingsLength);
2555
- redisReply *reply;
2556
- GET_REPLY(result, "getBindingIndex", reply);
2557
-
2558
- *bindingIndex = reply->integer;
2559
- freeReplyObject(reply);
2560
- return RULES_OK;
2561
- }
2562
-
2563
- unsigned int formatEvalMessage(void *rulesBinding,
2564
- char *sid,
2565
- char *mid,
2566
- char *message,
2567
- jsonObject *jo,
2568
- unsigned char actionType,
2569
- char **keys,
2570
- unsigned int keysLength,
2571
- char **command) {
2572
- unsigned int propertiesLength = jo->propertiesLength;
2573
- if (actionType == ACTION_RETRACT_FACT || actionType == ACTION_RETRACT_EVENT) {
2574
- propertiesLength = 0;
2575
- }
2576
-
2577
- binding *bindingContext = (binding*)rulesBinding;
2578
- time_t currentTime = time(NULL);
2579
- char score[11];
2580
- char keysLengthString[5];
2581
- #ifdef _WIN32
2582
- sprintf_s(keysLengthString, sizeof(char) * 5, "%d", keysLength);
2583
- sprintf_s(score, sizeof(char) * 11, "%ld", currentTime);
2584
- char **argv = (char **)_alloca(sizeof(char*)*(8 + keysLength + propertiesLength * 3));
2585
- size_t *argvl = (size_t *)_alloca(sizeof(size_t)*(8 + keysLength + propertiesLength * 3));
2586
- #else
2587
- snprintf(keysLengthString, sizeof(char) * 5, "%d", keysLength);
2588
- snprintf(score, sizeof(char) * 11, "%ld", currentTime);
2589
- char *argv[8 + keysLength + propertiesLength * 3];
2590
- size_t argvl[8 + keysLength + propertiesLength * 3];
2591
- #endif
2592
-
2593
- argv[0] = "evalsha";
2594
- argvl[0] = 7;
2595
- argv[1] = bindingContext->evalMessageHash;
2596
- argvl[1] = 40;
2597
- argv[2] = "0";
2598
- argvl[2] = 1;
2599
- argv[3] = sid;
2600
- argvl[3] = strlen(sid);
2601
- argv[4] = mid;
2602
- argvl[4] = strlen(mid);
2603
- argv[5] = score;
2604
- argvl[5] = strlen(score);
2605
- argv[6] = (actionType == ACTION_ASSERT_FACT || actionType == ACTION_RETRACT_FACT) ? "1" : "0";
2606
- argvl[6] = 1;
2607
- argv[7] = keysLengthString;
2608
- argvl[7] = strlen(keysLengthString);
2609
-
2610
- for (unsigned int i = 0; i < keysLength; ++i) {
2611
- argv[8 + i] = keys[i];
2612
- argvl[8 + i] = strlen(keys[i]);
2613
- }
2614
-
2615
- unsigned int offset = 8 + keysLength;
2616
- for (unsigned int i = 0; i < propertiesLength; ++i) {
2617
- argv[offset + i * 3] = jo->properties[i].name;
2618
- argvl[offset + i * 3] = jo->properties[i].nameLength;
2619
- argv[offset + i * 3 + 1] = jo->properties[i].valueString;
2620
- if (jo->properties[i].type == JSON_STRING) {
2621
- argvl[offset + i * 3 + 1] = jo->properties[i].valueLength;
2622
- } else {
2623
- argvl[offset + i * 3 + 1] = jo->properties[i].valueLength + 1;
2624
- }
2625
-
2626
- switch(jo->properties[i].type) {
2627
- case JSON_STRING:
2628
- argv[offset + i * 3 + 2] = "1";
2629
- break;
2630
- case JSON_INT:
2631
- argv[offset + i * 3 + 2] = "2";
2632
- break;
2633
- case JSON_DOUBLE:
2634
- argv[offset + i * 3 + 2] = "3";
2635
- break;
2636
- case JSON_BOOL:
2637
- argv[offset + i * 3 + 2] = "4";
2638
- break;
2639
- case JSON_ARRAY:
2640
- argv[offset + i * 3 + 2] = "5";
2641
- break;
2642
- case JSON_NIL:
2643
- argv[offset + i * 3 + 2] = "7";
2644
- break;
2645
- }
2646
- argvl[offset + i * 3 + 2] = 1;
2647
- }
2648
-
2649
- int result = redisFormatCommandArgv(command, offset + propertiesLength * 3, (const char**)argv, argvl);
2650
- if (result == 0) {
2651
- return ERR_OUT_OF_MEMORY;
2652
- }
2653
- return RULES_OK;
2654
- }
2655
-
2656
- unsigned int formatStoreMessage(void *rulesBinding,
2657
- char *sid,
2658
- char *message,
2659
- jsonObject *jo,
2660
- unsigned char storeFact,
2661
- unsigned char markVisited,
2662
- char **keys,
2663
- unsigned int keysLength,
2664
- char **command) {
2665
- unsigned int propertiesLength = jo->propertiesLength;
2666
-
2667
- binding *bindingContext = (binding*)rulesBinding;
2668
- char keysLengthString[5];
2669
- #ifdef _WIN32
2670
- sprintf_s(keysLengthString, sizeof(char) * 5, "%d", keysLength);
2671
- char **argv = (char **)_alloca(sizeof(char*)*(7 + keysLength + propertiesLength * 3));
2672
- size_t *argvl = (size_t *)_alloca(sizeof(size_t)*(7 + keysLength + propertiesLength * 3));
2673
- #else
2674
- snprintf(keysLengthString, sizeof(char) * 5, "%d", keysLength);
2675
- char *argv[7 + keysLength + propertiesLength * 3];
2676
- size_t argvl[7 + keysLength + propertiesLength * 3];
2677
- #endif
2678
-
2679
- argv[0] = "evalsha";
2680
- argvl[0] = 7;
2681
- argv[1] = bindingContext->addMessageHash;
2682
- argvl[1] = 40;
2683
- argv[2] = "0";
2684
- argvl[2] = 1;
2685
- argv[3] = sid;
2686
- argvl[3] = strlen(sid);
2687
- argv[4] = storeFact ? "1" : "0";
2688
- argvl[4] = 1;
2689
- argv[5] = markVisited ? "1" : "0";
2690
- argvl[5] = 1;
2691
- argv[6] = keysLengthString;
2692
- argvl[6] = strlen(keysLengthString);
2693
-
2694
- for (unsigned int i = 0; i < keysLength; ++i) {
2695
- argv[7 + i] = keys[i];
2696
- argvl[7 + i] = strlen(keys[i]);
2697
- }
2698
-
2699
- unsigned int offset = 7 + keysLength;
2700
- for (unsigned int i = 0; i < propertiesLength; ++i) {
2701
- argv[offset + i * 3] = jo->properties[i].name;
2702
- argvl[offset + i * 3] = jo->properties[i].nameLength;
2703
- argv[offset + i * 3 + 1] = jo->properties[i].valueString;
2704
- if (jo->properties[i].type == JSON_STRING) {
2705
- argvl[offset + i * 3 + 1] = jo->properties[i].valueLength;
2706
- } else {
2707
- argvl[offset + i * 3 + 1] = jo->properties[i].valueLength + 1;
2708
- }
2709
-
2710
- switch(jo->properties[i].type) {
2711
- case JSON_STRING:
2712
- argv[offset + i * 3 + 2] = "1";
2713
- break;
2714
- case JSON_INT:
2715
- argv[offset + i * 3 + 2] = "2";
2716
- break;
2717
- case JSON_DOUBLE:
2718
- argv[offset + i * 3 + 2] = "3";
2719
- break;
2720
- case JSON_BOOL:
2721
- argv[offset + i * 3 + 2] = "4";
2722
- break;
2723
- case JSON_ARRAY:
2724
- argv[offset + i * 3 + 2] = "5";
2725
- break;
2726
- case JSON_NIL:
2727
- argv[offset + i * 3 + 2] = "7";
2728
- break;
2729
- }
2730
- argvl[offset + i * 3 + 2] = 1;
2731
- }
2732
-
2733
- int result = redisFormatCommandArgv(command, offset + propertiesLength * 3, (const char**)argv, argvl);
2734
- if (result == 0) {
2735
- return ERR_OUT_OF_MEMORY;
2736
- }
2737
- return RULES_OK;
2738
- }
2739
-
2740
- unsigned int formatStoreSession(void *rulesBinding,
2741
- char *sid,
2742
- char *state,
2743
- unsigned char tryExists,
2744
- char **storeCommand) {
2745
- binding *currentBinding = (binding*)rulesBinding;
2746
-
2747
- int result;
2748
- if (tryExists) {
2749
- result = redisFormatCommand(storeCommand,
2750
- "hsetnx %s %s %s",
2751
- currentBinding->sessionHashset,
2752
- sid,
2753
- state);
2754
- } else {
2755
- result = redisFormatCommand(storeCommand,
2756
- "hset %s %s %s",
2757
- currentBinding->sessionHashset,
2758
- sid,
2759
- state);
2760
- }
2761
-
2762
- if (result == 0) {
2763
- return ERR_OUT_OF_MEMORY;
2764
- }
2765
- return RULES_OK;
2766
- }
2767
-
2768
- unsigned int formatStoreSessionFact(void *rulesBinding,
2769
- char *sid,
2770
- char *message,
2771
- unsigned char tryExists,
2772
- char **command) {
2773
- binding *currentBinding = (binding*)rulesBinding;
2774
-
2775
- int result;
2776
- if (tryExists) {
2777
- result = redisFormatCommand(command,
2778
- "hsetnx %s %s!f %s",
2779
- currentBinding->sessionHashset,
2780
- sid,
2781
- message);
2782
- } else {
2783
- result = redisFormatCommand(command,
2784
- "hset %s %s!f %s",
2785
- currentBinding->sessionHashset,
2786
- sid,
2787
- message);
2788
- }
2789
-
2790
- if (result == 0) {
2791
- return ERR_OUT_OF_MEMORY;
2792
- }
2793
- return RULES_OK;
2794
- }
2795
-
2796
- unsigned int formatRemoveTimer(void *rulesBinding,
2797
- char *timer,
2798
- char **command) {
2799
- binding *currentBinding = (binding*)rulesBinding;
2800
- int result = redisFormatCommand(command,
2801
- "zrem %s %s",
2802
- currentBinding->timersSortedset,
2803
- timer);
2804
- if (result == 0) {
2805
- return ERR_OUT_OF_MEMORY;
2806
- }
2807
- return RULES_OK;
2808
- }
2809
-
2810
- unsigned int formatRemoveAction(void *rulesBinding,
2811
- char *sid,
2812
- char **command) {
2813
- binding *bindingContext = (binding*)rulesBinding;
2814
- time_t currentTime = time(NULL);
2815
-
2816
- int result = redisFormatCommand(command,
2817
- "evalsha %s 0 %s %ld",
2818
- bindingContext->removeActionHash,
2819
- sid,
2820
- currentTime);
2821
- if (result == 0) {
2822
- return ERR_OUT_OF_MEMORY;
2823
- }
2824
- return RULES_OK;
2825
- }
2826
-
2827
- unsigned int formatRemoveMessage(void *rulesBinding,
2828
- char *sid,
2829
- char *mid,
2830
- unsigned char removeFact,
2831
- char **command) {
2832
- binding *currentBinding = (binding*)rulesBinding;
2833
-
2834
- int result = 0;
2835
- if (removeFact) {
2836
- result = redisFormatCommand(command,
2837
- "hdel %s!%s %s",
2838
- currentBinding->factsHashset,
2839
- sid,
2840
- mid);
2841
- } else {
2842
- result = redisFormatCommand(command,
2843
- "hdel %s!%s %s",
2844
- currentBinding->eventsHashset,
2845
- sid,
2846
- mid);
2847
- }
2848
-
2849
- if (result == 0) {
2850
- return ERR_OUT_OF_MEMORY;
2851
- }
2852
- return RULES_OK;
2853
- }
2854
-
2855
- unsigned int formatPeekAction(void *rulesBinding,
2856
- char *sid,
2857
- char **command) {
2858
- binding *currentBinding = (binding*)rulesBinding;
2859
-
2860
- time_t currentTime = time(NULL);
2861
- int result = redisFormatCommand(command,
2862
- "evalsha %s 0 %d %ld %s",
2863
- currentBinding->peekActionHash,
2864
- currentTime + 15,
2865
- currentTime,
2866
- sid);
2867
- if (result == 0) {
2868
- return ERR_OUT_OF_MEMORY;
2869
- }
2870
-
2871
- return RULES_OK;
2872
- }
2873
-
2874
-
2875
- unsigned int startNonBlockingBatch(void *rulesBinding,
2876
- char **commands,
2877
- unsigned int commandCount,
2878
- unsigned int *replyCount) {
2879
- *replyCount = commandCount;
2880
- if (commandCount == 0) {
2881
- return RULES_OK;
2882
- }
2883
-
2884
- unsigned int result = RULES_OK;
2885
- binding *currentBinding = (binding*)rulesBinding;
2886
- redisContext *reContext = currentBinding->reContext;
2887
-
2888
- sds newbuf = sdsempty();
2889
- for (unsigned int i = 0; i < commandCount; ++i) {
2890
- newbuf = sdscatlen(newbuf, commands[i], strlen(commands[i]));
2891
- if (newbuf == NULL) {
2892
- return ERR_OUT_OF_MEMORY;
2893
- }
2894
-
2895
- free(commands[i]);
2896
- }
2897
-
2898
- sdsfree(reContext->obuf);
2899
- reContext->obuf = newbuf;
2900
- int wdone = 0;
2901
- do {
2902
- if (redisBufferWrite(reContext, &wdone) == REDIS_ERR) {
2903
- printf("start non blocking batch error %u %s\n", reContext->err, reContext->errstr);
2904
- return ERR_REDIS_ERROR;
2905
- }
2906
- } while (!wdone);
2907
-
2908
- return result;
2909
- }
2910
-
2911
- unsigned int completeNonBlockingBatch(void *rulesBinding,
2912
- unsigned int replyCount) {
2913
- if (replyCount == 0) {
2914
- return RULES_OK;
2915
- }
2916
-
2917
- unsigned int result = RULES_OK;
2918
- binding *currentBinding = (binding*)rulesBinding;
2919
- redisContext *reContext = currentBinding->reContext;
2920
- redisReply *reply;
2921
- for (unsigned int i = 0; i < replyCount; ++i) {
2922
- result = tryGetReply(reContext, &reply);
2923
- if (result != RULES_OK) {
2924
- return result;
2925
- } else {
2926
- if (reply->type == REDIS_REPLY_ERROR) {
2927
- printf("complete non blocking batch error %d %s\n", i, reply->str);
2928
- result = ERR_REDIS_ERROR;
2929
- } else if (reply->type == REDIS_REPLY_INTEGER) {
2930
- if (reply->integer == ERR_EVENT_OBSERVED && result == RULES_OK) {
2931
- result = ERR_EVENT_OBSERVED;
2932
- }
2933
- }
2934
-
2935
- freeReplyObject(reply);
2936
- }
2937
- }
2938
-
2939
- return result;
2940
- }
2941
-
2942
- unsigned int executeBatch(void *rulesBinding,
2943
- char **commands,
2944
- unsigned int commandCount) {
2945
- return executeBatchWithReply(rulesBinding, 0, commands, commandCount, NULL);
2946
- }
2947
-
2948
- unsigned int executeBatchWithReply(void *rulesBinding,
2949
- unsigned int expectedReplies,
2950
- char **commands,
2951
- unsigned int commandCount,
2952
- redisReply **lastReply) {
2953
- if (commandCount == 0) {
2954
- return RULES_OK;
2955
- }
2956
-
2957
- unsigned int result = RULES_OK;
2958
- unsigned int replyCount = commandCount + expectedReplies;
2959
- binding *currentBinding = (binding*)rulesBinding;
2960
- redisContext *reContext = currentBinding->reContext;
2961
- if (lastReply) {
2962
- *lastReply = NULL;
2963
- }
2964
-
2965
- sds newbuf = sdsempty();
2966
- for (unsigned int i = 0; i < commandCount; ++i) {
2967
- newbuf = sdscatlen(newbuf, commands[i], strlen(commands[i]));
2968
- if (newbuf == NULL) {
2969
- return ERR_OUT_OF_MEMORY;
2970
- }
2971
-
2972
- free(commands[i]);
2973
- }
2974
-
2975
- sdsfree(reContext->obuf);
2976
- reContext->obuf = newbuf;
2977
- redisReply *reply;
2978
- for (unsigned int i = 0; i < replyCount; ++i) {
2979
- result = tryGetReply(reContext, &reply);
2980
- if (result != RULES_OK) {
2981
- return result;
2982
- } else {
2983
- if (reply->type == REDIS_REPLY_ERROR) {
2984
- printf("%s\n", reply->str);
2985
- freeReplyObject(reply);
2986
- result = ERR_REDIS_ERROR;
2987
- } else if (reply->type == REDIS_REPLY_ARRAY) {
2988
- if (lastReply == NULL) {
2989
- freeReplyObject(reply);
2990
- } else {
2991
- if (*lastReply != NULL) {
2992
- freeReplyObject(*lastReply);
2993
- }
2994
-
2995
- *lastReply = reply;
2996
- }
2997
- } else if (reply->type == REDIS_REPLY_INTEGER) {
2998
- if (reply->integer == ERR_EVENT_OBSERVED && result == RULES_OK) {
2999
- result = ERR_EVENT_OBSERVED;
3000
- }
3001
-
3002
- freeReplyObject(reply);
3003
- } else {
3004
- freeReplyObject(reply);
3005
- }
3006
- }
3007
- }
3008
-
3009
- return result;
3010
- }
3011
-
3012
- unsigned int removeMessage(void *rulesBinding, char *sid, char *mid) {
3013
- binding *currentBinding = (binding*)rulesBinding;
3014
- redisContext *reContext = currentBinding->reContext;
3015
- int result = redisAppendCommand(reContext,
3016
- "hdel %s!%s %s",
3017
- currentBinding->factsHashset,
3018
- sid,
3019
- mid);
3020
- VERIFY(result, "removeMessage");
3021
- return RULES_OK;
3022
- }
3023
-
3024
- unsigned int peekAction(ruleset *tree, void **bindingContext, redisReply **reply) {
3025
- bindingsList *list = tree->bindingsList;
3026
- for (unsigned int i = 0; i < list->bindingsLength; ++i) {
3027
- binding *currentBinding = &list->bindings[list->lastBinding % list->bindingsLength];
3028
- ++list->lastBinding;
3029
- redisContext *reContext = currentBinding->reContext;
3030
- time_t currentTime = time(NULL);
3031
-
3032
- int result = redisAppendCommand(reContext,
3033
- "evalsha %s 0 %d %ld",
3034
- currentBinding->peekActionHash,
3035
- currentTime + 15,
3036
- currentTime);
3037
- if (result != REDIS_OK) {
3038
- continue;
3039
- }
3040
-
3041
- result = tryGetReply(reContext, reply);
3042
- if (result != RULES_OK) {
3043
- return result;
3044
- }
3045
-
3046
- if ((*reply)->type == REDIS_REPLY_ERROR) {
3047
- printf("peekAction err string %s\n", (*reply)->str);
3048
- freeReplyObject(*reply);
3049
- return ERR_REDIS_ERROR;
3050
- }
3051
-
3052
- if ((*reply)->type == REDIS_REPLY_ARRAY) {
3053
- if ((*reply)->elements < 3) {
3054
- freeReplyObject(*reply);
3055
- return ERR_REDIS_ERROR;
3056
- }
3057
-
3058
- *bindingContext = currentBinding;
3059
- return RULES_OK;
3060
- } else {
3061
- freeReplyObject(*reply);
3062
- }
3063
- }
3064
-
3065
- return ERR_NO_ACTION_AVAILABLE;
3066
- }
3067
-
3068
- unsigned int peekTimers(ruleset *tree, void **bindingContext, redisReply **reply) {
3069
- bindingsList *list = tree->bindingsList;
3070
- for (unsigned int i = 0; i < list->bindingsLength; ++i) {
3071
- binding *currentBinding = &list->bindings[list->lastTimersBinding % list->bindingsLength];
3072
- ++list->lastTimersBinding;
3073
- redisContext *reContext = currentBinding->reContext;
3074
- time_t currentTime = time(NULL);
3075
-
3076
- int result = redisAppendCommand(reContext,
3077
- "evalsha %s 0 %ld",
3078
- currentBinding->timersHash,
3079
- currentTime);
3080
- if (result != REDIS_OK) {
3081
- continue;
3082
- }
3083
-
3084
- result = tryGetReply(reContext, reply);
3085
- if (result != RULES_OK) {
3086
- return result;
3087
- }
3088
-
3089
- if ((*reply)->type == REDIS_REPLY_ERROR) {
3090
- printf("peekTimers err string %s\n", (*reply)->str);
3091
- freeReplyObject(*reply);
3092
- return ERR_REDIS_ERROR;
3093
- }
3094
-
3095
- if ((*reply)->type == REDIS_REPLY_ARRAY) {
3096
- *bindingContext = currentBinding;
3097
- return RULES_OK;
3098
- } else {
3099
- freeReplyObject(*reply);
3100
- }
3101
- }
3102
-
3103
- return ERR_NO_TIMERS_AVAILABLE;
3104
- }
3105
-
3106
- unsigned int registerTimer(void *rulesBinding, unsigned int duration, char assert, char *timer) {
3107
- binding *currentBinding = (binding*)rulesBinding;
3108
- redisContext *reContext = currentBinding->reContext;
3109
- time_t currentTime = time(NULL);
3110
-
3111
- int result = RULES_OK;
3112
- if (assert) {
3113
- result = redisAppendCommand(reContext,
3114
- "zadd %s %ld a:%s",
3115
- currentBinding->timersSortedset,
3116
- currentTime + duration,
3117
- timer);
3118
- } else {
3119
- result = redisAppendCommand(reContext,
3120
- "zadd %s %ld p:%s",
3121
- currentBinding->timersSortedset,
3122
- currentTime + duration,
3123
- timer);
3124
- }
3125
-
3126
- VERIFY(result, "registerTimer");
3127
- return RULES_OK;
3128
- }
3129
-
3130
- unsigned int removeTimer(void *rulesBinding, char *sid, char *timerName) {
3131
- binding *currentBinding = (binding*)rulesBinding;
3132
- redisContext *reContext = currentBinding->reContext;
3133
- int result = redisAppendCommand(reContext,
3134
- "evalsha %s 0 %s %s",
3135
- currentBinding->removeTimerHash,
3136
- sid,
3137
- timerName);
3138
- VERIFY(result, "removeTimer");
3139
- return RULES_OK;
3140
- }
3141
-
3142
- unsigned int registerMessage(void *rulesBinding, unsigned int queueAction, char *destination, char *message) {
3143
- binding *currentBinding = (binding*)rulesBinding;
3144
- redisContext *reContext = currentBinding->reContext;
3145
- time_t currentTime = time(NULL);
3146
-
3147
- int result = RULES_OK;
3148
-
3149
- switch (queueAction) {
3150
- case QUEUE_ASSERT_FACT:
3151
- result = redisAppendCommand(reContext,
3152
- "zadd %s!t %ld a:%s",
3153
- destination,
3154
- currentTime,
3155
- message);
3156
- break;
3157
- case QUEUE_ASSERT_EVENT:
3158
- result = redisAppendCommand(reContext,
3159
- "zadd %s!t %ld p:%s",
3160
- destination,
3161
- currentTime,
3162
- message);
3163
- break;
3164
- case QUEUE_RETRACT_FACT:
3165
- result = redisAppendCommand(reContext,
3166
- "zadd %s!t %ld r:%s",
3167
- destination,
3168
- currentTime,
3169
- message);
3170
- break;
3171
- }
3172
-
3173
- VERIFY(result, "registerMessage");
3174
- return RULES_OK;
3175
- }
3176
-
3177
- unsigned int getSession(void *rulesBinding, char *sid, char **state) {
3178
- binding *currentBinding = (binding*)rulesBinding;
3179
- redisContext *reContext = currentBinding->reContext;
3180
- unsigned int result = redisAppendCommand(reContext,
3181
- "hget %s %s",
3182
- currentBinding->sessionHashset,
3183
- sid);
3184
- redisReply *reply;
3185
- GET_REPLY(result, "getSession", reply);
3186
- if (reply->type != REDIS_REPLY_STRING) {
3187
- freeReplyObject(reply);
3188
- return ERR_NEW_SESSION;
3189
- }
3190
-
3191
- *state = malloc((strlen(reply->str) + 1) * sizeof(char));
3192
- if (!*state) {
3193
- return ERR_OUT_OF_MEMORY;
3194
- }
3195
- strcpy(*state, reply->str);
3196
- freeReplyObject(reply);
3197
- return REDIS_OK;
3198
- }
3199
-
3200
- unsigned int getSessionVersion(void *rulesBinding, char *sid, unsigned long *stateVersion) {
3201
- binding *currentBinding = (binding*)rulesBinding;
3202
- redisContext *reContext = currentBinding->reContext;
3203
- unsigned int result = redisAppendCommand(reContext,
3204
- "hget %s!v %s",
3205
- currentBinding->sessionHashset,
3206
- sid);
3207
-
3208
- redisReply *reply;
3209
- GET_REPLY(result, "getSessionVersion", reply);
3210
- if (reply->type != REDIS_REPLY_INTEGER) {
3211
- *stateVersion = 0;
3212
- } else {
3213
- *stateVersion = reply->integer;
3214
- }
3215
-
3216
- freeReplyObject(reply);
3217
- return REDIS_OK;
3218
- }
3219
-
3220
- unsigned int deleteSession(ruleset *tree, void *rulesBinding, char *sid, unsigned int sidHash) {
3221
- binding *currentBinding = (binding*)rulesBinding;
3222
- redisContext *reContext = currentBinding->reContext;
3223
-
3224
- int result = redisAppendCommand(reContext,
3225
- "evalsha %s 0 %s %u",
3226
- currentBinding->deleteSessionHash,
3227
- sid,
3228
- sidHash);
3229
- VERIFY(result, "deleteSession");
3230
-
3231
- bindingsList *list = tree->bindingsList;
3232
- binding *firstBinding = &list->bindings[0];
3233
- if (firstBinding != currentBinding) {
3234
- reContext = firstBinding->reContext;
3235
- result = redisAppendCommand(reContext,
3236
- "hdel %s %u",
3237
- firstBinding->partitionHashset,
3238
- sidHash);
3239
- VERIFY(result, "deleteSession");
3240
- }
3241
-
3242
- return REDIS_OK;
3243
- }
3244
-
3245
- unsigned int updateAction(void *rulesBinding, char *sid) {
3246
- binding *currentBinding = (binding*)rulesBinding;
3247
- redisContext *reContext = currentBinding->reContext;
3248
- time_t currentTime = time(NULL);
3249
-
3250
- int result = redisAppendCommand(reContext,
3251
- "evalsha %s 0 %s %ld",
3252
- currentBinding->updateActionHash,
3253
- sid,
3254
- currentTime + 15);
3255
- VERIFY(result, "updateAction");
3256
- return RULES_OK;
3257
- }