durable_rules 0.34.10 → 0.34.11

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 17af99e481ae4e0bcb1b2ebe209b6e5edc18fee9
4
- data.tar.gz: cb8dd76e247553ece6ddc1e07b55c73185472a84
3
+ metadata.gz: 1a1c33ac9771e6fd5a65c237fa9ec44043ee2efa
4
+ data.tar.gz: 92da33c1378bccefc450cf31d0bbff11301fa2e8
5
5
  SHA512:
6
- metadata.gz: 6e850df050e57f8d9c3a6afe9e95290dcda77a15822b653b0a4dd65dfc379ebf2f78fcf3139a84817250671031ef502ff3aa53c6ebb9d637d8c08ba972c7ab5f
7
- data.tar.gz: 11c23e9dffe070addf470d6a5535dc4c964892c1674a047981c525009614ca5134af25b2553152885483542c3403285692da9fd013f32a17ccde565a1ef4c739
6
+ metadata.gz: e1557c00a12d9eff3c8d4d0b35c0e6efacf2928f2e1435eb873978e279af3a2f6f9f3b33d82bae98a2a10607469bf218ec942cc6a106f13cc5115d3c12ddb429
7
+ data.tar.gz: def1bedb13771e6f5546c5043933019cb36f1706293eb8afd79d97a05803dad5366765e085d87098aaa271a4d2e7b5834aeb261aed8bfad84f2b89f7b4893ec8
data/librb/durable.rb CHANGED
@@ -178,7 +178,7 @@ module Durable
178
178
  @__name = nil
179
179
  end
180
180
 
181
- def definition
181
+ def definition(parent_name=nil)
182
182
  new_definition = nil
183
183
  if @__op == :$or || @__op == :$and
184
184
  new_definition = {@__op => @definitions}
@@ -297,25 +297,33 @@ module Durable
297
297
  @expressions = expressions
298
298
  end
299
299
 
300
- def definition
300
+ def definition(parent_name=nil)
301
301
  index = 0
302
302
  new_definition = []
303
303
  for expression in @expressions do
304
304
  if (expression.kind_of? Expression) && expression.__name
305
305
  expression_name = expression.__name
306
306
  elsif @expressions.length == 1
307
- expression_name = "m"
307
+ if parent_name
308
+ expression_name = "#{parent_name}.m"
309
+ else
310
+ expression_name = "m"
311
+ end
308
312
  else
309
- expression_name = "m_#{index}"
313
+ if parent_name
314
+ expression_name = "#{parent_name}.m_#{index}"
315
+ else
316
+ expression_name = "m_#{index}"
317
+ end
310
318
  end
311
319
  if expression.__type == :$all
312
- new_definition << {expression_name + "$all" => expression.definition()}
320
+ new_definition << {expression_name + "$all" => expression.definition(expression_name)}
313
321
  elsif expression.__type == :$any
314
- new_definition << {expression_name + "$any" => expression.definition()}
322
+ new_definition << {expression_name + "$any" => expression.definition(expression_name)}
315
323
  elsif expression.__type == :$not
316
324
  new_definition << {expression_name + "$not" => expression.definition()[0]["m"]}
317
325
  else
318
- new_definition << {expression_name => expression.definition()}
326
+ new_definition << {expression_name => expression.definition(expression_name)}
319
327
  end
320
328
  index += 1
321
329
  end
data/librb/engine.rb CHANGED
@@ -495,7 +495,11 @@ module Engine
495
495
  end
496
496
 
497
497
  def assert_state(state)
498
- Rules.assert_state @handle, JSON.generate(state)
498
+ if state.key? :sid
499
+ Rules.assert_state @handle, state[:sid].to_s, JSON.generate(state)
500
+ else
501
+ Rules.assert_state @handle, state["sid"].to_s, JSON.generate(state)
502
+ end
499
503
  end
500
504
 
501
505
  def get_state(sid)
data/src/rules/events.c CHANGED
@@ -33,6 +33,7 @@
33
33
  #define OP_STRING_STRING 0x0101
34
34
 
35
35
  typedef struct actionContext {
36
+ unsigned long stateVersion;
36
37
  void *rulesBinding;
37
38
  redisReply *reply;
38
39
  } actionContext;
