public RulesEvaluationResult Evaluate(RuleApiModel rule, RawMessage message) { var result = new RulesEvaluationResult(); if (GroupContainsDevice(message.DeviceId, rule.GroupId)) { logger.Debug($"Evaluating rule {rule.Description} for device {message.DeviceId} with {rule.Conditions.Count()} conditions", () => { }); var descriptions = new List <string>(); foreach (var c in rule.Conditions) { var eval = EvaluateCondition(c, message); // perf: all conditions must match, break as soon as one doesn't if (!eval.Match) { return(result); } descriptions.Add(eval.Message); } result.Match = true; result.Message = string.Join("; ", descriptions); } else { logger.Debug($"Skipping rule {rule.Description} because device {message.DeviceId} doesn't belong to group {rule.GroupId}", () => { }); } return(result); }
private RulesEvaluationResult EvaluateCondition( ConditionApiModel condition, RawMessage message) { var r = new RulesEvaluationResult(); var field = condition.Field; object value; if (!message.PayloadData.TryGetValue(field, out value)) { logger.Debug($"Message payload doesn't contain field {field}", () => { }); return(r); } OperatorLogic logic; if (!OperatorLogicLookup.TryGetValue(condition.Operator.ToLowerInvariant(), out logic)) { logger.Error("Unknown operator", () => new { condition }); return(r); } switch (Type.GetTypeCode(value.GetType())) { case TypeCode.SByte: case TypeCode.Byte: case TypeCode.Int16: case TypeCode.UInt16: case TypeCode.Int32: case TypeCode.UInt32: case TypeCode.Int64: case TypeCode.UInt64: case TypeCode.Single: case TypeCode.Double: case TypeCode.Decimal: { var actualValue = Convert.ToDouble(value); var threshold = Convert.ToDouble(condition.Value); logger.Debug($"Field {field}, Value {actualValue}, Operator {condition.Operator}, Threshold {threshold}", () => { }); if (logic.DoubleTestFunc(actualValue, threshold)) { r.Match = true; r.Message = string.Format(logic.Message, field, actualValue, threshold); } } break; case TypeCode.String: { var actualValue = value.ToString(); var threshold = condition.Value; logger.Debug($"Field {field}, Value '{actualValue}', Operator {condition.Operator}, Threshold '{threshold}'", () => { }); if (logic.StringTestFunc(actualValue, threshold)) { r.Match = true; r.Message = string.Format(logic.Message, field, actualValue, threshold); } } break; default: logger.Error($"Unknown type for `{field}` value sent by device {message.DeviceId}", () => { }); break; } return(r); }