From f8528cccaed633c608fd817529bdffe22024a0b0 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Wed, 16 Jun 2021 18:22:13 +0300 Subject: [PATCH] Added *len dataconverter --- engine/filters.go | 75 +++++++++++++-------------------------- engine/filters_test.go | 39 ++++++++++++++++++++ packages/debian/changelog | 1 + utils/consts.go | 1 + utils/dataconverter.go | 19 ++++++++++ 5 files changed, 84 insertions(+), 51 deletions(-) diff --git a/engine/filters.go b/engine/filters.go index 19d2729af..7ada25855 100644 --- a/engine/filters.go +++ b/engine/filters.go @@ -505,32 +505,22 @@ func (fltr *FilterRule) passRSR(dDP utils.DataProvider) (bool, error) { } func (fltr *FilterRule) passGreaterThan(dDP utils.DataProvider) (bool, error) { - path, err := fltr.rsrElement.CompileDynRule(dDP) - if err != nil { - return false, err - } - fldIf, err := utils.DPDynamicInterface(path, dDP) + fldStr, err := fltr.rsrElement.ParseDataProviderWithInterfaces(dDP) if err != nil { if err == utils.ErrNotFound { return false, nil } return false, err } - if fldStr, castStr := fldIf.(string); castStr { // attempt converting string since deserialization fails here (ie: time.Time fields) - fldIf = utils.StringToInterface(fldStr) - } + fldIf := utils.StringToInterface(fldStr) orEqual := fltr.Type == utils.MetaGreaterOrEqual || fltr.Type == utils.MetaLessThan for _, val := range fltr.rsrValues { - valPath, err := val.CompileDynRule(dDP) + sval, err := val.ParseDataProviderWithInterfaces(dDP) if err != nil { continue } - sval, err := utils.DPDynamicInterface(valPath, dDP) - if err != nil { - continue - } - if gte, err := utils.GreaterThan(fldIf, sval, orEqual); err != nil { + if gte, err := utils.GreaterThan(fldIf, utils.StringToInterface(sval), orEqual); err != nil { return false, err } else if (utils.MetaGreaterThan == fltr.Type || utils.MetaGreaterOrEqual == fltr.Type) && gte { return true, nil @@ -542,30 +532,20 @@ func (fltr *FilterRule) passGreaterThan(dDP utils.DataProvider) (bool, error) { } func (fltr *FilterRule) passEqualTo(dDP utils.DataProvider) (bool, error) { - path, err := fltr.rsrElement.CompileDynRule(dDP) - if err != nil { - return false, err - } - fldIf, err := utils.DPDynamicInterface(path, dDP) + fldStr, err := fltr.rsrElement.ParseDataProviderWithInterfaces(dDP) if err != nil { if err == utils.ErrNotFound { return false, nil } return false, err } - if fldStr, castStr := fldIf.(string); castStr { // attempt converting string since deserialization fails here (ie: time.Time fields) - fldIf = utils.StringToInterface(fldStr) - } + fldIf := utils.StringToInterface(fldStr) for _, val := range fltr.rsrValues { - valPath, err := val.CompileDynRule(dDP) - if err != nil { - return false, err - } - sval, err := utils.DPDynamicInterface(valPath, dDP) + sval, err := val.ParseDataProviderWithInterfaces(dDP) if err != nil { continue } - if eq, err := utils.EqualTo(fldIf, sval); err != nil { + if eq, err := utils.EqualTo(fldIf, utils.StringToInterface(sval)); err != nil { return false, err } else if eq { return true, nil @@ -618,49 +598,42 @@ func (fltr *FilterRule) passAPIBan(ctx *context.Context, dDP utils.DataProvider) return dm.GetAPIBan(ctx, strVal, config.CgrConfig().APIBanCfg().Keys, fltr.Values[0] != utils.MetaAll, true, true) } +func parseTime(rsr *config.RSRParser, dDp utils.DataProvider) (_ time.Time, err error) { + var str string + if str, err = rsr.ParseDataProvider(dDp); err != nil { + return + } + return utils.ParseTimeDetectLayout(str, config.CgrConfig().GeneralCfg().DefaultTimezone) +} + func (fltr *FilterRule) passActivationInterval(dDp utils.DataProvider) (bool, error) { - strVal, err := fltr.rsrElement.ParseDataProvider(dDp) + timeVal, err := parseTime(fltr.rsrElement, dDp) if err != nil { if err == utils.ErrNotFound { return false, nil } return false, err } - timeStrVal, err := utils.ParseTimeDetectLayout(strVal, config.CgrConfig().GeneralCfg().DefaultTimezone) - if err != nil { - return false, err - } + if len(fltr.rsrValues) == 2 { - val2, err := fltr.rsrValues[1].CompileDynRule(dDp) - if err != nil { - return false, err - } - endTime, err := utils.ParseTimeDetectLayout(val2, config.CgrConfig().GeneralCfg().DefaultTimezone) + endTime, err := parseTime(fltr.rsrValues[1], dDp) if err != nil { return false, err } if fltr.rsrValues[0] == nil { - return timeStrVal.Before(endTime), nil + return timeVal.Before(endTime), nil } - val1, err := fltr.rsrValues[0].CompileDynRule(dDp) + startTime, err := parseTime(fltr.rsrValues[0], dDp) if err != nil { return false, err } - startTime, err := utils.ParseTimeDetectLayout(val1, config.CgrConfig().GeneralCfg().DefaultTimezone) - if err != nil { - return false, err - } - return startTime.Before(timeStrVal) && timeStrVal.Before(endTime), nil + return startTime.Before(timeVal) && timeVal.Before(endTime), nil } - val1, err := fltr.rsrValues[0].CompileDynRule(dDp) + startTime, err := parseTime(fltr.rsrValues[0], dDp) if err != nil { return false, err } - startTime, err := utils.ParseTimeDetectLayout(val1, config.CgrConfig().GeneralCfg().DefaultTimezone) - if err != nil { - return false, err - } - return startTime.Before(timeStrVal), nil + return startTime.Before(timeVal), nil } func verifyInlineFilterS(fltrs []string) (err error) { diff --git a/engine/filters_test.go b/engine/filters_test.go index eabd5c679..8b4473601 100644 --- a/engine/filters_test.go +++ b/engine/filters_test.go @@ -525,6 +525,26 @@ func TestInlineFilterPassFiltersForEvent(t *testing.T) { } else if pass { t.Errorf("Expecting: %+v, received: %+v", false, pass) } + + pEv = utils.MapStorage{utils.MetaReq: utils.MapStorage{utils.AccountField: "sip:12345678901234567@abcdefg"}} + if pass, err := filterS.Pass(context.TODO(), "cgrates.org", + []string{"*regex:~*req.Account:.{29,}"}, pEv); err != nil { + t.Errorf(err.Error()) + } else if !pass { + t.Errorf("Expecting: %+v, received: %+v", true, pass) + } + if pass, err := filterS.Pass(context.TODO(), "cgrates.org", + []string{"*regex:~*req.Account:^.{28}$"}, pEv); err != nil { + t.Errorf(err.Error()) + } else if pass { + t.Errorf("Expecting: %+v, received: %+v", false, pass) + } + if pass, err := filterS.Pass(context.TODO(), "cgrates.org", + []string{"*gte:~*req.Account{*len}:29"}, pEv); err != nil { + t.Errorf(err.Error()) + } else if !pass { + t.Errorf("Expecting: %+v, received: %+v", true, pass) + } } func TestPassFiltersForEventWithEmptyFilter(t *testing.T) { @@ -1244,6 +1264,25 @@ func TestFilterPassCronExpParseExpErr(t *testing.T) { } } +func TestFiltersPassGreaterThanErrIncomparable(t *testing.T) { + fltr, err := NewFilterRule(utils.MetaGreaterThan, "~*req.Usage", []string{"10"}) + fltr.rsrElement.Rules = "rules" + if err != nil { + t.Fatal(err) + } + ev := utils.MapStorage{ + utils.MetaReq: map[string]interface{}{ + utils.Usage: nil, + }, + } + + if passes, err := fltr.passCronExp(context.Background(), ev); err != nil { + t.Errorf("Expected nil, got %+v", err) + } else if passes { + t.Error("should not be passing") + } +} + func TestFilterPassCronExpParseDPErr(t *testing.T) { fltr, err := NewFilterRule(utils.MetaCronExp, "~*req.AnswerTime", []string{"~* * * * *"}) if err != nil { diff --git a/packages/debian/changelog b/packages/debian/changelog index 7e8eba203..d9078447b 100644 --- a/packages/debian/changelog +++ b/packages/debian/changelog @@ -10,6 +10,7 @@ cgrates (1.0) UNRELEASED; urgency=medium * [SessionS] The sessions are no longer terminated on shutdown if the replication_conns are set * [FilterS] Added *regex filter * [DispatcherS] Removed Subsystems field in favor of filters + * [RSRParsers] Added *len dataconverter -- DanB Thu, 4 May 2021 12:05:00 +0200 diff --git a/utils/consts.go b/utils/consts.go index 1190b5367..66234fc8d 100644 --- a/utils/consts.go +++ b/utils/consts.go @@ -710,6 +710,7 @@ const ( MetaIP2Hex = "*ip2hex" MetaString2Hex = "*string2hex" MetaUnixTime = "*unixtime" + MetaLen = "*len" MetaSIPURIMethod = "*sipuri_method" MetaSIPURIHost = "*sipuri_host" MetaSIPURIUser = "*sipuri_user" diff --git a/utils/dataconverter.go b/utils/dataconverter.go index e88bcd9e5..2139a3bda 100644 --- a/utils/dataconverter.go +++ b/utils/dataconverter.go @@ -20,6 +20,7 @@ package utils import ( "encoding/hex" + "encoding/json" "fmt" "math/rand" "net" @@ -87,6 +88,8 @@ func NewDataConverter(params string) (conv DataConverter, err error) { return new(SIPURIMethodConverter), nil case params == MetaUnixTime: return new(UnixTimeConverter), nil + case params == MetaLen: + return new(LengthConverter), nil case strings.HasPrefix(params, MetaLibPhoneNumber): if len(params) == len(MetaLibPhoneNumber) { return NewPhoneNumberConverter(EmptyString) @@ -446,3 +449,19 @@ func (rC *RandomConverter) Convert(in interface{}) ( } } } + +// LengthConverter converts the interface in the unix time +type LengthConverter struct{} + +// Convert implements DataConverter interface +func (LengthConverter) Convert(in interface{}) (out interface{}, err error) { + src := IfaceAsString(in) + if strings.HasPrefix(src, IdxStart) && + strings.HasSuffix(src, IdxEnd) { // it has a similar structure to a json marshaled slice + var slice []interface{} + if err := json.Unmarshal([]byte(src), &slice); err == nil { // no error when unmarshal safe to asume that this is a slice + return len(slice), nil + } + } + return len(src), nil +}