@@ -1029,6 +1030,7 @@ static unsigned int handleMessageCore(ruleset *tree,
1029
1030
  jsonProperty *sidProperty;
1030
1031
  int sidLength;
1031
1032
  char *storeCommand;
1033
+ char *versionCommand;
1032
1034
  int result = getId(properties, sidIndex, &sidProperty, &sidLength);
1033
1035
  if (result != RULES_OK) {
1034
1036
  return result;
@@ -1064,17 +1066,20 @@ static unsigned int handleMessageCore(ruleset *tree,
1064
1066
  }
1065
1067
  }
1066
1068
 
1067
- if (*commandCount == MAX_COMMAND_COUNT) {
1068
- return ERR_MAX_COMMAND_COUNT;
1069
- }
1070
-
1071
- result = formatStoreSession(*rulesBinding, sid, state, 0, &storeCommand);
1069
+ result = formatStoreSession(*rulesBinding, sid, state, 0, &storeCommand, &versionCommand);
1072
1070
  if (result != RULES_OK) {
1073
1071
  return result;
1074
1072
  }
1075
1073
 
1076
1074
  commands[*commandCount] = storeCommand;
1077
1075
  ++*commandCount;
1076
+
1077
+ if (*commandCount == MAX_COMMAND_COUNT) {
1078
+ return ERR_MAX_COMMAND_COUNT;
1079
+ }
1080
+
1081
+ commands[*commandCount] = versionCommand;
1082
+ ++*commandCount;
1078
1083
  }
1079
1084
  char *removeCommand = NULL;
1080
1085
  char *addKeys[MAX_ADD_COUNT];
@@ -1220,7 +1225,7 @@ static unsigned int handleMessageCore(ruleset *tree,
1220
1225
  return ERR_MAX_COMMAND_COUNT;
1221
1226
  }
1222
1227
 
1223
- result = formatStoreSession(*rulesBinding, sid, newState, 1, &storeCommand);
1228
+ result = formatStoreSession(*rulesBinding, sid, newState, 1, &storeCommand, &versionCommand);
1224
1229
  if (result != RULES_OK) {
1225
1230
  return result;
1226
1231
  }
