durable_rules 0.34.57 → 2.00.001
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/librb/durable.rb +46 -28
- data/librb/engine.rb +257 -548
- data/src/rules/Makefile +6 -7
- data/src/rules/events.c +1690 -1559
- data/src/rules/json.h +10 -6
- data/src/rules/rete.c +829 -1046
- data/src/rules/rete.h +66 -52
- data/src/rules/rules.h +67 -109
- data/src/rules/state.c +1245 -449
- data/src/rules/state.h +305 -31
- data/src/rulesrb/extconf.rb +1 -8
- data/src/rulesrb/rules.c +71 -369
- metadata +2 -36
- data/deps/hiredis/COPYING +0 -29
- data/deps/hiredis/Makefile +0 -217
- data/deps/hiredis/async.c +0 -687
- data/deps/hiredis/async.h +0 -129
- data/deps/hiredis/dict.c +0 -338
- data/deps/hiredis/dict.h +0 -126
- data/deps/hiredis/fmacros.h +0 -21
- data/deps/hiredis/hiredis.c +0 -1021
- data/deps/hiredis/hiredis.h +0 -223
- data/deps/hiredis/net.c +0 -458
- data/deps/hiredis/net.h +0 -53
- data/deps/hiredis/read.c +0 -525
- data/deps/hiredis/read.h +0 -116
- data/deps/hiredis/sds.c +0 -1095
- data/deps/hiredis/sds.h +0 -105
- data/deps/hiredis/test.c +0 -807
- data/deps/hiredis/win32.h +0 -42
- data/librb/interface.rb +0 -126
- data/src/rules/net.c +0 -3257
- data/src/rules/net.h +0 -165
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, ¤tNode->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
|
-
}
|