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/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
|
+
}
|