durable_rules 0.31.1
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 +7 -0
- data/LICENSE +20 -0
- data/Rakefile +34 -0
- data/deps/hiredis/COPYING +29 -0
- data/deps/hiredis/Makefile +148 -0
- data/deps/hiredis/async.c +622 -0
- data/deps/hiredis/async.h +125 -0
- data/deps/hiredis/dict.c +338 -0
- data/deps/hiredis/dict.h +126 -0
- data/deps/hiredis/fmacros.h +16 -0
- data/deps/hiredis/hiredis.c +1285 -0
- data/deps/hiredis/hiredis.h +210 -0
- data/deps/hiredis/net.c +299 -0
- data/deps/hiredis/net.h +47 -0
- data/deps/hiredis/sds.c +882 -0
- data/deps/hiredis/sds.h +100 -0
- data/deps/hiredis/test.c +654 -0
- data/deps/hiredis/zmalloc.h +13 -0
- data/librb/durable.rb +549 -0
- data/librb/engine.rb +1015 -0
- data/librb/interface.rb +64 -0
- data/src/rules/Makefile +55 -0
- data/src/rules/events.c +1848 -0
- data/src/rules/json.c +423 -0
- data/src/rules/json.h +24 -0
- data/src/rules/net.c +2559 -0
- data/src/rules/net.h +141 -0
- data/src/rules/rete.c +1726 -0
- data/src/rules/rete.h +133 -0
- data/src/rules/rules.h +171 -0
- data/src/rules/state.c +412 -0
- data/src/rules/state.h +57 -0
- data/src/rulesrb/extconf.rb +37 -0
- data/src/rulesrb/rules.c +644 -0
- metadata +120 -0
data/librb/interface.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require "sinatra"
|
2
|
+
require "json"
|
3
|
+
|
4
|
+
module Interface
|
5
|
+
class Application < Sinatra::Base
|
6
|
+
@@host = nil
|
7
|
+
|
8
|
+
def self.set_host(value)
|
9
|
+
@@host = value
|
10
|
+
end
|
11
|
+
|
12
|
+
get "/:ruleset_name/:sid" do
|
13
|
+
begin
|
14
|
+
JSON.generate @@host.get_state(params["ruleset_name"], params["sid"])
|
15
|
+
rescue Exception => e
|
16
|
+
status 404
|
17
|
+
e.to_s
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
post "/:ruleset_name/:sid" do
|
22
|
+
begin
|
23
|
+
request.body.rewind
|
24
|
+
message = JSON.parse request.body.read
|
25
|
+
message["sid"] = params["sid"]
|
26
|
+
@@host.post params["ruleset_name"], message
|
27
|
+
rescue Exception => e
|
28
|
+
status 500
|
29
|
+
e.to_s
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
patch "/:ruleset_name/:sid" do
|
34
|
+
begin
|
35
|
+
request.body.rewind
|
36
|
+
state = JSON.parse request.body.read
|
37
|
+
state["id"] = params["sid"]
|
38
|
+
@@host.patch_state params["ruleset_name"], state
|
39
|
+
rescue Exception => e
|
40
|
+
status 500
|
41
|
+
e.to_s
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
get "/:ruleset_name" do
|
46
|
+
begin
|
47
|
+
@@host.get_ruleset(params["ruleset_name"]).to_json
|
48
|
+
rescue Exception => e
|
49
|
+
status 404
|
50
|
+
e.to_s
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
post "/:ruleset_name" do
|
55
|
+
begin
|
56
|
+
request.body.rewind
|
57
|
+
@@host.set_ruleset params["ruleset_name"], JSON.parse(request.body.read)
|
58
|
+
rescue Exception => e
|
59
|
+
status 500
|
60
|
+
e.to_s
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/src/rules/Makefile
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
OBJ=events.o json.o net.o rete.o state.o
|
2
|
+
LIBNAME=rules
|
3
|
+
|
4
|
+
# Fallback to gcc when $CC is not in $PATH.
|
5
|
+
CC:=$(shell sh -c 'type $(CC) >/dev/null 2>/dev/null && echo $(CC) || echo gcc')
|
6
|
+
OPTIMIZATION?=-O3
|
7
|
+
WARNINGS=-Wall
|
8
|
+
DEBUG?= -g -ggdb
|
9
|
+
REAL_CFLAGS=$(OPTIMIZATION) -fPIC $(CFLAGS) $(WARNINGS) $(DEBUG) $(ARCH)
|
10
|
+
REAL_LDFLAGS=$(LDFLAGS) $(ARCH)
|
11
|
+
|
12
|
+
REAL_CFLAGS+= -I../../deps/hiredis
|
13
|
+
REAL_LDFLAGS+= ../deps/hiredis/libhiredis.a
|
14
|
+
|
15
|
+
STLIBSUFFIX=a
|
16
|
+
STLIBNAME=$(LIBNAME).$(STLIBSUFFIX)
|
17
|
+
STLIB_MAKE_CMD=ar rcs $(STLIBNAME)
|
18
|
+
|
19
|
+
# Platform-specific overrides
|
20
|
+
uname_S := $(shell sh -c 'uname -s 2>/dev/null || echo not')
|
21
|
+
ifeq ($(uname_S),SunOS)
|
22
|
+
REAL_LDFLAGS+= -ldl -lnsl -lsocket
|
23
|
+
INSTALL= cp -r
|
24
|
+
endif
|
25
|
+
|
26
|
+
all: $(STLIBNAME)
|
27
|
+
|
28
|
+
# Deps (use make dep to generate this)
|
29
|
+
events.o: events.c rules.h net.h json.h
|
30
|
+
json.o: json.c json.h rules.h
|
31
|
+
net.o: net.c net.h rules.h json.h rete.h
|
32
|
+
rete.o: rete.c rete.h net.h json.h state.h
|
33
|
+
state.o: state.c state.h json.h net.h
|
34
|
+
|
35
|
+
$(STLIBNAME): $(OBJ)
|
36
|
+
$(STLIB_MAKE_CMD) $(OBJ)
|
37
|
+
|
38
|
+
static: $(STLIBNAME)
|
39
|
+
|
40
|
+
rules-%: %.o $(STLIBNAME)
|
41
|
+
$(CC) -o $@ $(REAL_LDFLAGS) $< $(STLIBNAME)
|
42
|
+
|
43
|
+
.c.o:
|
44
|
+
$(CC) -std=c99 -c $(REAL_CFLAGS) $<
|
45
|
+
|
46
|
+
clean:
|
47
|
+
rm -rf $(STLIBNAME) $(BINS) *.o *.gcda *.gcno *.gcov
|
48
|
+
|
49
|
+
gprof:
|
50
|
+
$(MAKE) CFLAGS="-pg" LDFLAGS="-pg"
|
51
|
+
|
52
|
+
noopt:
|
53
|
+
$(MAKE) OPTIMIZATION=""
|
54
|
+
|
55
|
+
.PHONY: all clean gprof gcov noopt
|
data/src/rules/events.c
ADDED
@@ -0,0 +1,1848 @@
|
|
1
|
+
|
2
|
+
#include <stdio.h>
|
3
|
+
#include <stdlib.h>
|
4
|
+
#include <string.h>
|
5
|
+
#include "rules.h"
|
6
|
+
#include "net.h"
|
7
|
+
#include "json.h"
|
8
|
+
|
9
|
+
#define MAX_EVENT_PROPERTIES 64
|
10
|
+
#define MAX_RESULT_NODES 32
|
11
|
+
#define MAX_NODE_RESULTS 16
|
12
|
+
#define MAX_STACK_SIZE 64
|
13
|
+
#define MAX_STATE_PROPERTY_TIME 2
|
14
|
+
#define MAX_COMMAND_COUNT 5000
|
15
|
+
#define MAX_ADD_COUNT 1000
|
16
|
+
#define MAX_EVAL_COUNT 1000
|
17
|
+
|
18
|
+
#define OP_BOOL_BOOL 0x0404
|
19
|
+
#define OP_BOOL_INT 0x0402
|
20
|
+
#define OP_BOOL_DOUBLE 0x0403
|
21
|
+
#define OP_BOOL_STRING 0x0401
|
22
|
+
#define OP_INT_BOOL 0x0204
|
23
|
+
#define OP_INT_INT 0x0202
|
24
|
+
#define OP_INT_DOUBLE 0x0203
|
25
|
+
#define OP_INT_STRING 0x0201
|
26
|
+
#define OP_DOUBLE_BOOL 0x0304
|
27
|
+
#define OP_DOUBLE_INT 0x0302
|
28
|
+
#define OP_DOUBLE_DOUBLE 0x0303
|
29
|
+
#define OP_DOUBLE_STRING 0x0301
|
30
|
+
#define OP_STRING_BOOL 0x0104
|
31
|
+
#define OP_STRING_INT 0x0102
|
32
|
+
#define OP_STRING_DOUBLE 0x0103
|
33
|
+
#define OP_STRING_STRING 0x0101
|
34
|
+
|
35
|
+
typedef struct actionContext {
|
36
|
+
void *rulesBinding;
|
37
|
+
redisReply *reply;
|
38
|
+
} actionContext;
|
39
|
+
|
40
|
+
typedef struct jsonResult {
|
41
|
+
unsigned int hash;
|
42
|
+
char *firstName;
|
43
|
+
char *lastName;
|
44
|
+
char *messages[MAX_MESSAGE_BATCH];
|
45
|
+
unsigned short messagesLength;
|
46
|
+
unsigned char childrenCount;
|
47
|
+
unsigned char children[MAX_NODE_RESULTS];
|
48
|
+
} jsonResult;
|
49
|
+
|
50
|
+
static unsigned int handleMessage(ruleset *tree,
|
51
|
+
char *state,
|
52
|
+
char *message,
|
53
|
+
unsigned char actionType,
|
54
|
+
char **commands,
|
55
|
+
unsigned int *commandCount,
|
56
|
+
void **rulesBinding);
|
57
|
+
|
58
|
+
static unsigned int reduceStateIdiom(ruleset *tree,
|
59
|
+
char *sid,
|
60
|
+
unsigned int idiomOffset,
|
61
|
+
char **state,
|
62
|
+
unsigned char *releaseState,
|
63
|
+
jsonProperty **targetValue);
|
64
|
+
|
65
|
+
static unsigned char compareBool(unsigned char left,
|
66
|
+
unsigned char right,
|
67
|
+
unsigned char op) {
|
68
|
+
switch(op) {
|
69
|
+
case OP_LT:
|
70
|
+
return (left < right);
|
71
|
+
case OP_LTE:
|
72
|
+
return 1;
|
73
|
+
case OP_GT:
|
74
|
+
return (left > right);
|
75
|
+
case OP_GTE:
|
76
|
+
return 1;
|
77
|
+
case OP_EQ:
|
78
|
+
return (left == right);
|
79
|
+
case OP_NEQ:
|
80
|
+
return (left != right);
|
81
|
+
}
|
82
|
+
|
83
|
+
return 0;
|
84
|
+
}
|
85
|
+
|
86
|
+
static unsigned char compareInt(long left,
|
87
|
+
long right,
|
88
|
+
unsigned char op) {
|
89
|
+
switch(op) {
|
90
|
+
case OP_LT:
|
91
|
+
return (left < right);
|
92
|
+
case OP_LTE:
|
93
|
+
return (left <= right);
|
94
|
+
case OP_GT:
|
95
|
+
return (left > right);
|
96
|
+
case OP_GTE:
|
97
|
+
return (left >= right);
|
98
|
+
case OP_EQ:
|
99
|
+
return (left == right);
|
100
|
+
case OP_NEQ:
|
101
|
+
return (left != right);
|
102
|
+
}
|
103
|
+
|
104
|
+
return 0;
|
105
|
+
}
|
106
|
+
|
107
|
+
static unsigned char compareDouble(double left,
|
108
|
+
double right,
|
109
|
+
unsigned char op) {
|
110
|
+
switch(op) {
|
111
|
+
case OP_LT:
|
112
|
+
return (left < right);
|
113
|
+
case OP_LTE:
|
114
|
+
return (left <= right);
|
115
|
+
case OP_GT:
|
116
|
+
return (left > right);
|
117
|
+
case OP_GTE:
|
118
|
+
return (left >= right);
|
119
|
+
case OP_EQ:
|
120
|
+
return (left == right);
|
121
|
+
case OP_NEQ:
|
122
|
+
return (left != right);
|
123
|
+
}
|
124
|
+
|
125
|
+
return 0;
|
126
|
+
}
|
127
|
+
|
128
|
+
static unsigned char compareString(char *leftFirst,
|
129
|
+
unsigned short leftLength,
|
130
|
+
char *right,
|
131
|
+
unsigned char op) {
|
132
|
+
char temp = leftFirst[leftLength];
|
133
|
+
leftFirst[leftLength] = '\0';
|
134
|
+
int result = strcmp(leftFirst, right);
|
135
|
+
leftFirst[leftLength] = temp;
|
136
|
+
switch(op) {
|
137
|
+
case OP_LT:
|
138
|
+
return (result < 0);
|
139
|
+
case OP_LTE:
|
140
|
+
return (result <= 0);
|
141
|
+
case OP_GT:
|
142
|
+
return (result > 0);
|
143
|
+
case OP_GTE:
|
144
|
+
return (result >= 0);
|
145
|
+
case OP_EQ:
|
146
|
+
return (result == 0);
|
147
|
+
case OP_NEQ:
|
148
|
+
return (result != 0);
|
149
|
+
}
|
150
|
+
|
151
|
+
return 0;
|
152
|
+
}
|
153
|
+
|
154
|
+
static unsigned char compareStringProperty(char *left,
|
155
|
+
char *rightFirst,
|
156
|
+
unsigned short rightLength,
|
157
|
+
unsigned char op) {
|
158
|
+
char temp = rightFirst[rightLength];
|
159
|
+
rightFirst[rightLength] = '\0';
|
160
|
+
int result = strcmp(left, rightFirst);
|
161
|
+
rightFirst[rightLength] = temp;
|
162
|
+
switch(op) {
|
163
|
+
case OP_LT:
|
164
|
+
return (result < 0);
|
165
|
+
case OP_LTE:
|
166
|
+
return (result <= 0);
|
167
|
+
case OP_GT:
|
168
|
+
return (result > 0);
|
169
|
+
case OP_GTE:
|
170
|
+
return (result >= 0);
|
171
|
+
case OP_EQ:
|
172
|
+
return (result == 0);
|
173
|
+
case OP_NEQ:
|
174
|
+
return (result != 0);
|
175
|
+
}
|
176
|
+
|
177
|
+
return 0;
|
178
|
+
}
|
179
|
+
|
180
|
+
static unsigned char compareStringAndStringProperty(char *leftFirst,
|
181
|
+
unsigned short leftLength,
|
182
|
+
char *rightFirst,
|
183
|
+
unsigned short rightLength,
|
184
|
+
unsigned char op) {
|
185
|
+
|
186
|
+
char rightTemp = rightFirst[rightLength];
|
187
|
+
rightFirst[rightLength] = '\0';
|
188
|
+
char leftTemp = leftFirst[leftLength];
|
189
|
+
leftFirst[leftLength] = '\0';
|
190
|
+
int result = strcmp(leftFirst, rightFirst);
|
191
|
+
rightFirst[rightLength] = rightTemp;
|
192
|
+
leftFirst[leftLength] = leftTemp;
|
193
|
+
|
194
|
+
switch(op) {
|
195
|
+
case OP_LT:
|
196
|
+
return (result < 0);
|
197
|
+
case OP_LTE:
|
198
|
+
return (result <= 0);
|
199
|
+
case OP_GT:
|
200
|
+
return (result > 0);
|
201
|
+
case OP_GTE:
|
202
|
+
return (result >= 0);
|
203
|
+
case OP_EQ:
|
204
|
+
return (result == 0);
|
205
|
+
case OP_NEQ:
|
206
|
+
return (result != 0);
|
207
|
+
}
|
208
|
+
|
209
|
+
return 0;
|
210
|
+
|
211
|
+
}
|
212
|
+
|
213
|
+
static long reduceInt(long left,
|
214
|
+
long right,
|
215
|
+
unsigned char op) {
|
216
|
+
switch(op) {
|
217
|
+
case OP_ADD:
|
218
|
+
return left + right;
|
219
|
+
case OP_SUB:
|
220
|
+
return left - right;
|
221
|
+
case OP_MUL:
|
222
|
+
return left * right;
|
223
|
+
case OP_DIV:
|
224
|
+
return left / right;
|
225
|
+
}
|
226
|
+
|
227
|
+
return 0;
|
228
|
+
}
|
229
|
+
|
230
|
+
static double reduceDouble(double left,
|
231
|
+
double right,
|
232
|
+
unsigned char op) {
|
233
|
+
switch(op) {
|
234
|
+
case OP_ADD:
|
235
|
+
return left + right;
|
236
|
+
case OP_SUB:
|
237
|
+
return left - right;
|
238
|
+
case OP_MUL:
|
239
|
+
return left * right;
|
240
|
+
case OP_DIV:
|
241
|
+
return left / right;
|
242
|
+
}
|
243
|
+
|
244
|
+
return 0;
|
245
|
+
}
|
246
|
+
|
247
|
+
static void freeCommands(char **commands,
|
248
|
+
unsigned int commandCount) {
|
249
|
+
for (unsigned int i = 0; i < commandCount; ++i) {
|
250
|
+
free(commands[i]);
|
251
|
+
}
|
252
|
+
}
|
253
|
+
|
254
|
+
static unsigned int handleAction(ruleset *tree,
|
255
|
+
char *sid,
|
256
|
+
char *mid,
|
257
|
+
char *prefix,
|
258
|
+
node *node,
|
259
|
+
unsigned char actionType,
|
260
|
+
char **evalKeys,
|
261
|
+
unsigned short *evalPriorities,
|
262
|
+
unsigned int *evalCount,
|
263
|
+
char **addKeys,
|
264
|
+
unsigned int *addCount,
|
265
|
+
char **removeCommand,
|
266
|
+
void **rulesBinding) {
|
267
|
+
unsigned int result = ERR_UNEXPECTED_VALUE;
|
268
|
+
if (*rulesBinding == NULL) {
|
269
|
+
result = resolveBinding(tree,
|
270
|
+
sid,
|
271
|
+
rulesBinding);
|
272
|
+
if (result != RULES_OK) {
|
273
|
+
return result;
|
274
|
+
}
|
275
|
+
}
|
276
|
+
|
277
|
+
switch (actionType) {
|
278
|
+
case ACTION_ASSERT_EVENT:
|
279
|
+
case ACTION_ASSERT_FACT:
|
280
|
+
case ACTION_RETRACT_EVENT:
|
281
|
+
case ACTION_RETRACT_FACT:
|
282
|
+
if (*evalCount == MAX_EVAL_COUNT) {
|
283
|
+
return ERR_MAX_EVAL_COUNT;
|
284
|
+
}
|
285
|
+
|
286
|
+
char *evalKey = malloc((strlen(prefix) + 1) * sizeof(char));
|
287
|
+
if (evalKey == NULL) {
|
288
|
+
return ERR_OUT_OF_MEMORY;
|
289
|
+
}
|
290
|
+
|
291
|
+
strcpy(evalKey, prefix);
|
292
|
+
unsigned int index = *evalCount;
|
293
|
+
while (index > 0 && node->value.c.priority < evalPriorities[index - 1]) {
|
294
|
+
evalKeys[index] = evalKeys[index - 1];
|
295
|
+
evalPriorities[index] = evalPriorities[index - 1];
|
296
|
+
--index;
|
297
|
+
}
|
298
|
+
|
299
|
+
evalKeys[index] = evalKey;
|
300
|
+
evalPriorities[index] = node->value.c.priority;
|
301
|
+
++*evalCount;
|
302
|
+
break;
|
303
|
+
|
304
|
+
case ACTION_ADD_EVENT:
|
305
|
+
case ACTION_ADD_FACT:
|
306
|
+
if (*addCount == MAX_ADD_COUNT) {
|
307
|
+
return ERR_MAX_ADD_COUNT;
|
308
|
+
}
|
309
|
+
char *addKey = malloc((strlen(prefix) + 1) * sizeof(char));
|
310
|
+
if (addKey == NULL) {
|
311
|
+
return ERR_OUT_OF_MEMORY;
|
312
|
+
}
|
313
|
+
|
314
|
+
strcpy(addKey, prefix);
|
315
|
+
addKeys[*addCount] = addKey;
|
316
|
+
*addCount = *addCount + 1;
|
317
|
+
break;
|
318
|
+
|
319
|
+
case ACTION_REMOVE_EVENT:
|
320
|
+
case ACTION_REMOVE_FACT:
|
321
|
+
if (*removeCommand == NULL) {
|
322
|
+
result = formatRemoveMessage(*rulesBinding,
|
323
|
+
sid,
|
324
|
+
mid,
|
325
|
+
actionType == ACTION_REMOVE_FACT ? 1 : 0,
|
326
|
+
removeCommand);
|
327
|
+
|
328
|
+
if (result != RULES_OK) {
|
329
|
+
return result;
|
330
|
+
}
|
331
|
+
}
|
332
|
+
break;
|
333
|
+
}
|
334
|
+
return RULES_OK;
|
335
|
+
}
|
336
|
+
|
337
|
+
static unsigned int handleBeta(ruleset *tree,
|
338
|
+
char *sid,
|
339
|
+
char *mid,
|
340
|
+
node *betaNode,
|
341
|
+
unsigned short actionType,
|
342
|
+
char **evalKeys,
|
343
|
+
unsigned short *evalPriorities,
|
344
|
+
unsigned int *evalCount,
|
345
|
+
char **addKeys,
|
346
|
+
unsigned int *addCount,
|
347
|
+
char **removeCommand,
|
348
|
+
void **rulesBinding) {
|
349
|
+
int prefixLength = 0;
|
350
|
+
node *currentNode = betaNode;
|
351
|
+
while (currentNode != NULL) {
|
352
|
+
int nameLength = strlen(&tree->stringPool[currentNode->nameOffset]);
|
353
|
+
prefixLength += nameLength + 1;
|
354
|
+
|
355
|
+
if (currentNode->type == NODE_ACTION) {
|
356
|
+
currentNode = NULL;
|
357
|
+
} else {
|
358
|
+
if (currentNode->value.b.not) {
|
359
|
+
switch (actionType) {
|
360
|
+
case ACTION_ASSERT_FACT:
|
361
|
+
actionType = ACTION_ADD_FACT;
|
362
|
+
break;
|
363
|
+
case ACTION_ASSERT_EVENT:
|
364
|
+
actionType = ACTION_ADD_EVENT;
|
365
|
+
break;
|
366
|
+
case ACTION_REMOVE_FACT:
|
367
|
+
actionType = ACTION_RETRACT_FACT;
|
368
|
+
break;
|
369
|
+
case ACTION_REMOVE_EVENT:
|
370
|
+
actionType = ACTION_RETRACT_EVENT;
|
371
|
+
break;
|
372
|
+
}
|
373
|
+
}
|
374
|
+
currentNode = &tree->nodePool[currentNode->value.b.nextOffset];
|
375
|
+
}
|
376
|
+
}
|
377
|
+
|
378
|
+
node *actionNode = NULL;
|
379
|
+
#ifdef _WIN32
|
380
|
+
char *prefix = (char *)_alloca(sizeof(char)*(prefixLength));
|
381
|
+
#else
|
382
|
+
char prefix[prefixLength];
|
383
|
+
#endif
|
384
|
+
char *currentPrefix = prefix;
|
385
|
+
currentNode = betaNode;
|
386
|
+
while (currentNode != NULL) {
|
387
|
+
char *name = &tree->stringPool[currentNode->nameOffset];
|
388
|
+
int nameLength = strlen(&tree->stringPool[currentNode->nameOffset]);
|
389
|
+
strncpy(currentPrefix, name, nameLength);
|
390
|
+
|
391
|
+
if (currentNode->type == NODE_ACTION) {
|
392
|
+
currentPrefix[nameLength] = '\0';
|
393
|
+
actionNode = currentNode;
|
394
|
+
currentNode = NULL;
|
395
|
+
}
|
396
|
+
else {
|
397
|
+
currentPrefix[nameLength] = '!';
|
398
|
+
currentPrefix = ¤tPrefix[nameLength + 1];
|
399
|
+
currentNode = &tree->nodePool[currentNode->value.b.nextOffset];
|
400
|
+
}
|
401
|
+
}
|
402
|
+
return handleAction(tree,
|
403
|
+
sid,
|
404
|
+
mid,
|
405
|
+
prefix,
|
406
|
+
actionNode,
|
407
|
+
actionType,
|
408
|
+
evalKeys,
|
409
|
+
evalPriorities,
|
410
|
+
evalCount,
|
411
|
+
addKeys,
|
412
|
+
addCount,
|
413
|
+
removeCommand,
|
414
|
+
rulesBinding);
|
415
|
+
}
|
416
|
+
|
417
|
+
|
418
|
+
static unsigned int valueToProperty(ruleset *tree,
|
419
|
+
char *sid,
|
420
|
+
jsonValue *sourceValue,
|
421
|
+
char **state,
|
422
|
+
unsigned char *releaseState,
|
423
|
+
jsonProperty **targetProperty) {
|
424
|
+
|
425
|
+
unsigned int result = RULES_OK;
|
426
|
+
*releaseState = 0;
|
427
|
+
switch(sourceValue->type) {
|
428
|
+
case JSON_STATE_IDIOM:
|
429
|
+
result = reduceStateIdiom(tree,
|
430
|
+
sid,
|
431
|
+
sourceValue->value.idiomOffset,
|
432
|
+
state,
|
433
|
+
releaseState,
|
434
|
+
targetProperty);
|
435
|
+
|
436
|
+
return result;
|
437
|
+
case JSON_STATE_PROPERTY:
|
438
|
+
if (sourceValue->value.property.idOffset) {
|
439
|
+
sid = &tree->stringPool[sourceValue->value.property.idOffset];
|
440
|
+
}
|
441
|
+
result = fetchStateProperty(tree,
|
442
|
+
sid,
|
443
|
+
sourceValue->value.property.hash,
|
444
|
+
MAX_STATE_PROPERTY_TIME,
|
445
|
+
0,
|
446
|
+
state,
|
447
|
+
targetProperty);
|
448
|
+
|
449
|
+
if (result == ERR_STATE_NOT_LOADED || result == ERR_STALE_STATE) {
|
450
|
+
result = refreshState(tree,sid);
|
451
|
+
if (result != RULES_OK) {
|
452
|
+
return result;
|
453
|
+
}
|
454
|
+
|
455
|
+
result = fetchStateProperty(tree,
|
456
|
+
sid,
|
457
|
+
sourceValue->value.property.hash,
|
458
|
+
MAX_STATE_PROPERTY_TIME,
|
459
|
+
0,
|
460
|
+
state,
|
461
|
+
targetProperty);
|
462
|
+
}
|
463
|
+
|
464
|
+
return result;
|
465
|
+
case JSON_STRING:
|
466
|
+
*state = &tree->stringPool[sourceValue->value.stringOffset];
|
467
|
+
(*targetProperty)->valueLength = strlen(*state);
|
468
|
+
(*targetProperty)->valueOffset = 0;
|
469
|
+
break;
|
470
|
+
case JSON_INT:
|
471
|
+
(*targetProperty)->value.i = sourceValue->value.i;
|
472
|
+
break;
|
473
|
+
case JSON_DOUBLE:
|
474
|
+
(*targetProperty)->value.d = sourceValue->value.d;
|
475
|
+
break;
|
476
|
+
case JSON_BOOL:
|
477
|
+
(*targetProperty)->value.b = sourceValue->value.b;
|
478
|
+
break;
|
479
|
+
}
|
480
|
+
|
481
|
+
(*targetProperty)->isMaterial = 1;
|
482
|
+
(*targetProperty)->type = sourceValue->type;
|
483
|
+
return result;
|
484
|
+
}
|
485
|
+
|
486
|
+
static unsigned int reduceProperties(unsigned char operator,
|
487
|
+
jsonProperty *leftProperty,
|
488
|
+
char *leftState,
|
489
|
+
jsonProperty *rightProperty,
|
490
|
+
char *rightState,
|
491
|
+
jsonProperty *targetValue,
|
492
|
+
char **state) {
|
493
|
+
*state = NULL;
|
494
|
+
unsigned short type = leftProperty->type << 8;
|
495
|
+
type = type + rightProperty->type;
|
496
|
+
char leftTemp = 0;
|
497
|
+
char rightTemp = 0;
|
498
|
+
if (leftProperty->type == JSON_STRING || rightProperty->type == JSON_STRING) {
|
499
|
+
if (operator != OP_ADD) {
|
500
|
+
asprintf(state, "");
|
501
|
+
return RULES_OK;
|
502
|
+
}
|
503
|
+
|
504
|
+
if (leftProperty->type == JSON_STRING) {
|
505
|
+
leftTemp = leftState[leftProperty->valueOffset + leftProperty->valueLength];
|
506
|
+
leftState[leftProperty->valueOffset + leftProperty->valueLength] = '\0';
|
507
|
+
}
|
508
|
+
|
509
|
+
if (rightProperty->type == JSON_STRING) {
|
510
|
+
rightTemp = rightState[rightProperty->valueOffset + rightProperty->valueLength];
|
511
|
+
rightState[rightProperty->valueOffset + rightProperty->valueLength] = '\0';
|
512
|
+
}
|
513
|
+
}
|
514
|
+
|
515
|
+
switch(type) {
|
516
|
+
case OP_BOOL_BOOL:
|
517
|
+
targetValue->value.i = reduceInt(leftProperty->value.b, rightProperty->value.b, operator);
|
518
|
+
targetValue->type = JSON_INT;
|
519
|
+
break;
|
520
|
+
case OP_BOOL_INT:
|
521
|
+
targetValue->value.i = reduceInt(leftProperty->value.b, rightProperty->value.i, operator);
|
522
|
+
targetValue->type = JSON_INT;
|
523
|
+
break;
|
524
|
+
case OP_BOOL_DOUBLE:
|
525
|
+
targetValue->value.d = reduceDouble(leftProperty->value.b, rightProperty->value.d, operator);
|
526
|
+
targetValue->type = JSON_DOUBLE;
|
527
|
+
break;
|
528
|
+
case OP_BOOL_STRING:
|
529
|
+
if (asprintf(state,
|
530
|
+
"%s%s",
|
531
|
+
leftProperty->value.b ? "true" : "false",
|
532
|
+
rightState + rightProperty->valueOffset) == -1) {
|
533
|
+
return ERR_OUT_OF_MEMORY;
|
534
|
+
}
|
535
|
+
break;
|
536
|
+
case OP_INT_BOOL:
|
537
|
+
targetValue->value.i = reduceInt(leftProperty->value.i, rightProperty->value.b, operator);
|
538
|
+
targetValue->type = JSON_INT;
|
539
|
+
break;
|
540
|
+
case OP_INT_INT:
|
541
|
+
targetValue->value.i = reduceInt(leftProperty->value.i, rightProperty->value.i, operator);
|
542
|
+
targetValue->type = JSON_INT;
|
543
|
+
break;
|
544
|
+
case OP_INT_DOUBLE:
|
545
|
+
targetValue->value.d = reduceDouble(leftProperty->value.i, rightProperty->value.d, operator);
|
546
|
+
targetValue->type = JSON_DOUBLE;
|
547
|
+
break;
|
548
|
+
case OP_INT_STRING:
|
549
|
+
if (asprintf(state,
|
550
|
+
"%ld%s",
|
551
|
+
leftProperty->value.i,
|
552
|
+
rightState + rightProperty->valueOffset) == -1) {
|
553
|
+
return ERR_OUT_OF_MEMORY;
|
554
|
+
}
|
555
|
+
break;
|
556
|
+
case OP_DOUBLE_BOOL:
|
557
|
+
targetValue->value.d = reduceDouble(leftProperty->value.d, rightProperty->value.b, operator);
|
558
|
+
targetValue->type = JSON_DOUBLE;
|
559
|
+
break;
|
560
|
+
case OP_DOUBLE_INT:
|
561
|
+
targetValue->value.d = reduceDouble(leftProperty->value.d, rightProperty->value.i, operator);
|
562
|
+
targetValue->type = JSON_DOUBLE;
|
563
|
+
break;
|
564
|
+
case OP_DOUBLE_DOUBLE:
|
565
|
+
targetValue->value.d = reduceDouble(leftProperty->value.d, rightProperty->value.d, operator);
|
566
|
+
targetValue->type = JSON_DOUBLE;
|
567
|
+
break;
|
568
|
+
case OP_DOUBLE_STRING:
|
569
|
+
if (asprintf(state,
|
570
|
+
"%g%s",
|
571
|
+
leftProperty->value.d,
|
572
|
+
rightState + rightProperty->valueOffset) == -1) {
|
573
|
+
return ERR_OUT_OF_MEMORY;
|
574
|
+
}
|
575
|
+
|
576
|
+
break;
|
577
|
+
case OP_STRING_BOOL:
|
578
|
+
if (asprintf(state,
|
579
|
+
"%s%s",
|
580
|
+
leftState + leftProperty->valueOffset,
|
581
|
+
rightProperty->value.b ? "true" : "false") == -1) {
|
582
|
+
return ERR_OUT_OF_MEMORY;
|
583
|
+
}
|
584
|
+
break;
|
585
|
+
case OP_STRING_INT:
|
586
|
+
if (asprintf(state,
|
587
|
+
"%s%ld",
|
588
|
+
leftState + leftProperty->valueOffset,
|
589
|
+
rightProperty->value.i) == -1) {
|
590
|
+
return ERR_OUT_OF_MEMORY;
|
591
|
+
}
|
592
|
+
break;
|
593
|
+
case OP_STRING_DOUBLE:
|
594
|
+
if (asprintf(state,
|
595
|
+
"%s%ld",
|
596
|
+
leftState + leftProperty->valueOffset,
|
597
|
+
rightProperty->value.i) == -1) {
|
598
|
+
return ERR_OUT_OF_MEMORY;
|
599
|
+
}
|
600
|
+
break;
|
601
|
+
case OP_STRING_STRING:
|
602
|
+
if (asprintf(state,
|
603
|
+
"%s%s",
|
604
|
+
leftState + leftProperty->valueOffset,
|
605
|
+
rightState + rightProperty->valueOffset) == -1) {
|
606
|
+
return ERR_OUT_OF_MEMORY;
|
607
|
+
}
|
608
|
+
break;
|
609
|
+
}
|
610
|
+
|
611
|
+
if (leftProperty->type == JSON_STRING || rightProperty->type == JSON_STRING) {
|
612
|
+
targetValue->type = JSON_STRING;
|
613
|
+
targetValue->valueOffset = 0;
|
614
|
+
targetValue->valueLength = strlen(*state);
|
615
|
+
|
616
|
+
if (leftTemp) {
|
617
|
+
leftState[leftProperty->valueOffset + leftProperty->valueLength] = leftTemp;
|
618
|
+
}
|
619
|
+
|
620
|
+
if (rightTemp) {
|
621
|
+
rightState[rightProperty->valueOffset + rightProperty->valueLength] = rightTemp;
|
622
|
+
}
|
623
|
+
}
|
624
|
+
|
625
|
+
return RULES_OK;
|
626
|
+
}
|
627
|
+
|
628
|
+
static unsigned int reduceStateIdiom(ruleset *tree,
|
629
|
+
char *sid,
|
630
|
+
unsigned int idiomOffset,
|
631
|
+
char **state,
|
632
|
+
unsigned char *releaseState,
|
633
|
+
jsonProperty **targetValue) {
|
634
|
+
unsigned int result = RULES_OK;
|
635
|
+
*releaseState = 0;
|
636
|
+
idiom *currentIdiom = &tree->idiomPool[idiomOffset];
|
637
|
+
jsonProperty leftValue;
|
638
|
+
jsonProperty *leftProperty = &leftValue;
|
639
|
+
unsigned char releaseLeftState = 0;
|
640
|
+
char *leftState = NULL;
|
641
|
+
result = valueToProperty(tree,
|
642
|
+
sid,
|
643
|
+
¤tIdiom->left,
|
644
|
+
&leftState,
|
645
|
+
&releaseLeftState,
|
646
|
+
&leftProperty);
|
647
|
+
if (result != RULES_OK) {
|
648
|
+
return result;
|
649
|
+
}
|
650
|
+
|
651
|
+
jsonProperty rightValue;
|
652
|
+
jsonProperty *rightProperty = &rightValue;
|
653
|
+
unsigned char releaseRightState = 0;
|
654
|
+
char *rightState = NULL;
|
655
|
+
result = valueToProperty(tree,
|
656
|
+
sid,
|
657
|
+
¤tIdiom->right,
|
658
|
+
&rightState,
|
659
|
+
&releaseRightState,
|
660
|
+
&rightProperty);
|
661
|
+
if (result != RULES_OK) {
|
662
|
+
if (releaseLeftState) {
|
663
|
+
free(leftState);
|
664
|
+
}
|
665
|
+
|
666
|
+
return result;
|
667
|
+
}
|
668
|
+
|
669
|
+
result = reduceProperties(currentIdiom->operator,
|
670
|
+
leftProperty,
|
671
|
+
leftState,
|
672
|
+
rightProperty,
|
673
|
+
rightState,
|
674
|
+
*targetValue,
|
675
|
+
state);
|
676
|
+
|
677
|
+
if (releaseLeftState) {
|
678
|
+
free(leftState);
|
679
|
+
}
|
680
|
+
|
681
|
+
if (releaseRightState) {
|
682
|
+
free(rightState);
|
683
|
+
}
|
684
|
+
|
685
|
+
if (state) {
|
686
|
+
*releaseState = 1;
|
687
|
+
}
|
688
|
+
|
689
|
+
return result;
|
690
|
+
}
|
691
|
+
|
692
|
+
static unsigned int isMatch(ruleset *tree,
|
693
|
+
char *sid,
|
694
|
+
char *message,
|
695
|
+
jsonProperty *currentProperty,
|
696
|
+
alpha *currentAlpha,
|
697
|
+
unsigned char *propertyMatch,
|
698
|
+
void **rulesBinding) {
|
699
|
+
unsigned char alphaOp = currentAlpha->operator;
|
700
|
+
unsigned char propertyType = currentProperty->type;
|
701
|
+
unsigned int result = RULES_OK;
|
702
|
+
|
703
|
+
*propertyMatch = 0;
|
704
|
+
if (alphaOp == OP_EX) {
|
705
|
+
*propertyMatch = 1;
|
706
|
+
return RULES_OK;
|
707
|
+
}
|
708
|
+
|
709
|
+
rehydrateProperty(currentProperty, message);
|
710
|
+
jsonProperty rightValue;
|
711
|
+
jsonProperty *rightProperty = &rightValue;
|
712
|
+
unsigned char releaseRightState = 0;
|
713
|
+
char *rightState = NULL;
|
714
|
+
result = valueToProperty(tree,
|
715
|
+
sid,
|
716
|
+
¤tAlpha->right,
|
717
|
+
&rightState,
|
718
|
+
&releaseRightState,
|
719
|
+
&rightProperty);
|
720
|
+
if (result != RULES_OK) {
|
721
|
+
if (releaseRightState) {
|
722
|
+
free(rightState);
|
723
|
+
}
|
724
|
+
|
725
|
+
if (result != ERR_NEW_SESSION && result != ERR_PROPERTY_NOT_FOUND) {
|
726
|
+
return result;
|
727
|
+
}
|
728
|
+
|
729
|
+
return RULES_OK;
|
730
|
+
}
|
731
|
+
|
732
|
+
int leftLength;
|
733
|
+
int rightLength;
|
734
|
+
unsigned short type = propertyType << 8;
|
735
|
+
type = type + rightProperty->type;
|
736
|
+
switch(type) {
|
737
|
+
case OP_BOOL_BOOL:
|
738
|
+
*propertyMatch = compareBool(currentProperty->value.b, rightProperty->value.b, alphaOp);
|
739
|
+
break;
|
740
|
+
case OP_BOOL_INT:
|
741
|
+
*propertyMatch = compareInt(currentProperty->value.b, rightProperty->value.i, alphaOp);
|
742
|
+
break;
|
743
|
+
case OP_BOOL_DOUBLE:
|
744
|
+
*propertyMatch = compareDouble(currentProperty->value.b, rightProperty->value.d, alphaOp);
|
745
|
+
break;
|
746
|
+
case OP_BOOL_STRING:
|
747
|
+
if (currentProperty->value.b) {
|
748
|
+
*propertyMatch = compareStringProperty("true",
|
749
|
+
rightState + rightProperty->valueOffset,
|
750
|
+
rightProperty->valueLength,
|
751
|
+
alphaOp);
|
752
|
+
}
|
753
|
+
else {
|
754
|
+
*propertyMatch = compareStringProperty("false",
|
755
|
+
rightState + rightProperty->valueOffset,
|
756
|
+
rightProperty->valueLength,
|
757
|
+
alphaOp);
|
758
|
+
}
|
759
|
+
|
760
|
+
break;
|
761
|
+
case OP_INT_BOOL:
|
762
|
+
*propertyMatch = compareInt(currentProperty->value.i, rightProperty->value.b, alphaOp);
|
763
|
+
break;
|
764
|
+
case OP_INT_INT:
|
765
|
+
*propertyMatch = compareInt(currentProperty->value.i, rightProperty->value.i, alphaOp);
|
766
|
+
break;
|
767
|
+
case OP_INT_DOUBLE:
|
768
|
+
*propertyMatch = compareDouble(currentProperty->value.i, rightProperty->value.d, alphaOp);
|
769
|
+
break;
|
770
|
+
case OP_INT_STRING:
|
771
|
+
{
|
772
|
+
rightLength = rightProperty->valueLength + 1;
|
773
|
+
#ifdef _WIN32
|
774
|
+
char *leftStringInt = (char *)_alloca(sizeof(char)*(rightLength));
|
775
|
+
sprintf_s(leftStringInt, rightLength, "%ld", currentProperty->value.i);
|
776
|
+
#else
|
777
|
+
char leftStringInt[rightLength];
|
778
|
+
snprintf(leftStringInt, rightLength, "%ld", currentProperty->value.i);
|
779
|
+
#endif
|
780
|
+
*propertyMatch = compareStringProperty(leftStringInt,
|
781
|
+
rightState + rightProperty->valueOffset,
|
782
|
+
rightProperty->valueLength,
|
783
|
+
alphaOp);
|
784
|
+
}
|
785
|
+
break;
|
786
|
+
case OP_DOUBLE_BOOL:
|
787
|
+
*propertyMatch = compareDouble(currentProperty->value.i, rightProperty->value.b, alphaOp);
|
788
|
+
break;
|
789
|
+
case OP_DOUBLE_INT:
|
790
|
+
*propertyMatch = compareDouble(currentProperty->value.i, rightProperty->value.i, alphaOp);
|
791
|
+
break;
|
792
|
+
case OP_DOUBLE_DOUBLE:
|
793
|
+
*propertyMatch = compareDouble(currentProperty->value.i, rightProperty->value.d, alphaOp);
|
794
|
+
break;
|
795
|
+
case OP_DOUBLE_STRING:
|
796
|
+
{
|
797
|
+
rightLength = rightProperty->valueLength + 1;
|
798
|
+
#ifdef _WIN32
|
799
|
+
char *leftStringDouble = (char *)_alloca(sizeof(char)*(rightLength));
|
800
|
+
sprintf_s(leftStringDouble, rightLength, "%f", currentProperty->value.d);
|
801
|
+
#else
|
802
|
+
char leftStringDouble[rightLength];
|
803
|
+
snprintf(leftStringDouble, rightLength, "%f", currentProperty->value.d);
|
804
|
+
#endif
|
805
|
+
*propertyMatch = compareStringProperty(leftStringDouble,
|
806
|
+
rightState + rightProperty->valueOffset,
|
807
|
+
rightProperty->valueLength,
|
808
|
+
alphaOp);
|
809
|
+
}
|
810
|
+
break;
|
811
|
+
case OP_STRING_BOOL:
|
812
|
+
if (rightProperty->value.b) {
|
813
|
+
*propertyMatch = compareString(message + currentProperty->valueOffset,
|
814
|
+
currentProperty->valueLength,
|
815
|
+
"true",
|
816
|
+
alphaOp);
|
817
|
+
}
|
818
|
+
else {
|
819
|
+
*propertyMatch = compareString(message + currentProperty->valueOffset,
|
820
|
+
currentProperty->valueLength,
|
821
|
+
"false",
|
822
|
+
alphaOp);
|
823
|
+
}
|
824
|
+
break;
|
825
|
+
case OP_STRING_INT:
|
826
|
+
{
|
827
|
+
leftLength = currentProperty->valueLength + 1;
|
828
|
+
#ifdef _WIN32
|
829
|
+
char *rightStringInt = (char *)_alloca(sizeof(char)*(leftLength));
|
830
|
+
sprintf_s(rightStringInt, leftLength, "%ld", rightProperty->value.i);
|
831
|
+
#else
|
832
|
+
char rightStringInt[leftLength];
|
833
|
+
snprintf(rightStringInt, leftLength, "%ld", rightProperty->value.i);
|
834
|
+
#endif
|
835
|
+
*propertyMatch = compareString(message + currentProperty->valueOffset,
|
836
|
+
currentProperty->valueLength,
|
837
|
+
rightStringInt,
|
838
|
+
alphaOp);
|
839
|
+
}
|
840
|
+
break;
|
841
|
+
case OP_STRING_DOUBLE:
|
842
|
+
{
|
843
|
+
leftLength = currentProperty->valueLength + 1;
|
844
|
+
#ifdef _WIN32
|
845
|
+
char *rightStringDouble = (char *)_alloca(sizeof(char)*(leftLength));
|
846
|
+
sprintf_s(rightStringDouble, leftLength, "%f", rightProperty->value.d);
|
847
|
+
#else
|
848
|
+
char rightStringDouble[leftLength];
|
849
|
+
snprintf(rightStringDouble, leftLength, "%f", rightProperty->value.d);
|
850
|
+
#endif
|
851
|
+
*propertyMatch = compareString(message + currentProperty->valueOffset,
|
852
|
+
currentProperty->valueLength,
|
853
|
+
rightStringDouble,
|
854
|
+
alphaOp);
|
855
|
+
}
|
856
|
+
break;
|
857
|
+
case OP_STRING_STRING:
|
858
|
+
*propertyMatch = compareStringAndStringProperty(message + currentProperty->valueOffset,
|
859
|
+
currentProperty->valueLength,
|
860
|
+
rightState + rightProperty->valueOffset,
|
861
|
+
rightProperty->valueLength,
|
862
|
+
alphaOp);
|
863
|
+
break;
|
864
|
+
}
|
865
|
+
|
866
|
+
if (releaseRightState) {
|
867
|
+
free(rightState);
|
868
|
+
}
|
869
|
+
|
870
|
+
return result;
|
871
|
+
}
|
872
|
+
|
873
|
+
static unsigned int handleAlpha(ruleset *tree,
|
874
|
+
char *sid,
|
875
|
+
char *mid,
|
876
|
+
char *message,
|
877
|
+
jsonProperty *allProperties,
|
878
|
+
unsigned int propertiesLength,
|
879
|
+
alpha *alphaNode,
|
880
|
+
unsigned char actionType,
|
881
|
+
char **evalKeys,
|
882
|
+
unsigned short *evalPriorities,
|
883
|
+
unsigned int *evalCount,
|
884
|
+
char **addKeys,
|
885
|
+
unsigned int *addCount,
|
886
|
+
char **removeCommand,
|
887
|
+
void **rulesBinding) {
|
888
|
+
unsigned int result = ERR_EVENT_NOT_HANDLED;
|
889
|
+
unsigned short top = 1;
|
890
|
+
unsigned int entry;
|
891
|
+
alpha *stack[MAX_STACK_SIZE];
|
892
|
+
stack[0] = alphaNode;
|
893
|
+
alpha *currentAlpha;
|
894
|
+
while (top) {
|
895
|
+
--top;
|
896
|
+
currentAlpha = stack[top];
|
897
|
+
if (currentAlpha->nextListOffset) {
|
898
|
+
unsigned int *nextList = &tree->nextPool[currentAlpha->nextListOffset];
|
899
|
+
for (entry = 0; nextList[entry] != 0; ++entry) {
|
900
|
+
node *listNode = &tree->nodePool[nextList[entry]];
|
901
|
+
char exists = 0;
|
902
|
+
for(unsigned int propertyIndex = 0; propertyIndex < propertiesLength; ++propertyIndex) {
|
903
|
+
if (listNode->value.a.hash == allProperties[propertyIndex].hash) {
|
904
|
+
exists = 1;
|
905
|
+
break;
|
906
|
+
}
|
907
|
+
}
|
908
|
+
|
909
|
+
if (!exists) {
|
910
|
+
if (top == MAX_STACK_SIZE) {
|
911
|
+
return ERR_MAX_STACK_SIZE;
|
912
|
+
}
|
913
|
+
|
914
|
+
stack[top] = &listNode->value.a;
|
915
|
+
++top;
|
916
|
+
}
|
917
|
+
}
|
918
|
+
}
|
919
|
+
|
920
|
+
if (currentAlpha->nextOffset) {
|
921
|
+
unsigned int *nextHashset = &tree->nextPool[currentAlpha->nextOffset];
|
922
|
+
for(unsigned int propertyIndex = 0; propertyIndex < propertiesLength; ++propertyIndex) {
|
923
|
+
jsonProperty *currentProperty = &allProperties[propertyIndex];
|
924
|
+
for (entry = currentProperty->hash & HASH_MASK; nextHashset[entry] != 0; entry = (entry + 1) % NEXT_BUCKET_LENGTH) {
|
925
|
+
node *hashNode = &tree->nodePool[nextHashset[entry]];
|
926
|
+
if (currentProperty->hash == hashNode->value.a.hash) {
|
927
|
+
if (hashNode->value.a.right.type == JSON_EVENT_PROPERTY || hashNode->value.a.right.type == JSON_EVENT_IDIOM) {
|
928
|
+
if (top == MAX_STACK_SIZE) {
|
929
|
+
return ERR_MAX_STACK_SIZE;
|
930
|
+
}
|
931
|
+
|
932
|
+
stack[top] = &hashNode->value.a;
|
933
|
+
++top;
|
934
|
+
} else {
|
935
|
+
unsigned char match = 0;
|
936
|
+
unsigned int mresult = isMatch(tree,
|
937
|
+
sid,
|
938
|
+
message,
|
939
|
+
currentProperty,
|
940
|
+
&hashNode->value.a,
|
941
|
+
&match,
|
942
|
+
rulesBinding);
|
943
|
+
if (mresult != RULES_OK){
|
944
|
+
return mresult;
|
945
|
+
}
|
946
|
+
if (match) {
|
947
|
+
if (top == MAX_STACK_SIZE) {
|
948
|
+
return ERR_MAX_STACK_SIZE;
|
949
|
+
}
|
950
|
+
|
951
|
+
stack[top] = &hashNode->value.a;
|
952
|
+
++top;
|
953
|
+
}
|
954
|
+
}
|
955
|
+
}
|
956
|
+
}
|
957
|
+
}
|
958
|
+
}
|
959
|
+
|
960
|
+
if (currentAlpha->betaListOffset) {
|
961
|
+
unsigned int *betaList = &tree->nextPool[currentAlpha->betaListOffset];
|
962
|
+
for (unsigned int entry = 0; betaList[entry] != 0; ++entry) {
|
963
|
+
unsigned int bresult = handleBeta(tree,
|
964
|
+
sid,
|
965
|
+
mid,
|
966
|
+
&tree->nodePool[betaList[entry]],
|
967
|
+
actionType,
|
968
|
+
evalKeys,
|
969
|
+
evalPriorities,
|
970
|
+
evalCount,
|
971
|
+
addKeys,
|
972
|
+
addCount,
|
973
|
+
removeCommand,
|
974
|
+
rulesBinding);
|
975
|
+
if (bresult != RULES_OK && bresult != ERR_NEW_SESSION) {
|
976
|
+
return result;
|
977
|
+
}
|
978
|
+
|
979
|
+
if (result != ERR_NEW_SESSION) {
|
980
|
+
result = bresult;
|
981
|
+
}
|
982
|
+
}
|
983
|
+
}
|
984
|
+
}
|
985
|
+
|
986
|
+
return result;
|
987
|
+
}
|
988
|
+
|
989
|
+
static unsigned int getId(jsonProperty *allProperties,
|
990
|
+
unsigned int idIndex,
|
991
|
+
jsonProperty **idProperty,
|
992
|
+
int *idLength) {
|
993
|
+
jsonProperty *currentProperty;
|
994
|
+
if (idIndex == UNDEFINED_INDEX) {
|
995
|
+
return ERR_NO_ID_DEFINED;
|
996
|
+
}
|
997
|
+
|
998
|
+
currentProperty = &allProperties[idIndex];
|
999
|
+
*idLength = currentProperty->valueLength;
|
1000
|
+
switch(currentProperty->type) {
|
1001
|
+
case JSON_INT:
|
1002
|
+
case JSON_DOUBLE:
|
1003
|
+
*idLength = *idLength + 1;
|
1004
|
+
case JSON_STRING:
|
1005
|
+
break;
|
1006
|
+
default:
|
1007
|
+
return ERR_INVALID_ID;
|
1008
|
+
}
|
1009
|
+
|
1010
|
+
*idProperty = currentProperty;
|
1011
|
+
return RULES_OK;
|
1012
|
+
}
|
1013
|
+
|
1014
|
+
static unsigned int handleMessageCore(ruleset *tree,
|
1015
|
+
char *state,
|
1016
|
+
char *message,
|
1017
|
+
jsonProperty *properties,
|
1018
|
+
unsigned int propertiesLength,
|
1019
|
+
unsigned int midIndex,
|
1020
|
+
unsigned int sidIndex,
|
1021
|
+
unsigned char actionType,
|
1022
|
+
char **commands,
|
1023
|
+
unsigned int *commandCount,
|
1024
|
+
void **rulesBinding) {
|
1025
|
+
jsonProperty *midProperty;
|
1026
|
+
int midLength;
|
1027
|
+
jsonProperty *sidProperty;
|
1028
|
+
int sidLength;
|
1029
|
+
char *storeCommand;
|
1030
|
+
int result = getId(properties, sidIndex, &sidProperty, &sidLength);
|
1031
|
+
if (result != RULES_OK) {
|
1032
|
+
return result;
|
1033
|
+
}
|
1034
|
+
#ifdef _WIN32
|
1035
|
+
char *sid = (char *)_alloca(sizeof(char)*(sidLength + 1));
|
1036
|
+
#else
|
1037
|
+
char sid[sidLength + 1];
|
1038
|
+
#endif
|
1039
|
+
strncpy(sid, message + sidProperty->valueOffset, sidLength);
|
1040
|
+
sid[sidLength] = '\0';
|
1041
|
+
|
1042
|
+
result = getId(properties, midIndex, &midProperty, &midLength);
|
1043
|
+
if (result != RULES_OK) {
|
1044
|
+
return result;
|
1045
|
+
}
|
1046
|
+
#ifdef _WIN32
|
1047
|
+
char *mid = (char *)_alloca(sizeof(char)*(midLength + 1));
|
1048
|
+
#else
|
1049
|
+
char mid[midLength + 1];
|
1050
|
+
#endif
|
1051
|
+
strncpy(mid, message + midProperty->valueOffset, midLength);
|
1052
|
+
mid[midLength] = '\0';
|
1053
|
+
if (*commandCount == MAX_COMMAND_COUNT) {
|
1054
|
+
return ERR_MAX_COMMAND_COUNT;
|
1055
|
+
}
|
1056
|
+
|
1057
|
+
if (state) {
|
1058
|
+
if (!*rulesBinding) {
|
1059
|
+
result = resolveBinding(tree, sid, rulesBinding);
|
1060
|
+
if (result != RULES_OK) {
|
1061
|
+
return result;
|
1062
|
+
}
|
1063
|
+
}
|
1064
|
+
|
1065
|
+
if (*commandCount == MAX_COMMAND_COUNT) {
|
1066
|
+
return ERR_MAX_COMMAND_COUNT;
|
1067
|
+
}
|
1068
|
+
|
1069
|
+
result = formatStoreSession(*rulesBinding, sid, state, 0, &storeCommand);
|
1070
|
+
if (result != RULES_OK) {
|
1071
|
+
return result;
|
1072
|
+
}
|
1073
|
+
|
1074
|
+
commands[*commandCount] = storeCommand;
|
1075
|
+
++*commandCount;
|
1076
|
+
}
|
1077
|
+
|
1078
|
+
char *removeCommand = NULL;
|
1079
|
+
char *addKeys[MAX_ADD_COUNT];
|
1080
|
+
unsigned int addCount = 0;
|
1081
|
+
char *evalKeys[MAX_EVAL_COUNT];
|
1082
|
+
unsigned short evalPriorities[MAX_EVAL_COUNT];
|
1083
|
+
unsigned int evalCount = 0;
|
1084
|
+
result = handleAlpha(tree,
|
1085
|
+
sid,
|
1086
|
+
mid,
|
1087
|
+
message,
|
1088
|
+
properties,
|
1089
|
+
propertiesLength,
|
1090
|
+
&tree->nodePool[NODE_M_OFFSET].value.a,
|
1091
|
+
actionType,
|
1092
|
+
evalKeys,
|
1093
|
+
evalPriorities,
|
1094
|
+
&evalCount,
|
1095
|
+
addKeys,
|
1096
|
+
&addCount,
|
1097
|
+
&removeCommand,
|
1098
|
+
rulesBinding);
|
1099
|
+
if (result == RULES_OK) {
|
1100
|
+
if (*commandCount == MAX_COMMAND_COUNT - 3) {
|
1101
|
+
for (unsigned int i = 0; i < addCount; ++i) {
|
1102
|
+
free(addKeys[i]);
|
1103
|
+
}
|
1104
|
+
|
1105
|
+
for (unsigned int i = 0; i < evalCount; ++i) {
|
1106
|
+
free(evalKeys[i]);
|
1107
|
+
}
|
1108
|
+
|
1109
|
+
return ERR_MAX_COMMAND_COUNT;
|
1110
|
+
}
|
1111
|
+
|
1112
|
+
if (removeCommand) {
|
1113
|
+
commands[*commandCount] = removeCommand;
|
1114
|
+
++*commandCount;
|
1115
|
+
}
|
1116
|
+
|
1117
|
+
if (addCount > 0) {
|
1118
|
+
char *addCommand = NULL;
|
1119
|
+
result = formatStoreMessage(*rulesBinding,
|
1120
|
+
sid,
|
1121
|
+
message,
|
1122
|
+
properties,
|
1123
|
+
propertiesLength,
|
1124
|
+
actionType == ACTION_ASSERT_FACT ? 1 : 0,
|
1125
|
+
addKeys,
|
1126
|
+
addCount,
|
1127
|
+
&addCommand);
|
1128
|
+
|
1129
|
+
for (unsigned int i = 0; i < addCount; ++i) {
|
1130
|
+
free(addKeys[i]);
|
1131
|
+
}
|
1132
|
+
|
1133
|
+
if (result != RULES_OK) {
|
1134
|
+
for (unsigned int i = 0; i < evalCount; ++i) {
|
1135
|
+
free(evalKeys[i]);
|
1136
|
+
}
|
1137
|
+
|
1138
|
+
return result;
|
1139
|
+
}
|
1140
|
+
|
1141
|
+
commands[*commandCount] = addCommand;
|
1142
|
+
++*commandCount;
|
1143
|
+
}
|
1144
|
+
|
1145
|
+
if (evalCount > 0) {
|
1146
|
+
char *evalCommand = NULL;
|
1147
|
+
result = formatEvalMessage(*rulesBinding,
|
1148
|
+
sid,
|
1149
|
+
mid,
|
1150
|
+
message,
|
1151
|
+
properties,
|
1152
|
+
propertiesLength,
|
1153
|
+
actionType,
|
1154
|
+
evalKeys,
|
1155
|
+
evalCount,
|
1156
|
+
&evalCommand);
|
1157
|
+
|
1158
|
+
for (unsigned int i = 0; i < evalCount; ++i) {
|
1159
|
+
free(evalKeys[i]);
|
1160
|
+
}
|
1161
|
+
|
1162
|
+
if (result != RULES_OK) {
|
1163
|
+
return result;
|
1164
|
+
}
|
1165
|
+
|
1166
|
+
commands[*commandCount] = evalCommand;
|
1167
|
+
++*commandCount;
|
1168
|
+
}
|
1169
|
+
|
1170
|
+
if (!state) {
|
1171
|
+
// try creating state if doesn't exist
|
1172
|
+
jsonProperty *targetProperty;
|
1173
|
+
char *targetState;
|
1174
|
+
result = fetchStateProperty(tree,
|
1175
|
+
sid,
|
1176
|
+
HASH_SID,
|
1177
|
+
MAX_STATE_PROPERTY_TIME,
|
1178
|
+
1,
|
1179
|
+
&targetState,
|
1180
|
+
&targetProperty);
|
1181
|
+
if (result != ERR_STATE_NOT_LOADED && result != ERR_PROPERTY_NOT_FOUND) {
|
1182
|
+
return result;
|
1183
|
+
}
|
1184
|
+
|
1185
|
+
// this sid has been tried by this process already
|
1186
|
+
if (result == ERR_PROPERTY_NOT_FOUND) {
|
1187
|
+
return RULES_OK;
|
1188
|
+
}
|
1189
|
+
|
1190
|
+
result = refreshState(tree,sid);
|
1191
|
+
if (result != ERR_NEW_SESSION) {
|
1192
|
+
return result;
|
1193
|
+
}
|
1194
|
+
#ifdef _WIN32
|
1195
|
+
char *stateMessage = (char *)_alloca(sizeof(char)*(36 + sidLength));
|
1196
|
+
char *newState = (char *)_alloca(sizeof(char)*(12 + sidLength));
|
1197
|
+
if (sidProperty->type == JSON_STRING) {
|
1198
|
+
sprintf_s(stateMessage, 36 + sidLength, "{\"id\":\"$s\", \"sid\":\"%s\", \"$s\":1}", sid);
|
1199
|
+
sprintf_s(newState, 12 + sidLength, "{\"sid\":\"%s\"}", sid);
|
1200
|
+
}
|
1201
|
+
else {
|
1202
|
+
sprintf_s(stateMessage, 36 + sidLength, "{\"id\":\"$s\", \"sid\":%s, \"$s\":1}", sid);
|
1203
|
+
sprintf_s(newState, 12 + sidLength, "{\"sid\":%s}", sid);
|
1204
|
+
}
|
1205
|
+
#else
|
1206
|
+
char stateMessage[36 + sidLength];
|
1207
|
+
char newState[12 + sidLength];
|
1208
|
+
if (sidProperty->type == JSON_STRING) {
|
1209
|
+
snprintf(stateMessage, 36 + sidLength, "{\"id\":\"$s\", \"sid\":\"%s\", \"$s\":1}", sid);
|
1210
|
+
snprintf(newState, 12 + sidLength, "{\"sid\":\"%s\"}", sid);
|
1211
|
+
}
|
1212
|
+
else {
|
1213
|
+
snprintf(stateMessage, 36 + sidLength, "{\"id\":\"$s\", \"sid\":%s, \"$s\":1}", sid);
|
1214
|
+
snprintf(newState, 12 + sidLength, "{\"sid\":%s}", sid);
|
1215
|
+
}
|
1216
|
+
#endif
|
1217
|
+
|
1218
|
+
if (*commandCount == MAX_COMMAND_COUNT) {
|
1219
|
+
return ERR_MAX_COMMAND_COUNT;
|
1220
|
+
}
|
1221
|
+
|
1222
|
+
result = formatStoreSession(*rulesBinding, sid, newState, 1, &storeCommand);
|
1223
|
+
if (result != RULES_OK) {
|
1224
|
+
return result;
|
1225
|
+
}
|
1226
|
+
|
1227
|
+
commands[*commandCount] = storeCommand;
|
1228
|
+
++*commandCount;
|
1229
|
+
|
1230
|
+
result = handleMessage(tree,
|
1231
|
+
NULL,
|
1232
|
+
stateMessage,
|
1233
|
+
ACTION_ASSERT_EVENT,
|
1234
|
+
commands,
|
1235
|
+
commandCount,
|
1236
|
+
rulesBinding);
|
1237
|
+
if (result != RULES_OK && result != ERR_EVENT_NOT_HANDLED) {
|
1238
|
+
return result;
|
1239
|
+
}
|
1240
|
+
|
1241
|
+
if (result == ERR_EVENT_NOT_HANDLED) {
|
1242
|
+
return RULES_OK;
|
1243
|
+
}
|
1244
|
+
}
|
1245
|
+
|
1246
|
+
return RULES_OK;
|
1247
|
+
}
|
1248
|
+
|
1249
|
+
return result;
|
1250
|
+
}
|
1251
|
+
|
1252
|
+
static unsigned int handleMessage(ruleset *tree,
|
1253
|
+
char *state,
|
1254
|
+
char *message,
|
1255
|
+
unsigned char actionType,
|
1256
|
+
char **commands,
|
1257
|
+
unsigned int *commandCount,
|
1258
|
+
void **rulesBinding) {
|
1259
|
+
char *next;
|
1260
|
+
unsigned int propertiesLength = 0;
|
1261
|
+
unsigned int midIndex = UNDEFINED_INDEX;
|
1262
|
+
unsigned int sidIndex = UNDEFINED_INDEX;
|
1263
|
+
jsonProperty properties[MAX_EVENT_PROPERTIES];
|
1264
|
+
int result = constructObject(NULL,
|
1265
|
+
message,
|
1266
|
+
0,
|
1267
|
+
MAX_EVENT_PROPERTIES,
|
1268
|
+
properties,
|
1269
|
+
&propertiesLength,
|
1270
|
+
&midIndex,
|
1271
|
+
&sidIndex,
|
1272
|
+
&next);
|
1273
|
+
if (result != RULES_OK) {
|
1274
|
+
return result;
|
1275
|
+
}
|
1276
|
+
|
1277
|
+
return handleMessageCore(tree,
|
1278
|
+
state,
|
1279
|
+
message,
|
1280
|
+
properties,
|
1281
|
+
propertiesLength,
|
1282
|
+
midIndex,
|
1283
|
+
sidIndex,
|
1284
|
+
actionType,
|
1285
|
+
commands,
|
1286
|
+
commandCount,
|
1287
|
+
rulesBinding);
|
1288
|
+
}
|
1289
|
+
|
1290
|
+
static unsigned int handleMessages(void *handle,
|
1291
|
+
unsigned char actionType,
|
1292
|
+
char *messages,
|
1293
|
+
char **commands,
|
1294
|
+
unsigned int *commandCount,
|
1295
|
+
unsigned int *resultsLength,
|
1296
|
+
unsigned int **results,
|
1297
|
+
void **rulesBinding) {
|
1298
|
+
unsigned int messagesLength = 64;
|
1299
|
+
unsigned int *resultsArray = malloc(sizeof(unsigned int) * messagesLength);
|
1300
|
+
if (!resultsArray) {
|
1301
|
+
return ERR_OUT_OF_MEMORY;
|
1302
|
+
}
|
1303
|
+
|
1304
|
+
*results = resultsArray;
|
1305
|
+
*resultsLength = 0;
|
1306
|
+
unsigned int result;
|
1307
|
+
jsonProperty properties[MAX_EVENT_PROPERTIES];
|
1308
|
+
unsigned int propertiesLength = 0;
|
1309
|
+
unsigned int propertiesMidIndex = UNDEFINED_INDEX;
|
1310
|
+
unsigned int propertiesSidIndex = UNDEFINED_INDEX;
|
1311
|
+
|
1312
|
+
char *first = messages;
|
1313
|
+
char *last = NULL;
|
1314
|
+
char lastTemp;
|
1315
|
+
|
1316
|
+
while (*first != '{' && *first != '\0' ) {
|
1317
|
+
++first;
|
1318
|
+
}
|
1319
|
+
|
1320
|
+
while (constructObject(NULL,
|
1321
|
+
first,
|
1322
|
+
0,
|
1323
|
+
MAX_EVENT_PROPERTIES,
|
1324
|
+
properties,
|
1325
|
+
&propertiesLength,
|
1326
|
+
&propertiesMidIndex,
|
1327
|
+
&propertiesSidIndex,
|
1328
|
+
&last) == RULES_OK) {
|
1329
|
+
|
1330
|
+
while (*last != ',' && *last != ']' ) {
|
1331
|
+
++last;
|
1332
|
+
}
|
1333
|
+
|
1334
|
+
lastTemp = *last;
|
1335
|
+
*last = '\0';
|
1336
|
+
result = handleMessageCore(handle,
|
1337
|
+
NULL,
|
1338
|
+
first,
|
1339
|
+
properties,
|
1340
|
+
propertiesLength,
|
1341
|
+
propertiesMidIndex,
|
1342
|
+
propertiesSidIndex,
|
1343
|
+
actionType,
|
1344
|
+
commands,
|
1345
|
+
commandCount,
|
1346
|
+
rulesBinding);
|
1347
|
+
|
1348
|
+
*last = lastTemp;
|
1349
|
+
if (result != RULES_OK && result != ERR_EVENT_NOT_HANDLED) {
|
1350
|
+
free(resultsArray);
|
1351
|
+
return result;
|
1352
|
+
}
|
1353
|
+
|
1354
|
+
if (*resultsLength >= messagesLength) {
|
1355
|
+
messagesLength = messagesLength * 2;
|
1356
|
+
resultsArray = realloc(resultsArray, sizeof(unsigned int) * messagesLength);
|
1357
|
+
if (!resultsArray) {
|
1358
|
+
return ERR_OUT_OF_MEMORY;
|
1359
|
+
}
|
1360
|
+
*results = resultsArray;
|
1361
|
+
}
|
1362
|
+
|
1363
|
+
resultsArray[*resultsLength] = result;
|
1364
|
+
++*resultsLength;
|
1365
|
+
propertiesLength = 0;
|
1366
|
+
propertiesMidIndex = UNDEFINED_INDEX;
|
1367
|
+
propertiesSidIndex = UNDEFINED_INDEX;
|
1368
|
+
|
1369
|
+
first = last;
|
1370
|
+
while (*first != '{' && *first != '\0' ) {
|
1371
|
+
++first;
|
1372
|
+
}
|
1373
|
+
}
|
1374
|
+
|
1375
|
+
return RULES_OK;
|
1376
|
+
}
|
1377
|
+
|
1378
|
+
static unsigned int handleState(ruleset *tree,
|
1379
|
+
char *state,
|
1380
|
+
char **commands,
|
1381
|
+
unsigned int *commandCount,
|
1382
|
+
void **rulesBinding) {
|
1383
|
+
int stateLength = strlen(state);
|
1384
|
+
if (stateLength < 2) {
|
1385
|
+
return ERR_PARSE_OBJECT;
|
1386
|
+
}
|
1387
|
+
|
1388
|
+
if (state[0] != '{') {
|
1389
|
+
return ERR_PARSE_OBJECT;
|
1390
|
+
}
|
1391
|
+
|
1392
|
+
char *stateMessagePostfix = state + 1;
|
1393
|
+
#ifdef _WIN32
|
1394
|
+
char *stateMessage = (char *)_alloca(sizeof(char)*(30 + stateLength - 1));
|
1395
|
+
#else
|
1396
|
+
char stateMessage[30 + stateLength - 1];
|
1397
|
+
#endif
|
1398
|
+
int randomMid = rand();
|
1399
|
+
#ifdef _WIN32
|
1400
|
+
sprintf_s(stateMessage, 30 + stateLength - 1, "{\"id\":%d, \"$s\":1, %s", randomMid, stateMessagePostfix);
|
1401
|
+
#else
|
1402
|
+
snprintf(stateMessage, 30 + stateLength - 1, "{\"id\":%d, \"$s\":1, %s", randomMid, stateMessagePostfix);
|
1403
|
+
#endif
|
1404
|
+
unsigned int result = handleMessage(tree,
|
1405
|
+
state,
|
1406
|
+
stateMessage,
|
1407
|
+
ACTION_ASSERT_EVENT,
|
1408
|
+
commands,
|
1409
|
+
commandCount,
|
1410
|
+
rulesBinding);
|
1411
|
+
|
1412
|
+
return result;
|
1413
|
+
}
|
1414
|
+
|
1415
|
+
static unsigned int handleTimers(void *handle,
|
1416
|
+
char **commands,
|
1417
|
+
unsigned int *commandCount,
|
1418
|
+
void **rulesBinding) {
|
1419
|
+
redisReply *reply;
|
1420
|
+
unsigned int result = peekTimers(handle, rulesBinding, &reply);
|
1421
|
+
if (result != RULES_OK) {
|
1422
|
+
return result;
|
1423
|
+
}
|
1424
|
+
|
1425
|
+
for (unsigned long i = 0; i < reply->elements; ++i) {
|
1426
|
+
if (*commandCount == MAX_COMMAND_COUNT) {
|
1427
|
+
return ERR_MAX_COMMAND_COUNT;
|
1428
|
+
}
|
1429
|
+
|
1430
|
+
char *command;
|
1431
|
+
result = formatRemoveTimer(*rulesBinding, reply->element[i]->str, &command);
|
1432
|
+
if (result != RULES_OK) {
|
1433
|
+
freeReplyObject(reply);
|
1434
|
+
return result;
|
1435
|
+
}
|
1436
|
+
|
1437
|
+
commands[*commandCount] = command;
|
1438
|
+
++*commandCount;
|
1439
|
+
|
1440
|
+
result = handleMessage(handle,
|
1441
|
+
NULL,
|
1442
|
+
reply->element[i]->str,
|
1443
|
+
ACTION_ASSERT_EVENT,
|
1444
|
+
commands,
|
1445
|
+
commandCount,
|
1446
|
+
rulesBinding);
|
1447
|
+
if (result != RULES_OK && result != ERR_EVENT_NOT_HANDLED) {
|
1448
|
+
freeReplyObject(reply);
|
1449
|
+
return result;
|
1450
|
+
}
|
1451
|
+
}
|
1452
|
+
|
1453
|
+
freeReplyObject(reply);
|
1454
|
+
return RULES_OK;
|
1455
|
+
}
|
1456
|
+
|
1457
|
+
static unsigned int startHandleMessage(void *handle,
|
1458
|
+
char *message,
|
1459
|
+
unsigned char actionType,
|
1460
|
+
void **rulesBinding,
|
1461
|
+
unsigned int *replyCount) {
|
1462
|
+
char *commands[MAX_COMMAND_COUNT];
|
1463
|
+
unsigned int commandCount = 0;
|
1464
|
+
unsigned int result = handleMessage(handle,
|
1465
|
+
NULL,
|
1466
|
+
message,
|
1467
|
+
actionType,
|
1468
|
+
commands,
|
1469
|
+
&commandCount,
|
1470
|
+
rulesBinding);
|
1471
|
+
if (result != RULES_OK && result != ERR_EVENT_NOT_HANDLED) {
|
1472
|
+
freeCommands(commands, commandCount);
|
1473
|
+
return result;
|
1474
|
+
}
|
1475
|
+
|
1476
|
+
unsigned int batchResult = startNonBlockingBatch(*rulesBinding, commands, commandCount, replyCount);
|
1477
|
+
if (batchResult != RULES_OK) {
|
1478
|
+
return batchResult;
|
1479
|
+
}
|
1480
|
+
|
1481
|
+
return result;
|
1482
|
+
}
|
1483
|
+
|
1484
|
+
static unsigned int executeHandleMessage(void *handle,
|
1485
|
+
char *message,
|
1486
|
+
unsigned char actionType) {
|
1487
|
+
char *commands[MAX_COMMAND_COUNT];
|
1488
|
+
unsigned int commandCount = 0;
|
1489
|
+
void *rulesBinding = NULL;
|
1490
|
+
unsigned int result = handleMessage(handle,
|
1491
|
+
NULL,
|
1492
|
+
message,
|
1493
|
+
actionType,
|
1494
|
+
commands,
|
1495
|
+
&commandCount,
|
1496
|
+
&rulesBinding);
|
1497
|
+
if (result != RULES_OK && result != ERR_EVENT_NOT_HANDLED) {
|
1498
|
+
freeCommands(commands, commandCount);
|
1499
|
+
return result;
|
1500
|
+
}
|
1501
|
+
|
1502
|
+
unsigned int batchResult = executeBatch(rulesBinding, commands, commandCount);
|
1503
|
+
if (batchResult != RULES_OK) {
|
1504
|
+
return batchResult;
|
1505
|
+
}
|
1506
|
+
|
1507
|
+
return result;
|
1508
|
+
}
|
1509
|
+
|
1510
|
+
static unsigned int startHandleMessages(void *handle,
|
1511
|
+
char *messages,
|
1512
|
+
unsigned char actionType,
|
1513
|
+
unsigned int *resultsLength,
|
1514
|
+
unsigned int **results,
|
1515
|
+
void **rulesBinding,
|
1516
|
+
unsigned int *replyCount) {
|
1517
|
+
char *commands[MAX_COMMAND_COUNT];
|
1518
|
+
unsigned int commandCount = 0;
|
1519
|
+
unsigned int result = handleMessages(handle,
|
1520
|
+
actionType,
|
1521
|
+
messages,
|
1522
|
+
commands,
|
1523
|
+
&commandCount,
|
1524
|
+
resultsLength,
|
1525
|
+
results,
|
1526
|
+
rulesBinding);
|
1527
|
+
if (result != RULES_OK && result != ERR_EVENT_NOT_HANDLED) {
|
1528
|
+
freeCommands(commands, commandCount);
|
1529
|
+
return result;
|
1530
|
+
}
|
1531
|
+
|
1532
|
+
unsigned int batchResult = startNonBlockingBatch(*rulesBinding, commands, commandCount, replyCount);
|
1533
|
+
if (batchResult != RULES_OK) {
|
1534
|
+
return batchResult;
|
1535
|
+
}
|
1536
|
+
|
1537
|
+
return result;
|
1538
|
+
}
|
1539
|
+
|
1540
|
+
static unsigned int executeHandleMessages(void *handle,
|
1541
|
+
char *messages,
|
1542
|
+
unsigned char actionType,
|
1543
|
+
unsigned int *resultsLength,
|
1544
|
+
unsigned int **results) {
|
1545
|
+
char *commands[MAX_COMMAND_COUNT];
|
1546
|
+
unsigned int commandCount = 0;
|
1547
|
+
void *rulesBinding = NULL;
|
1548
|
+
unsigned int result = handleMessages(handle,
|
1549
|
+
actionType,
|
1550
|
+
messages,
|
1551
|
+
commands,
|
1552
|
+
&commandCount,
|
1553
|
+
resultsLength,
|
1554
|
+
results,
|
1555
|
+
&rulesBinding);
|
1556
|
+
if (result != RULES_OK && result != ERR_EVENT_NOT_HANDLED) {
|
1557
|
+
freeCommands(commands, commandCount);
|
1558
|
+
return result;
|
1559
|
+
}
|
1560
|
+
|
1561
|
+
unsigned int batchResult = executeBatch(rulesBinding, commands, commandCount);
|
1562
|
+
if (batchResult != RULES_OK) {
|
1563
|
+
return batchResult;
|
1564
|
+
}
|
1565
|
+
|
1566
|
+
return result;
|
1567
|
+
}
|
1568
|
+
|
1569
|
+
unsigned int complete(void *rulesBinding, unsigned int replyCount) {
|
1570
|
+
return completeNonBlockingBatch(rulesBinding, replyCount);
|
1571
|
+
}
|
1572
|
+
|
1573
|
+
unsigned int assertEvent(void *handle, char *message) {
|
1574
|
+
return executeHandleMessage(handle, message, ACTION_ASSERT_EVENT);
|
1575
|
+
}
|
1576
|
+
|
1577
|
+
unsigned int startAssertEvent(void *handle,
|
1578
|
+
char *message,
|
1579
|
+
void **rulesBinding,
|
1580
|
+
unsigned int *replyCount) {
|
1581
|
+
return startHandleMessage(handle, message, ACTION_ASSERT_EVENT, rulesBinding, replyCount);
|
1582
|
+
}
|
1583
|
+
|
1584
|
+
unsigned int assertEvents(void *handle,
|
1585
|
+
char *messages,
|
1586
|
+
unsigned int *resultsLength,
|
1587
|
+
unsigned int **results) {
|
1588
|
+
return executeHandleMessages(handle, messages, ACTION_ASSERT_EVENT, resultsLength, results);
|
1589
|
+
}
|
1590
|
+
|
1591
|
+
unsigned int startAssertEvents(void *handle,
|
1592
|
+
char *messages,
|
1593
|
+
unsigned int *resultsLength,
|
1594
|
+
unsigned int **results,
|
1595
|
+
void **rulesBinding,
|
1596
|
+
unsigned int *replyCount) {
|
1597
|
+
return startHandleMessages(handle, messages, ACTION_ASSERT_EVENT, resultsLength, results, rulesBinding, replyCount);
|
1598
|
+
}
|
1599
|
+
|
1600
|
+
unsigned int retractEvent(void *handle, char *message) {
|
1601
|
+
return executeHandleMessage(handle, message, ACTION_REMOVE_EVENT);
|
1602
|
+
}
|
1603
|
+
|
1604
|
+
unsigned int startAssertFact(void *handle,
|
1605
|
+
char *message,
|
1606
|
+
void **rulesBinding,
|
1607
|
+
unsigned int *replyCount) {
|
1608
|
+
return startHandleMessage(handle, message, ACTION_ASSERT_FACT, rulesBinding, replyCount);
|
1609
|
+
}
|
1610
|
+
|
1611
|
+
unsigned int assertFact(void *handle, char *message) {
|
1612
|
+
return executeHandleMessage(handle, message, ACTION_ASSERT_FACT);
|
1613
|
+
}
|
1614
|
+
|
1615
|
+
unsigned int startAssertFacts(void *handle,
|
1616
|
+
char *messages,
|
1617
|
+
unsigned int *resultsLength,
|
1618
|
+
unsigned int **results,
|
1619
|
+
void **rulesBinding,
|
1620
|
+
unsigned int *replyCount) {
|
1621
|
+
return startHandleMessages(handle, messages, ACTION_ASSERT_FACT, resultsLength, results, rulesBinding, replyCount);
|
1622
|
+
}
|
1623
|
+
|
1624
|
+
unsigned int assertFacts(void *handle,
|
1625
|
+
char *messages,
|
1626
|
+
unsigned int *resultsLength,
|
1627
|
+
unsigned int **results) {
|
1628
|
+
return executeHandleMessages(handle, messages, ACTION_ASSERT_FACT, resultsLength, results);
|
1629
|
+
}
|
1630
|
+
|
1631
|
+
unsigned int retractFact(void *handle, char *message) {
|
1632
|
+
return executeHandleMessage(handle, message, ACTION_REMOVE_FACT);
|
1633
|
+
}
|
1634
|
+
|
1635
|
+
unsigned int startRetractFact(void *handle,
|
1636
|
+
char *message,
|
1637
|
+
void **rulesBinding,
|
1638
|
+
unsigned int *replyCount) {
|
1639
|
+
return startHandleMessage(handle, message, ACTION_REMOVE_FACT, rulesBinding, replyCount);
|
1640
|
+
}
|
1641
|
+
|
1642
|
+
unsigned int retractFacts(void *handle,
|
1643
|
+
char *messages,
|
1644
|
+
unsigned int *resultsLength,
|
1645
|
+
unsigned int **results) {
|
1646
|
+
return executeHandleMessages(handle, messages, ACTION_REMOVE_FACT, resultsLength, results);
|
1647
|
+
}
|
1648
|
+
|
1649
|
+
unsigned int startRetractFacts(void *handle,
|
1650
|
+
char *messages,
|
1651
|
+
unsigned int *resultsLength,
|
1652
|
+
unsigned int **results,
|
1653
|
+
void **rulesBinding,
|
1654
|
+
unsigned int *replyCount) {
|
1655
|
+
return startHandleMessages(handle, messages, ACTION_REMOVE_FACT, resultsLength, results, rulesBinding, replyCount);
|
1656
|
+
}
|
1657
|
+
|
1658
|
+
unsigned int assertState(void *handle, char *state) {
|
1659
|
+
char *commands[MAX_COMMAND_COUNT];
|
1660
|
+
unsigned int commandCount = 0;
|
1661
|
+
void *rulesBinding = NULL;
|
1662
|
+
unsigned int result = handleState(handle,
|
1663
|
+
state,
|
1664
|
+
commands,
|
1665
|
+
&commandCount,
|
1666
|
+
&rulesBinding);
|
1667
|
+
if (result != RULES_OK && result != ERR_EVENT_NOT_HANDLED) {
|
1668
|
+
freeCommands(commands, commandCount);
|
1669
|
+
return result;
|
1670
|
+
}
|
1671
|
+
|
1672
|
+
unsigned int batchResult = executeBatch(rulesBinding, commands, commandCount);
|
1673
|
+
if (batchResult != RULES_OK) {
|
1674
|
+
return batchResult;
|
1675
|
+
}
|
1676
|
+
|
1677
|
+
return result;
|
1678
|
+
}
|
1679
|
+
|
1680
|
+
unsigned int assertTimers(void *handle) {
|
1681
|
+
char *commands[MAX_COMMAND_COUNT];
|
1682
|
+
unsigned int commandCount = 0;
|
1683
|
+
void *rulesBinding = NULL;
|
1684
|
+
unsigned int result = handleTimers(handle,
|
1685
|
+
commands,
|
1686
|
+
&commandCount,
|
1687
|
+
&rulesBinding);
|
1688
|
+
if (result != RULES_OK) {
|
1689
|
+
freeCommands(commands, commandCount);
|
1690
|
+
return result;
|
1691
|
+
}
|
1692
|
+
|
1693
|
+
return executeBatch(rulesBinding, commands, commandCount);
|
1694
|
+
}
|
1695
|
+
|
1696
|
+
unsigned int startAction(void *handle,
|
1697
|
+
char **state,
|
1698
|
+
char **messages,
|
1699
|
+
void **actionHandle,
|
1700
|
+
void **actionBinding) {
|
1701
|
+
redisReply *reply;
|
1702
|
+
void *rulesBinding;
|
1703
|
+
unsigned int result = peekAction(handle, &rulesBinding, &reply);
|
1704
|
+
if (result != RULES_OK) {
|
1705
|
+
return result;
|
1706
|
+
}
|
1707
|
+
|
1708
|
+
*state = reply->element[1]->str;
|
1709
|
+
*messages = reply->element[2]->str;
|
1710
|
+
actionContext *context = malloc(sizeof(actionContext));
|
1711
|
+
context->reply = reply;
|
1712
|
+
context->rulesBinding = rulesBinding;
|
1713
|
+
*actionHandle = context;
|
1714
|
+
*actionBinding = rulesBinding;
|
1715
|
+
return RULES_OK;
|
1716
|
+
}
|
1717
|
+
|
1718
|
+
unsigned int startUpdateState(void *handle,
|
1719
|
+
void *actionHandle,
|
1720
|
+
char *state,
|
1721
|
+
void **rulesBinding,
|
1722
|
+
unsigned int *replyCount) {
|
1723
|
+
char *commands[MAX_COMMAND_COUNT];
|
1724
|
+
unsigned int result = RULES_OK;
|
1725
|
+
unsigned int commandCount = 0;
|
1726
|
+
result = handleState(handle,
|
1727
|
+
state,
|
1728
|
+
commands,
|
1729
|
+
&commandCount,
|
1730
|
+
rulesBinding);
|
1731
|
+
if (result != RULES_OK && result != ERR_EVENT_NOT_HANDLED) {
|
1732
|
+
//reply object should be freed by the app during abandonAction
|
1733
|
+
freeCommands(commands, commandCount);
|
1734
|
+
return result;
|
1735
|
+
}
|
1736
|
+
|
1737
|
+
result = startNonBlockingBatch(*rulesBinding, commands, commandCount, replyCount);
|
1738
|
+
return result;
|
1739
|
+
|
1740
|
+
}
|
1741
|
+
|
1742
|
+
unsigned int completeAction(void *handle,
|
1743
|
+
void *actionHandle,
|
1744
|
+
char *state) {
|
1745
|
+
char *commands[MAX_COMMAND_COUNT];
|
1746
|
+
unsigned int commandCount = 0;
|
1747
|
+
actionContext *context = (actionContext*)actionHandle;
|
1748
|
+
redisReply *reply = context->reply;
|
1749
|
+
void *rulesBinding = context->rulesBinding;
|
1750
|
+
|
1751
|
+
unsigned int result = formatRemoveAction(rulesBinding,
|
1752
|
+
reply->element[0]->str,
|
1753
|
+
&commands[commandCount]);
|
1754
|
+
if (result != RULES_OK) {
|
1755
|
+
//reply object should be freed by the app during abandonAction
|
1756
|
+
return result;
|
1757
|
+
}
|
1758
|
+
|
1759
|
+
++commandCount;
|
1760
|
+
result = handleState(handle,
|
1761
|
+
state,
|
1762
|
+
commands,
|
1763
|
+
&commandCount,
|
1764
|
+
&rulesBinding);
|
1765
|
+
if (result != RULES_OK && result != ERR_EVENT_NOT_HANDLED) {
|
1766
|
+
//reply object should be freed by the app during abandonAction
|
1767
|
+
freeCommands(commands, commandCount);
|
1768
|
+
return result;
|
1769
|
+
}
|
1770
|
+
|
1771
|
+
result = executeBatch(rulesBinding, commands, commandCount);
|
1772
|
+
freeReplyObject(reply);
|
1773
|
+
free(actionHandle);
|
1774
|
+
return result;
|
1775
|
+
}
|
1776
|
+
|
1777
|
+
unsigned int completeAndStartAction(void *handle,
|
1778
|
+
unsigned int expectedReplies,
|
1779
|
+
void *actionHandle,
|
1780
|
+
char **messages) {
|
1781
|
+
char *commands[MAX_COMMAND_COUNT];
|
1782
|
+
unsigned int commandCount = 0;
|
1783
|
+
actionContext *context = (actionContext*)actionHandle;
|
1784
|
+
redisReply *reply = context->reply;
|
1785
|
+
void *rulesBinding = context->rulesBinding;
|
1786
|
+
|
1787
|
+
unsigned int result = formatRemoveAction(rulesBinding,
|
1788
|
+
reply->element[0]->str,
|
1789
|
+
&commands[commandCount]);
|
1790
|
+
if (result != RULES_OK) {
|
1791
|
+
//reply object should be freed by the app during abandonAction
|
1792
|
+
return result;
|
1793
|
+
}
|
1794
|
+
|
1795
|
+
++commandCount;
|
1796
|
+
if (commandCount == MAX_COMMAND_COUNT) {
|
1797
|
+
//reply object should be freed by the app during abandonAction
|
1798
|
+
freeCommands(commands, commandCount);
|
1799
|
+
return ERR_MAX_COMMAND_COUNT;
|
1800
|
+
}
|
1801
|
+
|
1802
|
+
result = formatPeekAction(rulesBinding,
|
1803
|
+
reply->element[0]->str,
|
1804
|
+
&commands[commandCount]);
|
1805
|
+
if (result != RULES_OK) {
|
1806
|
+
//reply object should be freed by the app during abandonAction
|
1807
|
+
freeCommands(commands, commandCount);
|
1808
|
+
return result;
|
1809
|
+
}
|
1810
|
+
|
1811
|
+
++commandCount;
|
1812
|
+
redisReply *newReply;
|
1813
|
+
result = executeBatchWithReply(rulesBinding,
|
1814
|
+
expectedReplies,
|
1815
|
+
commands,
|
1816
|
+
commandCount,
|
1817
|
+
&newReply);
|
1818
|
+
if (result != RULES_OK) {
|
1819
|
+
//reply object should be freed by the app during abandonAction
|
1820
|
+
return result;
|
1821
|
+
}
|
1822
|
+
|
1823
|
+
freeReplyObject(reply);
|
1824
|
+
if (newReply == NULL) {
|
1825
|
+
free(actionHandle);
|
1826
|
+
return ERR_NO_ACTION_AVAILABLE;
|
1827
|
+
}
|
1828
|
+
|
1829
|
+
*messages = newReply->element[1]->str;
|
1830
|
+
context->reply = newReply;
|
1831
|
+
return RULES_OK;
|
1832
|
+
}
|
1833
|
+
|
1834
|
+
unsigned int abandonAction(void *handle, void *actionHandle) {
|
1835
|
+
freeReplyObject(((actionContext*)actionHandle)->reply);
|
1836
|
+
free(actionHandle);
|
1837
|
+
return RULES_OK;
|
1838
|
+
}
|
1839
|
+
|
1840
|
+
unsigned int startTimer(void *handle, char *sid, unsigned int duration, char *timer) {
|
1841
|
+
void *rulesBinding;
|
1842
|
+
unsigned int result = resolveBinding(handle, sid, &rulesBinding);
|
1843
|
+
if (result != RULES_OK) {
|
1844
|
+
return result;
|
1845
|
+
}
|
1846
|
+
|
1847
|
+
return registerTimer(rulesBinding, duration, timer);
|
1848
|
+
}
|