@@ -1228,6 +1233,13 @@ static unsigned int handleMessageCore(ruleset *tree,
1228
1233
  commands[*commandCount] = storeCommand;
1229
1234
  ++*commandCount;
1230
1235
 
1236
+ if (*commandCount == MAX_COMMAND_COUNT) {
1237
+ return ERR_MAX_COMMAND_COUNT;
1238
+ }
1239
+
1240
+ commands[*commandCount] = versionCommand;
1241
+ ++*commandCount;
1242
+
1231
1243
  result = handleMessage(tree,
1232
1244
  NULL,
1233
1245
  stateMessage,
@@ -1362,7 +1374,8 @@ static unsigned int handleMessages(void *handle,
1362
1374
  }
1363
1375
 
1364
1376
  static unsigned int handleState(ruleset *tree,
1365
- char *state,
1377
+ char *state,
1378
+ unsigned long stateVersion,
1366
1379
  char **commands,
1367
1380
  unsigned int *commandCount,
1368
1381
  void **rulesBinding) {
@@ -1377,15 +1390,15 @@ static unsigned int handleState(ruleset *tree,
1377
1390
 
1378
1391
  char *stateMessagePostfix = state + 1;
1379
1392
  #ifdef _WIN32
1380
- char *stateMessage = (char *)_alloca(sizeof(char)*(35 + stateLength - 1));
1393
+ char *stateMessage = (char *)_alloca(sizeof(char)*(40 + stateLength - 1));
1381
1394
  #else
1382
- char stateMessage[35 + stateLength - 1];
1395
+ char stateMessage[40 + stateLength - 1];
1383
1396
  #endif
1384
- int randomMid = rand();
1397
+
1385
1398
  #ifdef _WIN32
1386
- sprintf_s(stateMessage, 35 + stateLength - 1, "{\"id\":\"$v-%d\", \"$s\":1, %s", randomMid, stateMessagePostfix);
1399
+ sprintf_s(stateMessage, 40 + stateLength - 1, "{\"id\":\"$v-%016lu\", \"$s\":1, %s", stateVersion, stateMessagePostfix);
1387
1400
  #else
1388
- snprintf(stateMessage, 35 + stateLength - 1, "{\"id\":\"$v-%d\", \"$s\":1, %s", randomMid, stateMessagePostfix);
1401
+ snprintf(stateMessage, 40 + stateLength - 1, "{\"id\":\"$v-%016lu\", \"$s\":1, %s", stateVersion, stateMessagePostfix);
1389
1402
  #endif
1390
1403
  unsigned int result = handleMessage(tree,
1391
1404
  state,
@@ -1638,15 +1651,22 @@ unsigned int startRetractFacts(void *handle,
1638
1651
  return startHandleMessages(handle, messages, ACTION_REMOVE_FACT, rulesBinding, replyCount);
1639
1652
  }
1640
1653
 
1641
- unsigned int assertState(void *handle, char *state) {
1654
+ unsigned int assertState(void *handle, char *sid, char *state) {
1642
1655
  char *commands[MAX_COMMAND_COUNT];
1643
1656
  unsigned int commandCount = 0;
1644
1657
  void *rulesBinding = NULL;
1645
- unsigned int result = handleState(handle,
1646
- state,
1647
- commands,
1648
- &commandCount,
1649
- &rulesBinding);
1658
+ unsigned long stateVersion;
1659
+ unsigned int result = getStateVersion(handle, sid, &stateVersion);
1660
+ if (result != RULES_OK) {
1661
+ return result;
1662
+ }
1663
+
1664
+ result = handleState(handle,
1665
+ state,
1666
+ stateVersion,
1667
+ commands,
1668
+ &commandCount,
1669
+ &rulesBinding);
1650
1670
  if (result != RULES_OK && result != ERR_EVENT_NOT_HANDLED) {
1651
1671
  freeCommands(commands, commandCount);
1652
1672
  return result;
@@ -1693,13 +1713,14 @@ unsigned int startAction(void *handle,
1693
1713
  return result;
1694
1714
  }
1695
1715
 
1696
- *state = reply->element[1]->str;
1697
- *messages = reply->element[2]->str;
1716
+ *state = reply->element[2]->str;
1717
+ *messages = reply->element[3]->str;
1698
1718
  actionContext *context = malloc(sizeof(actionContext));
1699
1719
  if (!context) {
1700
1720
  return ERR_OUT_OF_MEMORY;
1701
1721
  }
1702
1722
 
1723
+ context->stateVersion = reply->element[1]->integer;
1703
1724
  context->reply = reply;
1704
1725
  context->rulesBinding = rulesBinding;
1705
1726
  *actionHandle = context;
@@ -1715,8 +1736,10 @@ unsigned int startUpdateState(void *handle,
1715
1736
  char *commands[MAX_COMMAND_COUNT];
1716
1737
  unsigned int result = RULES_OK;
1717
1738
  unsigned int commandCount = 0;
1739
+ unsigned long stateVersion = ((actionContext*)actionHandle)->stateVersion;
1718
1740
  result = handleState(handle,
1719
1741
  state,
1742
+ stateVersion,
1720
1743
  commands,
1721
1744
  &commandCount,
1722
1745
  rulesBinding);
@@ -1750,7 +1773,8 @@ unsigned int completeAction(void *handle,
1750
1773
 
1751
1774
  ++commandCount;
1752
1775
  result = handleState(handle,
1753
- state,
1776
+ state,
1777
+ context->stateVersion,
1754
1778
  commands,
1755
1779
  &commandCount,
1756
1780
  &rulesBinding);
@@ -1823,7 +1847,8 @@ unsigned int completeAndStartAction(void *handle,
1823
1847
  return ERR_NO_ACTION_AVAILABLE;
1824
1848
  }
1825
1849
 
1826
- *messages = newReply->element[1]->str;
1850
+ *messages = newReply->element[2]->str;
1851
+ context->stateVersion = newReply->element[1]->integer;
1827
1852
  context->reply = newReply;
1828
1853
  return RULES_OK;
1829
1854
  }
data/src/rules/net.c CHANGED
@@ -528,11 +528,13 @@ static unsigned int loadDeleteSessionCommand(ruleset *tree, binding *rulesBindin
528
528
  " end\n"
529
529
  "end\n"
530
530
  "redis.call(\"hdel\", \"%s!s\", sid)\n"
531
+ "redis.call(\"hdel\", \"%s!s!v\", sid)\n"
531
532
  "redis.call(\"zrem\", \"%s!a\", sid)\n"
532
533
  "redis.call(\"del\", \"%s!a!\" .. sid)\n"
533
534
  "redis.call(\"del\", \"%s!e!\" .. sid)\n"
534
535
  "redis.call(\"del\", \"%s!f!\" .. sid)\n"
535
536
  "redis.call(\"del\", \"%s!v!\" .. sid)\n%s",
537
+ name,
536
538
  name,
537
539
  name,
538
540
  name,
@@ -661,6 +663,10 @@ static unsigned int loadAddMessageCommand(ruleset *tree, binding *rulesBinding)
661
663
  " else\n"
662
664
  " message[ARGV[index]] = false\n"
663
665
  " end\n"
666
+ " elseif ARGV[index + 2] == \"5\" then\n"
667
+ " message[ARGV[index]] = cjson.decode(ARGV[index + 1])\n"
668
+ " elseif ARGV[index + 2] == \"7\" then\n"
669
+ " message[ARGV[index]] = \"$null\"\n"
664
670
  " end\n"
665
671
  "end\n"
666
672
  "local mid = message[\"id\"]\n"
@@ -763,8 +769,9 @@ static unsigned int loadPeekActionCommand(ruleset *tree, binding *rulesBinding)
763
769
  for (unsigned int iii = 0; iii < currentJoin->expressionsLength; ++iii) {
764
770
  unsigned int expressionOffset = tree->nextPool[currentJoin->expressionsOffset + iii];
765
771
  expression *expr = &tree->expressionPool[expressionOffset];
766
- char *currentAlias = &tree->stringPool[expr->aliasOffset];
767
772
  char *currentKey = &tree->stringPool[expr->nameOffset];
773
+ char *currentAlias = &tree->stringPool[expr->aliasOffset];
774
+
768
775
 
769
776
  if (iii == 0) {
770
777
  if (expr->not) {
@@ -1083,13 +1090,23 @@ static unsigned int loadPeekActionCommand(ruleset *tree, binding *rulesBinding)
1083
1090
  " return sid, name, frame\n"
1084
1091
  "end\n"
1085
1092
  "local fixup_frame = function(frame)\n"
1093
+ " local new_frame = {}\n"
1086
1094
  " for message_name, message in pairs(frame) do\n"
1087
- " if message ~= \"$n\" then\n"
1095
+ " if message_name == 1 then\n"
1096
+ " return frame\n"
1097
+ " end\n"
1098
+ " local start\n"
1099
+ " local name\n"
1100
+ " local next\n"
1101
+ " local new_message = {}\n"
1102
+ " if message == \"$n\" then\n"
1103
+ " new_message = message\n"
1104
+ " else\n"
1088
1105
  " for key, value in pairs(message) do\n"
1089
- " local start = 1\n"
1090
- " local sub_message = message\n"
1091
- " local name = key\n"
1092
- " local next = nil\n"
1106
+ " local sub_message = new_message\n"
1107
+ " start = 1\n"
1108
+ " name = key\n"
1109
+ " next = nil\n"
1093
1110
  " repeat\n"
1094
1111
  " next = string.find(key, \"%%.\", start)\n"
1095
1112
  " if next then\n"
@@ -1106,12 +1123,36 @@ static unsigned int loadPeekActionCommand(ruleset *tree, binding *rulesBinding)
1106
1123
  " name = string.sub(key, start)\n"
1107
1124
  " end\n"
1108
1125
  " until not next\n"
1109
- " message[key] = nil\n"
1110
- " sub_message[name] = value\n"
1126
+ " if value == \"$null\" then\n"
1127
+ " sub_message[name] = cjson.null\n"
1128
+ " else\n"
1129
+ " sub_message[name] = value\n"
1130
+ " end\n"
1111
1131
  " end\n"
1112
1132
  " end\n"
1133
+ " local sub_frame = new_frame\n"
1134
+ " name = message_name\n"
1135
+ " next = nil\n"
1136
+ " start = 1\n"
1137
+ " repeat\n"
1138
+ " next = string.find(message_name, \"%%.\", start)\n"
1139
+ " if next then\n"
1140
+ " name = string.sub(message_name, start, next - 1)\n"
1141
+ " if sub_frame[name] then\n"
1142
+ " sub_frame = sub_frame[name]\n"
1143
+ " else\n"
1144
+ " local new_sub_frame = {}\n"
1145
+ " sub_frame[name] = new_sub_frame\n"
1146
+ " sub_frame = new_sub_frame\n"
1147
+ " end\n"
1148
+ " start = next + 1\n"
1149
+ " else\n"
1150
+ " name = string.sub(message_name, start)\n"
1151
+ " end\n"
1152
+ " until not next\n"
1153
+ " sub_frame[name] = new_message\n"
1113
1154
  " end\n"
1114
- " return frame\n"
1155
+ " return new_frame\n"
1115
1156
  "end\n"
1116
1157
  "get_context = function(action_key)\n"
1117
1158
  " if context_directory[action_key] then\n"
@@ -1128,11 +1169,12 @@ static unsigned int loadPeekActionCommand(ruleset *tree, binding *rulesBinding)
1128
1169
  "end\n"
1129
1170
  "if frame then\n"
1130
1171
  " redis.call(\"zadd\", action_key, tonumber(ARGV[1]), new_sid)\n"
1172
+ " local state_version = redis.call(\"hget\", state_key .. \"!v\", new_sid)\n"
1131
1173
  " if #ARGV == 2 then\n"
1132
1174
  " local state = redis.call(\"hget\", state_key, new_sid)\n"
1133
- " return {new_sid, state, cjson.encode({[action_name] = fixup_frame(frame)})}\n"
1175
+ " return {new_sid, tonumber(state_version), state, cjson.encode({[action_name] = fixup_frame(frame)})}\n"
1134
1176
  " else\n"
1135
- " return {new_sid, cjson.encode({[action_name] = fixup_frame(frame)})}\n"
1177
+ " return {new_sid, tonumber(state_version), cjson.encode({[action_name] = fixup_frame(frame)})}\n"
1136
1178
  " end\n"
1137
1179
  "end\n",
1138
1180
  name,
@@ -1168,7 +1210,7 @@ static unsigned int loadEvalMessageCommand(ruleset *tree, binding *rulesBinding)
1168
1210
  char *lua = NULL;
1169
1211
  char *oldLua;
1170
1212
 
1171
- #ifdef _WIN32
1213
+ #ifdef _WIN32
1172
1214
  char *actionKey = (char *)_alloca(sizeof(char)*(nameLength + 3));
1173
1215
  sprintf_s(actionKey, nameLength + 3, "%s!a", name);
1174
1216
  #else
@@ -1206,6 +1248,7 @@ static unsigned int loadEvalMessageCommand(ruleset *tree, binding *rulesBinding)
1206
1248
  oldLua = lua;
1207
1249
  if (asprintf(&lua,
1208
1250
  "%stoggle = false\n"
1251
+ "context_directory = {}\n"
1209
1252
  "context = {}\n"
1210
1253
  "reviewers = {}\n"
1211
1254
  "context[\"reviewers\"] = reviewers\n"
@@ -1236,9 +1279,10 @@ static unsigned int loadEvalMessageCommand(ruleset *tree, binding *rulesBinding)
1236
1279
  for (unsigned int iii = 0; iii < currentJoin->expressionsLength; ++iii) {
1237
1280
  unsigned int expressionOffset = tree->nextPool[currentJoin->expressionsOffset + iii];
1238
1281
  expression *expr = &tree->expressionPool[expressionOffset];
1239
- char *currentAlias = &tree->stringPool[expr->aliasOffset];
1240
1282
  char *currentKey = &tree->stringPool[expr->nameOffset];
1283
+ char *currentAlias = &tree->stringPool[expr->aliasOffset];
1241
1284
  char *nextKeyTest;
1285
+
1242
1286
  if (iii == (currentJoin->expressionsLength - 1)) {
1243
1287
  nextKeyTest = (char*)calloc(1, sizeof(char));
1244
1288
  if (!nextKeyTest) {
@@ -1384,6 +1428,7 @@ static unsigned int loadEvalMessageCommand(ruleset *tree, binding *rulesBinding)
1384
1428
  char *test = NULL;
1385
1429
  char *primaryKeyLua = NULL;
1386
1430
  char *primaryFrameKeyLua = NULL;
1431
+
1387
1432
  unsigned int result = createTest(tree, expr, &test, &primaryKeyLua, &primaryFrameKeyLua);
1388
1433
  if (result != RULES_OK) {
1389
1434
  return result;
@@ -1569,6 +1614,9 @@ static unsigned int loadEvalMessageCommand(ruleset *tree, binding *rulesBinding)
1569
1614
  "%sif toggle then\n"
1570
1615
  " context[\"process_key\"] = process_key_with_span\n"
1571
1616
  " context[\"process_key_count\"] = %d\n"
1617
+ " if not process_message(message) then\n"
1618
+ " return\n"
1619
+ " end\n"
1572
1620
  "end\n",
1573
1621
  lua,
1574
1622
  currentNode->value.c.span) == -1) {
@@ -1582,6 +1630,9 @@ static unsigned int loadEvalMessageCommand(ruleset *tree, binding *rulesBinding)
1582
1630
  "%sif toggle then\n"
1583
1631
  " context[\"process_key\"] = process_key_with_cap\n"
1584
1632
  " context[\"process_key_count\"] = %d\n"
1633
+ " if not process_message(message) then\n"
1634
+ " return\n"
1635
+ " end\n"
1585
1636
  "end\n",
1586
1637
  lua,
1587
1638
  currentNode->value.c.cap) == -1) {
@@ -1595,6 +1646,9 @@ static unsigned int loadEvalMessageCommand(ruleset *tree, binding *rulesBinding)
1595
1646
  "%sif toggle then\n"
1596
1647
  " context[\"process_key\"] = process_key_with_window\n"
1597
1648
  " context[\"process_key_count\"] = %d\n"
1649
+ " if not process_message(message) then\n"
1650
+ " return\n"
1651
+ " end\n"
1598
1652
  "end\n",
1599
1653
  lua,
1600
1654
  currentNode->value.c.count) == -1) {
@@ -1998,6 +2052,41 @@ static unsigned int loadEvalMessageCommand(ruleset *tree, binding *rulesBinding)
1998
2052
  " end\n"
1999
2053
  " return queue_lock\n"
2000
2054
  "end\n"
2055
+ "local process_message = function(message)\n"
2056
+ " for index = 6, 5 + keys_count, 1 do\n"
2057
+ " results = {}\n"
2058
+ " unpacked_results = {}\n"
2059
+ " key = ARGV[index]\n"
2060
+ " context = context_directory[key]\n"
2061
+ " if context then\n"
2062
+ " keys = context[\"keys\"]\n"
2063
+ " reviewers = context[\"reviewers\"]\n"
2064
+ " frame_packers = context[\"frame_packers\"]\n"
2065
+ " frame_unpackers = context[\"frame_unpackers\"]\n"
2066
+ " primary_message_keys = context[\"primary_message_keys\"]\n"
2067
+ " primary_frame_keys = context[\"primary_frame_keys\"]\n"
2068
+ " directory = context[\"directory\"]\n"
2069
+ " results_key = context[\"results_key\"]\n"
2070
+ " inverse_directory = context[\"inverse_directory\"]\n"
2071
+ " expressions_count = context[\"expressions_count\"]\n"
2072
+ " local process_key = context[\"process_key\"]\n"
2073
+ " local process_key_count = context[\"process_key_count\"]\n"
2074
+ " queue_action = process_key(message, process_key_count) or queue_action\n"
2075
+ " if assert_fact == 0 and events_message_cache[tostring(message[\"id\"])] == false then\n"
2076
+ " break\n"
2077
+ " end\n"
2078
+ " end\n"
2079
+ " end\n"
2080
+ " if queue_action then\n"
2081
+ " if not redis.call(\"zscore\", actions_key, sid) then\n"
2082
+ " redis.call(\"zadd\", actions_key , score, sid)\n"
2083
+ " end\n"
2084
+ " if assert_fact == 0 then\n"
2085
+ " return false\n"
2086
+ " end\n"
2087
+ " end\n"
2088
+ " return true\n"
2089
+ "end\n"
2001
2090
  "local message = nil\n"
2002
2091
  "if #ARGV > (6 + keys_count) then\n"
2003
2092
  " message = {}\n"
@@ -2012,6 +2101,10 @@ static unsigned int loadEvalMessageCommand(ruleset *tree, binding *rulesBinding)
2012
2101
  " else\n"
2013
2102
  " message[ARGV[index]] = false\n"
2014
2103
  " end\n"
2104
+ " elseif ARGV[index + 2] == \"5\" then\n"
2105
+ " message[ARGV[index]] = cjson.decode(ARGV[index + 1])\n"
2106
+ " elseif ARGV[index + 2] == \"7\" then\n"
2107
+ " message[ARGV[index]] = \"$null\"\n"
2015
2108
  " end\n"
2016
2109
  " end\n"
2017
2110
  " if assert_fact == 1 then\n"
@@ -2032,33 +2125,7 @@ static unsigned int loadEvalMessageCommand(ruleset *tree, binding *rulesBinding)
2032
2125
  "for index = 6, 5 + keys_count, 1 do\n"
2033
2126
  " input_keys[ARGV[index]] = true\n"
2034
2127
  "end\n"
2035
- "%sfor index = 6, 5 + keys_count, 1 do\n"
2036
- " results = {}\n"
2037
- " unpacked_results = {}\n"
2038
- " key = ARGV[index]\n"
2039
- " context = context_directory[key]\n"
2040
- " keys = context[\"keys\"]\n"
2041
- " reviewers = context[\"reviewers\"]\n"
2042
- " frame_packers = context[\"frame_packers\"]\n"
2043
- " frame_unpackers = context[\"frame_unpackers\"]\n"
2044
- " primary_message_keys = context[\"primary_message_keys\"]\n"
2045
- " primary_frame_keys = context[\"primary_frame_keys\"]\n"
2046
- " directory = context[\"directory\"]\n"
2047
- " results_key = context[\"results_key\"]\n"
2048
- " inverse_directory = context[\"inverse_directory\"]\n"
2049
- " expressions_count = context[\"expressions_count\"]\n"
2050
- " local process_key = context[\"process_key\"]\n"
2051
- " local process_key_count = context[\"process_key_count\"]\n"
2052
- " queue_action = process_key(message, process_key_count) or queue_action\n"
2053
- " if assert_fact == 0 and events_message_cache[tostring(message[\"id\"])] == false then\n"
2054
- " break\n"
2055
- " end\n"
2056
- "end\n"
2057
- "if queue_action then\n"
2058
- " if not redis.call(\"zscore\", actions_key, sid) then\n"
2059
- " redis.call(\"zadd\", actions_key , score, sid)\n"
2060
- " end\n"
2061
- "end\n",
2128
+ "%s\n",
2062
2129
  name,
2063
2130
  name,
2064
2131
  name,
@@ -2493,22 +2560,40 @@ unsigned int formatStoreSession(void *rulesBinding,
2493
2560
  char *sid,
2494
2561
  char *state,
2495
2562
  unsigned char tryExists,
2496
- char **command) {
2563
+ char **storeCommand,
2564
+ char **versionCommand) {
2497
2565
  binding *currentBinding = (binding*)rulesBinding;
2498
2566
 
2499
2567
  int result;
2500
2568
  if (tryExists) {
2501
- result = redisFormatCommand(command,
2569
+ result = redisFormatCommand(storeCommand,
2502
2570
  "hsetnx %s %s %s",
2503
2571
  currentBinding->sessionHashset,
2504
2572
  sid,
2505
2573
  state);
2574
+ if (result == 0) {
2575
+ return ERR_OUT_OF_MEMORY;
2576
+ }
2577
+
2578
+ result = redisFormatCommand(versionCommand,
2579
+ "hsetnx %s!v %s 0",
2580
+ currentBinding->sessionHashset,
2581
+ sid);
2506
2582
  } else {
2507
- result = redisFormatCommand(command,
2583
+ result = redisFormatCommand(storeCommand,
2508
2584
  "hset %s %s %s",
2509
2585
  currentBinding->sessionHashset,
2510
2586
  sid,
2511
2587
  state);
2588
+
2589
+ if (result == 0) {
2590
+ return ERR_OUT_OF_MEMORY;
2591
+ }
2592
+
2593
+ result = redisFormatCommand(versionCommand,
2594
+ "hincrby %s!v %s 1",
2595
+ currentBinding->sessionHashset,
2596
+ sid);
2512
2597
  }
2513
2598
 
2514
2599
  if (result == 0) {
@@ -3028,6 +3113,38 @@ unsigned int getSession(void *rulesBinding, char *sid, char **state) {
3028
3113
  return REDIS_OK;
3029
3114
  }
3030
3115
 
3116
+ unsigned int getSessionVersion(void *rulesBinding, char *sid, unsigned long *stateVersion) {
3117
+ binding *currentBinding = (binding*)rulesBinding;
3118
+ redisContext *reContext = currentBinding->reContext;
3119
+ unsigned int result = redisAppendCommand(reContext,
3120
+ "hget %s!v %s",
3121
+ currentBinding->sessionHashset,
3122
+ sid);
3123
+ if (result != REDIS_OK) {
3124
+ return ERR_REDIS_ERROR;
3125
+ }
3126
+
3127
+ redisReply *reply;
3128
+ result = tryGetReply(reContext, &reply);
3129
+ if (result != RULES_OK) {
3130
+ return result;
3131
+ }
3132
+
3133
+ if (reply->type == REDIS_REPLY_ERROR) {
3134
+ freeReplyObject(reply);
3135
+ return ERR_REDIS_ERROR;
3136
+ }
3137
+
3138
+ if (reply->type != REDIS_REPLY_INTEGER) {
3139
+ *stateVersion = 0;
3140
+ } else {
3141
+ *stateVersion = reply->integer;
3142
+ }
3143
+
3144
+ freeReplyObject(reply);
3145
+ return REDIS_OK;
3146
+ }
3147
+
3031
3148
  unsigned int deleteSession(void *rulesBinding, char *sid) {
3032
3149
  binding *currentBinding = (binding*)rulesBinding;
3033
3150
  redisContext *reContext = currentBinding->reContext;
data/src/rules/net.h CHANGED
@@ -74,7 +74,8 @@ unsigned int formatStoreSession(void *rulesBinding,
74
74
  char *sid,
75
75
  char *state,
76
76
  unsigned char tryExists,
77
- char **command);
77
+ char **storeCommand,
78
+ char **versionCommand);
78
79
 
79
80
  unsigned int formatStoreSessionFact(void *rulesBinding,
80
81
  char *sid,
@@ -148,6 +149,10 @@ unsigned int getSession(void *rulesBinding,
148
149
  char *sid,
149
150
  char **state);
150
151
 
152
+ unsigned int getSessionVersion(void *rulesBinding,
153
+ char *sid,
154
+ unsigned long *stateVersion);
155
+
151
156
  unsigned int deleteSession(void *rulesBinding,
152
157
  char *sid);
153
158
 
data/src/rules/rules.h CHANGED
@@ -131,7 +131,8 @@ unsigned int startUpdateState(void *handle,
131
131
  void **rulesBinding,
132
132
  unsigned int *replyCount);
133
133
 
134
- unsigned int assertState(void *handle,
134
+ unsigned int assertState(void *handle,
135
+ char *sid,
135
136
  char *state);
136
137
 
137
138
  unsigned int startAction(void *handle,
data/src/rules/state.c CHANGED
@@ -453,6 +453,17 @@ unsigned int getState(void *handle, char *sid, char **state) {
453
453
  return getSession(rulesBinding, sid, state);
454
454
  }
455
455
 
456
+ unsigned int getStateVersion(void *handle, char *sid, unsigned long *stateVersion) {
457
+ void *rulesBinding = NULL;
458
+ unsigned int result = resolveBinding(handle, sid, &rulesBinding);
459
+ if (result != RULES_OK) {
460
+ return result;
461
+ }
462
+
463
+ return getSessionVersion(rulesBinding, sid, stateVersion);
464
+ }
465
+
466
+
456
467
  unsigned int deleteState(void *handle, char *sid) {
457
468
  void *rulesBinding = NULL;
458
469
  unsigned int result = resolveBinding(handle, sid, &rulesBinding);
data/src/rules/state.h CHANGED
@@ -57,3 +57,6 @@ unsigned int fetchStateProperty(void *tree,
57
57
  unsigned char ignoreStaleState,
58
58
  char **state,
59
59
  jsonProperty **property);
60
+ unsigned int getStateVersion(void *handle,
61
+ char *sid,
62
+ unsigned long *stateVersion);
data/src/rulesrb/rules.c CHANGED
@@ -420,11 +420,12 @@ static VALUE rbRetractFacts(VALUE self, VALUE handle, VALUE facts) {
420
420
  return Qnil;
421
421
  }
422
422
 
423
- static VALUE rbAssertState(VALUE self, VALUE handle, VALUE state) {
423
+ static VALUE rbAssertState(VALUE self, VALUE handle, VALUE sid, VALUE state) {
424
424
  Check_Type(handle, T_FIXNUM);
425
+ Check_Type(sid, T_STRING);
425
426
  Check_Type(state, T_STRING);
426
427
 
427
- unsigned int result = assertState((void *)FIX2LONG(handle), RSTRING_PTR(state));
428
+ unsigned int result = assertState((void *)FIX2LONG(handle), RSTRING_PTR(sid), RSTRING_PTR(state));
428
429
  if (result == RULES_OK || result == ERR_EVENT_NOT_HANDLED || result == ERR_EVENT_OBSERVED) {
429
430
  return INT2FIX(result);
430
431
  } else {
@@ -671,7 +672,7 @@ void Init_rules() {
671
672
  rb_define_singleton_method(rulesModule, "queue_retract_fact", rbQueueRetractFact, 4);
672
673
  rb_define_singleton_method(rulesModule, "start_retract_facts", rbStartRetractFacts, 2);
673
674
  rb_define_singleton_method(rulesModule, "retract_facts", rbRetractFacts, 2);
674
- rb_define_singleton_method(rulesModule, "assert_state", rbAssertState, 2);
675
+ rb_define_singleton_method(rulesModule, "assert_state", rbAssertState, 3);
675
676
  rb_define_singleton_method(rulesModule, "start_update_state", rbStartUpdateState, 3);
676
677
  rb_define_singleton_method(rulesModule, "start_action", rbStartAction, 1);
677
678
  rb_define_singleton_method(rulesModule, "complete_action", rbCompleteAction, 3);
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: durable_rules
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.34.10
4
+ version: 0.34.11
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jesus Ruiz
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-09-06 00:00:00.000000000 Z
11
+ date: 2016-09-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -129,7 +129,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
129
129
  version: '0'
130
130
  requirements: []
131
131
  rubyforge_project:
132
- rubygems_version: 2.0.14
132
+ rubygems_version: 2.0.14.1
133
133
  signing_key:
134
134
  specification_version: 4
135
135
  summary: for real time analytics (a Ruby Rules Engine)