durable_rules 0.31.1
Sign up to get free protection for your applications and to get access to all the features.
- 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/src/rules/rete.h
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
#include "state.h"
|
2
|
+
|
3
|
+
#define OP_NOP 0
|
4
|
+
#define OP_LT 0x01
|
5
|
+
#define OP_LTE 0x02
|
6
|
+
#define OP_GT 0x03
|
7
|
+
#define OP_GTE 0x04
|
8
|
+
#define OP_EQ 0x05
|
9
|
+
#define OP_NEQ 0x06
|
10
|
+
#define OP_EX 0x07
|
11
|
+
#define OP_NEX 0x08
|
12
|
+
#define OP_ALL 0x09
|
13
|
+
#define OP_ANY 0x0A
|
14
|
+
#define OP_OR 0x0B
|
15
|
+
#define OP_AND 0x0C
|
16
|
+
#define OP_END 0x0D
|
17
|
+
#define OP_ADD 0x0E
|
18
|
+
#define OP_SUB 0x0F
|
19
|
+
#define OP_MUL 0x10
|
20
|
+
#define OP_DIV 0x11
|
21
|
+
#define OP_TYPE 0x12
|
22
|
+
#define OP_NOT 0x13
|
23
|
+
|
24
|
+
#define NODE_ALPHA 0
|
25
|
+
#define NODE_BETA_CONNECTOR 1
|
26
|
+
#define NODE_ACTION 2
|
27
|
+
#define NODE_M_OFFSET 0
|
28
|
+
|
29
|
+
typedef struct reference {
|
30
|
+
unsigned int hash;
|
31
|
+
unsigned int nameOffset;
|
32
|
+
unsigned int idOffset;
|
33
|
+
} reference;
|
34
|
+
|
35
|
+
typedef struct jsonValue {
|
36
|
+
unsigned char type;
|
37
|
+
union {
|
38
|
+
long i;
|
39
|
+
double d;
|
40
|
+
unsigned char b;
|
41
|
+
unsigned int stringOffset;
|
42
|
+
unsigned int idiomOffset;
|
43
|
+
reference property;
|
44
|
+
} value;
|
45
|
+
} jsonValue;
|
46
|
+
|
47
|
+
typedef struct idiom {
|
48
|
+
unsigned char operator;
|
49
|
+
jsonValue left;
|
50
|
+
jsonValue right;
|
51
|
+
} idiom;
|
52
|
+
|
53
|
+
typedef struct expression {
|
54
|
+
unsigned int nameOffset;
|
55
|
+
unsigned int aliasOffset;
|
56
|
+
unsigned short termsLength;
|
57
|
+
unsigned char not;
|
58
|
+
union {
|
59
|
+
unsigned int termsOffset;
|
60
|
+
unsigned int *termsPointer;
|
61
|
+
} t;
|
62
|
+
} expression;
|
63
|
+
|
64
|
+
typedef struct join {
|
65
|
+
unsigned int expressionsOffset;
|
66
|
+
unsigned short expressionsLength;
|
67
|
+
} join;
|
68
|
+
|
69
|
+
typedef struct alpha {
|
70
|
+
unsigned int hash;
|
71
|
+
unsigned char operator;
|
72
|
+
unsigned int betaListOffset;
|
73
|
+
unsigned int nextListOffset;
|
74
|
+
unsigned int nextOffset;
|
75
|
+
jsonValue right;
|
76
|
+
} alpha;
|
77
|
+
|
78
|
+
typedef struct betaConnector {
|
79
|
+
unsigned int hash;
|
80
|
+
unsigned int nextOffset;
|
81
|
+
unsigned char not;
|
82
|
+
} betaConnector;
|
83
|
+
|
84
|
+
typedef struct action {
|
85
|
+
unsigned int index;
|
86
|
+
unsigned short span;
|
87
|
+
unsigned short count;
|
88
|
+
unsigned short cap;
|
89
|
+
unsigned int partitionBy;
|
90
|
+
unsigned short priority;
|
91
|
+
unsigned int joinsOffset;
|
92
|
+
unsigned short joinsLength;
|
93
|
+
} action;
|
94
|
+
|
95
|
+
typedef struct node {
|
96
|
+
unsigned int nameOffset;
|
97
|
+
unsigned char type;
|
98
|
+
union {
|
99
|
+
alpha a;
|
100
|
+
betaConnector b;
|
101
|
+
action c;
|
102
|
+
} value;
|
103
|
+
} node;
|
104
|
+
|
105
|
+
typedef struct ruleset {
|
106
|
+
unsigned int nameOffset;
|
107
|
+
node *nodePool;
|
108
|
+
unsigned int nodeOffset;
|
109
|
+
unsigned int *nextPool;
|
110
|
+
unsigned int nextOffset;
|
111
|
+
char *stringPool;
|
112
|
+
unsigned int stringPoolLength;
|
113
|
+
expression *expressionPool;
|
114
|
+
unsigned int expressionOffset;
|
115
|
+
idiom *idiomPool;
|
116
|
+
unsigned int idiomOffset;
|
117
|
+
join *joinPool;
|
118
|
+
unsigned int joinOffset;
|
119
|
+
unsigned int actionCount;
|
120
|
+
void *bindingsList;
|
121
|
+
unsigned int *stateBuckets;
|
122
|
+
unsigned int stateBucketsLength;
|
123
|
+
stateEntry *state;
|
124
|
+
unsigned int maxStateLength;
|
125
|
+
unsigned int stateLength;
|
126
|
+
unsigned int lruStateOffset;
|
127
|
+
unsigned int mruStateOffset;
|
128
|
+
unsigned int orNodeOffset;
|
129
|
+
unsigned int andNodeOffset;
|
130
|
+
unsigned int endNodeOffset;
|
131
|
+
} ruleset;
|
132
|
+
|
133
|
+
|
data/src/rules/rules.h
ADDED
@@ -0,0 +1,171 @@
|
|
1
|
+
|
2
|
+
#define RULES_OK 0
|
3
|
+
#define ERR_OUT_OF_MEMORY 1
|
4
|
+
#define ERR_UNEXPECTED_TYPE 2
|
5
|
+
#define ERR_IDENTIFIER_LENGTH 3
|
6
|
+
#define ERR_UNEXPECTED_VALUE 4
|
7
|
+
#define ERR_UNEXPECTED_NAME 5
|
8
|
+
#define ERR_RULE_LIMIT_EXCEEDED 6
|
9
|
+
#define ERR_RULE_EXISTS_LIMIT_EXCEEDED 7
|
10
|
+
#define ERR_RULE_BETA_LIMIT_EXCEEDED 8
|
11
|
+
#define ERR_RULE_WITHOUT_QUALIFIER 9
|
12
|
+
#define ERR_SETTING_NOT_FOUND 10
|
13
|
+
#define ERR_PARSE_VALUE 101
|
14
|
+
#define ERR_PARSE_STRING 102
|
15
|
+
#define ERR_PARSE_NUMBER 103
|
16
|
+
#define ERR_PARSE_OBJECT 104
|
17
|
+
#define ERR_PARSE_ARRAY 105
|
18
|
+
#define ERR_EVENT_NOT_HANDLED 201
|
19
|
+
#define ERR_EVENT_MAX_PROPERTIES 202
|
20
|
+
#define ERR_MAX_STACK_SIZE 203
|
21
|
+
#define ERR_NO_ID_DEFINED 204
|
22
|
+
#define ERR_INVALID_ID 205
|
23
|
+
#define ERR_PARSE_PATH 206
|
24
|
+
#define ERR_MAX_NODE_RESULTS 207
|
25
|
+
#define ERR_MAX_RESULT_NODES 208
|
26
|
+
#define ERR_MAX_COMMAND_COUNT 209
|
27
|
+
#define ERR_MAX_ADD_COUNT 210
|
28
|
+
#define ERR_MAX_EVAL_COUNT 211
|
29
|
+
#define ERR_CONNECT_REDIS 301
|
30
|
+
#define ERR_REDIS_ERROR 302
|
31
|
+
#define ERR_NO_ACTION_AVAILABLE 303
|
32
|
+
#define ERR_NO_TIMERS_AVAILABLE 304
|
33
|
+
#define ERR_NEW_SESSION 305
|
34
|
+
#define ERR_STATE_CACHE_FULL 401
|
35
|
+
#define ERR_BINDING_NOT_MAPPED 402
|
36
|
+
#define ERR_STATE_NOT_LOADED 403
|
37
|
+
#define ERR_STALE_STATE 404
|
38
|
+
#define ERR_PROPERTY_NOT_FOUND 405
|
39
|
+
|
40
|
+
#define NEXT_BUCKET_LENGTH 512
|
41
|
+
#define NEXT_LIST_LENGTH 32
|
42
|
+
#define BETA_LIST_LENGTH 16
|
43
|
+
#define HASH_MASK 0x1F
|
44
|
+
|
45
|
+
#ifdef __cplusplus
|
46
|
+
extern "C" {
|
47
|
+
#endif
|
48
|
+
|
49
|
+
unsigned int createRuleset(void **handle,
|
50
|
+
char *name,
|
51
|
+
char *rules,
|
52
|
+
unsigned int stateCaheSize);
|
53
|
+
|
54
|
+
unsigned int deleteRuleset(void *handle);
|
55
|
+
|
56
|
+
unsigned int bindRuleset(void *handle,
|
57
|
+
char *host,
|
58
|
+
unsigned int port,
|
59
|
+
char *password);
|
60
|
+
|
61
|
+
unsigned int complete(void *rulesBinding,
|
62
|
+
unsigned int replyCount);
|
63
|
+
|
64
|
+
unsigned int assertEvent(void *handle,
|
65
|
+
char *message);
|
66
|
+
|
67
|
+
unsigned int startAssertEvent(void *handle,
|
68
|
+
char *message,
|
69
|
+
void **rulesBinding,
|
70
|
+
unsigned int *replyCount);
|
71
|
+
|
72
|
+
unsigned int assertEvents(void *handle,
|
73
|
+
char *messages,
|
74
|
+
unsigned int *resultsLength,
|
75
|
+
unsigned int **results);
|
76
|
+
|
77
|
+
unsigned int startAssertEvents(void *handle,
|
78
|
+
char *messages,
|
79
|
+
unsigned int *resultsLength,
|
80
|
+
unsigned int **results,
|
81
|
+
void **rulesBinding,
|
82
|
+
unsigned int *replyCount);
|
83
|
+
|
84
|
+
unsigned int retractEvent(void *handle,
|
85
|
+
char *message);
|
86
|
+
|
87
|
+
unsigned int startAssertFact(void *handle,
|
88
|
+
char *message,
|
89
|
+
void **rulesBinding,
|
90
|
+
unsigned int *replyCount);
|
91
|
+
|
92
|
+
unsigned int assertFact(void *handle,
|
93
|
+
char *message);
|
94
|
+
|
95
|
+
unsigned int startAssertFacts(void *handle,
|
96
|
+
char *messages,
|
97
|
+
unsigned int *resultsLength,
|
98
|
+
unsigned int **results,
|
99
|
+
void **rulesBinding,
|
100
|
+
unsigned int *replyCount);
|
101
|
+
|
102
|
+
unsigned int assertFacts(void *handle,
|
103
|
+
char *messages,
|
104
|
+
unsigned int *resultsLength,
|
105
|
+
unsigned int **results);
|
106
|
+
|
107
|
+
unsigned int retractFact(void *handle,
|
108
|
+
char *message);
|
109
|
+
|
110
|
+
unsigned int startRetractFact(void *handle,
|
111
|
+
char *message,
|
112
|
+
void **rulesBinding,
|
113
|
+
unsigned int *replyCount);
|
114
|
+
|
115
|
+
unsigned int retractFacts(void *handle,
|
116
|
+
char *messages,
|
117
|
+
unsigned int *resultsLength,
|
118
|
+
unsigned int **results);
|
119
|
+
|
120
|
+
unsigned int startRetractFacts(void *handle,
|
121
|
+
char *messages,
|
122
|
+
unsigned int *resultsLength,
|
123
|
+
unsigned int **results,
|
124
|
+
void **rulesBinding,
|
125
|
+
unsigned int *replyCount);
|
126
|
+
|
127
|
+
unsigned int startUpdateState(void *handle,
|
128
|
+
void *actionHandle,
|
129
|
+
char *state,
|
130
|
+
void **rulesBinding,
|
131
|
+
unsigned int *replyCount);
|
132
|
+
|
133
|
+
unsigned int assertState(void *handle,
|
134
|
+
char *state);
|
135
|
+
|
136
|
+
unsigned int startAction(void *handle,
|
137
|
+
char **state,
|
138
|
+
char **messages,
|
139
|
+
void **actionHandle,
|
140
|
+
void **actionBinding);
|
141
|
+
|
142
|
+
unsigned int completeAction(void *handle,
|
143
|
+
void *actionHandle,
|
144
|
+
char *state);
|
145
|
+
|
146
|
+
unsigned int completeAndStartAction(void *handle,
|
147
|
+
unsigned int expectedReplies,
|
148
|
+
void *actionHandle,
|
149
|
+
char **messages);
|
150
|
+
|
151
|
+
unsigned int abandonAction(void *handle,
|
152
|
+
void *actionHandle);
|
153
|
+
|
154
|
+
unsigned int startTimer(void *handle,
|
155
|
+
char *sid,
|
156
|
+
unsigned int duration,
|
157
|
+
char *timer);
|
158
|
+
|
159
|
+
unsigned int assertTimers(void *handle);
|
160
|
+
|
161
|
+
unsigned int getState(void *handle,
|
162
|
+
char *sid,
|
163
|
+
char **state);
|
164
|
+
|
165
|
+
#ifdef _WIN32
|
166
|
+
int asprintf(char** ret, char* format, ...);
|
167
|
+
#endif
|
168
|
+
|
169
|
+
#ifdef __cplusplus
|
170
|
+
}
|
171
|
+
#endif
|
data/src/rules/state.c
ADDED
@@ -0,0 +1,412 @@
|
|
1
|
+
#include <stdio.h>
|
2
|
+
#include <stdlib.h>
|
3
|
+
#include <string.h>
|
4
|
+
#include <time.h>
|
5
|
+
#include "rules.h"
|
6
|
+
#include "json.h"
|
7
|
+
#include "net.h"
|
8
|
+
|
9
|
+
unsigned int djbHash(char *str, unsigned int len) {
|
10
|
+
unsigned int hash = 5381;
|
11
|
+
unsigned int i = 0;
|
12
|
+
|
13
|
+
for(i = 0; i < len; str++, i++) {
|
14
|
+
hash = ((hash << 5) + hash) + (*str);
|
15
|
+
}
|
16
|
+
|
17
|
+
return hash;
|
18
|
+
}
|
19
|
+
|
20
|
+
static unsigned int evictEntry(ruleset *tree) {
|
21
|
+
stateEntry *lruEntry = &tree->state[tree->lruStateOffset];
|
22
|
+
unsigned int lruBucket = lruEntry->sidHash % tree->stateBucketsLength;
|
23
|
+
unsigned int offset = tree->stateBuckets[lruBucket];
|
24
|
+
unsigned int lastOffset = UNDEFINED_HASH_OFFSET;
|
25
|
+
unsigned char found = 0;
|
26
|
+
while (!found) {
|
27
|
+
stateEntry *current = &tree->state[offset];
|
28
|
+
if (current->sidHash == lruEntry->sidHash) {
|
29
|
+
if (!strcmp(current->sid, lruEntry->sid)) {
|
30
|
+
if (lastOffset == UNDEFINED_HASH_OFFSET) {
|
31
|
+
tree->stateBuckets[lruBucket] = current->nextHashOffset;
|
32
|
+
} else {
|
33
|
+
tree->state[lastOffset].nextHashOffset = current->nextHashOffset;
|
34
|
+
}
|
35
|
+
|
36
|
+
if (current->state) {
|
37
|
+
free(current->state);
|
38
|
+
current->state = NULL;
|
39
|
+
}
|
40
|
+
|
41
|
+
free(current->sid);
|
42
|
+
current->sid = NULL;
|
43
|
+
found = 1;
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
lastOffset = offset;
|
48
|
+
offset = current->nextHashOffset;
|
49
|
+
}
|
50
|
+
|
51
|
+
unsigned int result = tree->lruStateOffset;
|
52
|
+
tree->lruStateOffset = lruEntry->nextLruOffset;
|
53
|
+
tree->state[tree->lruStateOffset].prevLruOffset = UNDEFINED_HASH_OFFSET;
|
54
|
+
return result;
|
55
|
+
}
|
56
|
+
|
57
|
+
static unsigned int addEntry(ruleset *tree, char *sid, unsigned int sidHash) {
|
58
|
+
unsigned newOffset;
|
59
|
+
if (tree->stateLength == tree->maxStateLength) {
|
60
|
+
newOffset = evictEntry(tree);
|
61
|
+
} else {
|
62
|
+
newOffset = tree->stateLength;
|
63
|
+
++tree->stateLength;
|
64
|
+
}
|
65
|
+
|
66
|
+
stateEntry *current = &tree->state[newOffset];
|
67
|
+
current->prevLruOffset = UNDEFINED_HASH_OFFSET;
|
68
|
+
current->nextLruOffset = UNDEFINED_HASH_OFFSET;
|
69
|
+
current->nextHashOffset = UNDEFINED_HASH_OFFSET;
|
70
|
+
current->sid = malloc(strlen(sid) + 1);
|
71
|
+
strcpy(current->sid, sid);
|
72
|
+
current->sidHash = sidHash;
|
73
|
+
unsigned int bucket = sidHash % tree->stateBucketsLength;
|
74
|
+
unsigned int offset = tree->stateBuckets[bucket];
|
75
|
+
if (offset == UNDEFINED_HASH_OFFSET) {
|
76
|
+
tree->stateBuckets[bucket] = newOffset;
|
77
|
+
}
|
78
|
+
else {
|
79
|
+
while (1) {
|
80
|
+
current = &tree->state[offset];
|
81
|
+
if (current->nextHashOffset == UNDEFINED_HASH_OFFSET) {
|
82
|
+
current->nextHashOffset = newOffset;
|
83
|
+
break;
|
84
|
+
}
|
85
|
+
|
86
|
+
offset = current->nextHashOffset;
|
87
|
+
}
|
88
|
+
}
|
89
|
+
|
90
|
+
return newOffset;
|
91
|
+
}
|
92
|
+
|
93
|
+
static unsigned char ensureEntry(ruleset *tree, char *sid, unsigned int sidHash, stateEntry **result) {
|
94
|
+
unsigned int bucket = sidHash % tree->stateBucketsLength;
|
95
|
+
unsigned int offset = tree->stateBuckets[bucket];
|
96
|
+
stateEntry *current = NULL;
|
97
|
+
unsigned char found = 0;
|
98
|
+
while (offset != UNDEFINED_HASH_OFFSET) {
|
99
|
+
current = &tree->state[offset];
|
100
|
+
if (current->sidHash == sidHash) {
|
101
|
+
if (!strcmp(current->sid, sid)) {
|
102
|
+
found = 1;
|
103
|
+
break;
|
104
|
+
}
|
105
|
+
}
|
106
|
+
|
107
|
+
offset = current->nextHashOffset;
|
108
|
+
}
|
109
|
+
if (offset == UNDEFINED_HASH_OFFSET) {
|
110
|
+
offset = addEntry(tree, sid, sidHash);
|
111
|
+
current = &tree->state[offset];
|
112
|
+
}
|
113
|
+
|
114
|
+
if (current->prevLruOffset != UNDEFINED_HASH_OFFSET) {
|
115
|
+
tree->state[current->prevLruOffset].nextLruOffset = current->nextLruOffset;
|
116
|
+
}
|
117
|
+
|
118
|
+
if (current->nextLruOffset != UNDEFINED_HASH_OFFSET) {
|
119
|
+
tree->state[current->nextLruOffset].prevLruOffset = current->prevLruOffset;
|
120
|
+
}
|
121
|
+
|
122
|
+
current->prevLruOffset = tree->mruStateOffset;
|
123
|
+
current->nextLruOffset = UNDEFINED_HASH_OFFSET;
|
124
|
+
if (tree->mruStateOffset == UNDEFINED_HASH_OFFSET) {
|
125
|
+
tree->lruStateOffset = offset;
|
126
|
+
} else {
|
127
|
+
tree->state[tree->mruStateOffset].nextLruOffset = offset;
|
128
|
+
}
|
129
|
+
|
130
|
+
tree->mruStateOffset = offset;
|
131
|
+
*result = current;
|
132
|
+
return found;
|
133
|
+
}
|
134
|
+
|
135
|
+
static stateEntry *getEntry(ruleset *tree, char *sid, unsigned int sidHash) {
|
136
|
+
unsigned int bucket = sidHash % tree->stateBucketsLength;
|
137
|
+
unsigned int offset = tree->stateBuckets[bucket];
|
138
|
+
while (offset != UNDEFINED_HASH_OFFSET) {
|
139
|
+
stateEntry *current = &tree->state[offset];
|
140
|
+
if (current->sidHash == sidHash) {
|
141
|
+
if (!strcmp(current->sid, sid)) {
|
142
|
+
return current;
|
143
|
+
}
|
144
|
+
}
|
145
|
+
|
146
|
+
offset = current->nextHashOffset;
|
147
|
+
}
|
148
|
+
|
149
|
+
return NULL;
|
150
|
+
}
|
151
|
+
|
152
|
+
unsigned int constructObject(char *parentName,
|
153
|
+
char *object,
|
154
|
+
char createHashtable,
|
155
|
+
unsigned int maxProperties,
|
156
|
+
jsonProperty *properties,
|
157
|
+
unsigned int *propertiesLength,
|
158
|
+
unsigned int *midIndex,
|
159
|
+
unsigned int *sidIndex,
|
160
|
+
char **next) {
|
161
|
+
char *firstName;
|
162
|
+
char *lastName;
|
163
|
+
char *first;
|
164
|
+
char *last;
|
165
|
+
unsigned char type;
|
166
|
+
unsigned int hash;
|
167
|
+
int parentNameLength = (parentName ? strlen(parentName): 0);
|
168
|
+
unsigned int result = readNextName(object, &firstName, &lastName, &hash);
|
169
|
+
while (result == PARSE_OK) {
|
170
|
+
result = readNextValue(lastName, &first, &last, &type);
|
171
|
+
if (result != PARSE_OK) {
|
172
|
+
return result;
|
173
|
+
}
|
174
|
+
|
175
|
+
if (!parentName) {
|
176
|
+
if (type == JSON_OBJECT) {
|
177
|
+
int nameLength = lastName - firstName;
|
178
|
+
#ifdef _WIN32
|
179
|
+
char *newParent = (char *)_alloca(sizeof(char)*(nameLength + 1));
|
180
|
+
#else
|
181
|
+
char newParent[nameLength + 1];
|
182
|
+
#endif
|
183
|
+
strncpy(newParent, firstName, nameLength);
|
184
|
+
newParent[nameLength] = '\0';
|
185
|
+
return constructObject(newParent,
|
186
|
+
first,
|
187
|
+
createHashtable,
|
188
|
+
maxProperties,
|
189
|
+
properties,
|
190
|
+
propertiesLength,
|
191
|
+
midIndex,
|
192
|
+
sidIndex,
|
193
|
+
next);
|
194
|
+
}
|
195
|
+
} else {
|
196
|
+
int nameLength = lastName - firstName;
|
197
|
+
int fullNameLength = nameLength + parentNameLength + 1;
|
198
|
+
#ifdef _WIN32
|
199
|
+
char *fullName = (char *)_alloca(sizeof(char)*(fullNameLength + 1));
|
200
|
+
#else
|
201
|
+
char fullName[fullNameLength + 1];
|
202
|
+
#endif
|
203
|
+
strncpy(fullName, firstName, nameLength);
|
204
|
+
fullName[nameLength] = '.';
|
205
|
+
strncpy(&fullName[nameLength + 1], parentName, parentNameLength);
|
206
|
+
fullName[fullNameLength] = '\0';
|
207
|
+
hash = djbHash(fullName, fullNameLength);
|
208
|
+
if (type == JSON_OBJECT) {
|
209
|
+
return constructObject(fullName,
|
210
|
+
first,
|
211
|
+
createHashtable,
|
212
|
+
maxProperties,
|
213
|
+
properties,
|
214
|
+
propertiesLength,
|
215
|
+
midIndex,
|
216
|
+
sidIndex,
|
217
|
+
next);
|
218
|
+
}
|
219
|
+
}
|
220
|
+
|
221
|
+
jsonProperty *property = NULL;
|
222
|
+
if (!createHashtable) {
|
223
|
+
property = &properties[*propertiesLength];
|
224
|
+
if (hash == HASH_ID) {
|
225
|
+
*midIndex = *propertiesLength;
|
226
|
+
} else if (hash == HASH_SID) {
|
227
|
+
*sidIndex = *propertiesLength;
|
228
|
+
}
|
229
|
+
} else {
|
230
|
+
unsigned int candidate = hash % maxProperties;
|
231
|
+
while (properties[candidate].type != 0) {
|
232
|
+
candidate = (candidate + 1) % maxProperties;
|
233
|
+
}
|
234
|
+
|
235
|
+
if (hash == HASH_ID) {
|
236
|
+
*midIndex = candidate;
|
237
|
+
} else if (hash == HASH_SID) {
|
238
|
+
*sidIndex = candidate;
|
239
|
+
}
|
240
|
+
|
241
|
+
property = &properties[candidate];
|
242
|
+
}
|
243
|
+
|
244
|
+
|
245
|
+
|
246
|
+
*propertiesLength = *propertiesLength + 1;
|
247
|
+
if (*propertiesLength == maxProperties) {
|
248
|
+
return ERR_EVENT_MAX_PROPERTIES;
|
249
|
+
}
|
250
|
+
|
251
|
+
property->isMaterial = 0;
|
252
|
+
property->hash = hash;
|
253
|
+
property->valueOffset = first - object;
|
254
|
+
property->valueLength = last - first;
|
255
|
+
property->nameOffset = firstName - object;
|
256
|
+
property->nameLength = lastName - firstName;
|
257
|
+
property->type = type;
|
258
|
+
*next = last;
|
259
|
+
result = readNextName(last, &firstName, &lastName, &hash);
|
260
|
+
}
|
261
|
+
|
262
|
+
return (result == PARSE_END ? RULES_OK: result);
|
263
|
+
}
|
264
|
+
|
265
|
+
void rehydrateProperty(jsonProperty *property, char *state) {
|
266
|
+
// ID and SID are treated as strings regardless of type
|
267
|
+
// to avoid unnecessary conversions
|
268
|
+
if (!property->isMaterial && property->hash != HASH_ID && property->hash != HASH_SID) {
|
269
|
+
unsigned short propertyLength = property->valueLength + 1;
|
270
|
+
char *propertyFirst = state + property->valueOffset;
|
271
|
+
unsigned char propertyType = property->type;
|
272
|
+
unsigned char b = 0;
|
273
|
+
char temp;
|
274
|
+
|
275
|
+
switch(propertyType) {
|
276
|
+
case JSON_INT:
|
277
|
+
temp = propertyFirst[propertyLength];
|
278
|
+
propertyFirst[propertyLength] = '\0';
|
279
|
+
property->value.i = atol(propertyFirst);
|
280
|
+
propertyFirst[propertyLength] = temp;
|
281
|
+
break;
|
282
|
+
case JSON_DOUBLE:
|
283
|
+
temp = propertyFirst[propertyLength];
|
284
|
+
propertyFirst[propertyLength] = '\0';
|
285
|
+
property->value.d = atof(propertyFirst);
|
286
|
+
propertyFirst[propertyLength] = temp;
|
287
|
+
break;
|
288
|
+
case JSON_BOOL:
|
289
|
+
if (propertyLength == 4 && strncmp("true", propertyFirst, 4) == 0) {
|
290
|
+
b = 1;
|
291
|
+
}
|
292
|
+
|
293
|
+
property->value.b = b;
|
294
|
+
break;
|
295
|
+
}
|
296
|
+
|
297
|
+
property->isMaterial = 1;
|
298
|
+
}
|
299
|
+
}
|
300
|
+
|
301
|
+
static unsigned int resolveBindingAndEntry(ruleset *tree,
|
302
|
+
char *sid,
|
303
|
+
stateEntry **entry,
|
304
|
+
void **rulesBinding) {
|
305
|
+
unsigned int sidHash = djbHash(sid, strlen(sid));
|
306
|
+
if (!ensureEntry(tree, sid, sidHash, entry)) {
|
307
|
+
unsigned int result = getBindingIndex(tree, sidHash, &(*entry)->bindingIndex);
|
308
|
+
if (result != RULES_OK) {
|
309
|
+
return result;
|
310
|
+
}
|
311
|
+
}
|
312
|
+
|
313
|
+
bindingsList *list = tree->bindingsList;
|
314
|
+
*rulesBinding = &list->bindings[(*entry)->bindingIndex];
|
315
|
+
return RULES_OK;
|
316
|
+
}
|
317
|
+
|
318
|
+
unsigned int resolveBinding(void *handle,
|
319
|
+
char *sid,
|
320
|
+
void **rulesBinding) {
|
321
|
+
stateEntry *entry = NULL;
|
322
|
+
return resolveBindingAndEntry(handle, sid, &entry, rulesBinding);
|
323
|
+
}
|
324
|
+
|
325
|
+
unsigned int refreshState(void *handle,
|
326
|
+
char *sid) {
|
327
|
+
unsigned int result;
|
328
|
+
stateEntry *entry = NULL;
|
329
|
+
void *rulesBinding;
|
330
|
+
result = resolveBindingAndEntry(handle, sid, &entry, &rulesBinding);
|
331
|
+
if (result != RULES_OK) {
|
332
|
+
return result;
|
333
|
+
}
|
334
|
+
|
335
|
+
if (entry->state) {
|
336
|
+
free(entry->state);
|
337
|
+
entry->state = NULL;
|
338
|
+
}
|
339
|
+
|
340
|
+
result = getSession(rulesBinding, sid, &entry->state);
|
341
|
+
if (result != RULES_OK) {
|
342
|
+
if (result == ERR_NEW_SESSION) {
|
343
|
+
entry->lastRefresh = time(NULL);
|
344
|
+
}
|
345
|
+
return result;
|
346
|
+
}
|
347
|
+
|
348
|
+
memset(entry->properties, 0, MAX_STATE_PROPERTIES * sizeof(jsonProperty));
|
349
|
+
entry->propertiesLength = 0;
|
350
|
+
char *next;
|
351
|
+
unsigned int midIndex = UNDEFINED_INDEX;
|
352
|
+
unsigned int sidIndex = UNDEFINED_INDEX;
|
353
|
+
result = constructObject(NULL,
|
354
|
+
entry->state,
|
355
|
+
1,
|
356
|
+
MAX_STATE_PROPERTIES,
|
357
|
+
entry->properties,
|
358
|
+
&entry->propertiesLength,
|
359
|
+
&midIndex,
|
360
|
+
&sidIndex,
|
361
|
+
&next);
|
362
|
+
if (result != RULES_OK) {
|
363
|
+
return result;
|
364
|
+
}
|
365
|
+
|
366
|
+
entry->lastRefresh = time(NULL);
|
367
|
+
return RULES_OK;
|
368
|
+
}
|
369
|
+
|
370
|
+
unsigned int fetchStateProperty(void *tree,
|
371
|
+
char *sid,
|
372
|
+
unsigned int propertyHash,
|
373
|
+
unsigned int maxTime,
|
374
|
+
unsigned char ignoreStaleState,
|
375
|
+
char **state,
|
376
|
+
jsonProperty **property) {
|
377
|
+
unsigned int sidHash = djbHash(sid, strlen(sid));
|
378
|
+
stateEntry *entry = getEntry(tree, sid, sidHash);
|
379
|
+
if (entry == NULL || entry->lastRefresh == 0) {
|
380
|
+
return ERR_STATE_NOT_LOADED;
|
381
|
+
}
|
382
|
+
|
383
|
+
if (!ignoreStaleState && (time(NULL) - entry->lastRefresh > maxTime)) {
|
384
|
+
return ERR_STALE_STATE;
|
385
|
+
}
|
386
|
+
|
387
|
+
unsigned int propertyIndex = propertyHash % MAX_STATE_PROPERTIES;
|
388
|
+
jsonProperty *result = &entry->properties[propertyIndex];
|
389
|
+
while (result->type != 0 && result->hash != propertyHash) {
|
390
|
+
propertyIndex = (propertyIndex + 1) % MAX_STATE_PROPERTIES;
|
391
|
+
result = &entry->properties[propertyIndex];
|
392
|
+
}
|
393
|
+
|
394
|
+
if (!result->type) {
|
395
|
+
return ERR_PROPERTY_NOT_FOUND;
|
396
|
+
}
|
397
|
+
|
398
|
+
*state = entry->state;
|
399
|
+
rehydrateProperty(result, *state);
|
400
|
+
*property = result;
|
401
|
+
return RULES_OK;
|
402
|
+
}
|
403
|
+
|
404
|
+
unsigned int getState(void *handle, char *sid, char **state) {
|
405
|
+
void *rulesBinding = NULL;
|
406
|
+
unsigned int result = resolveBinding(handle, sid, &rulesBinding);
|
407
|
+
if (result != RULES_OK) {
|
408
|
+
return result;
|
409
|
+
}
|
410
|
+
|
411
|
+
return getSession(rulesBinding, sid, state);
|
412
|
+
}
|