RequestFilter with *rsr_fields type

This commit is contained in:
DanB
2016-07-14 16:03:16 +02:00
parent 2f71f1fdd9
commit 6f76c211d6
4 changed files with 135 additions and 14 deletions

View File

@@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>
package engine
import (
"errors"
"strings"
"github.com/cgrates/cgrates/utils"
@@ -28,18 +29,41 @@ import (
const (
MetaStringPrefix = "*string_prefix"
MetaTiming = "*timing"
MetaRSRFilters = "*rsr_filters"
MetaRSRFields = "*rsr_fields"
MetaCDRStats = "*cdr_stats"
MetaDestinations = "*destinations"
)
func NewRequestFilter(rfType, fieldName, vals string, tpDB RatingStorage, cdrStats rpcclient.RpcClientConnection) (*RequestFilter, error) {
rf := &RequestFilter{Type: rfType, FieldName: fieldName, Values: vals, tpDB: tpDB, cdrStats: cdrStats}
switch rfType {
case MetaTiming, MetaDestinations:
if tpDB == nil {
return nil, errors.New("Missing tpDB information")
}
case MetaCDRStats:
if cdrStats == nil {
return nil, errors.New("Missing cdrStats information")
}
case MetaRSRFields:
var err error
if rf.rsrFields, err = utils.ParseRSRFields(vals, utils.INFIELD_SEP); err != nil {
return nil, err
}
}
return rf, nil
}
// RequestFilter filters requests coming into various places
type RequestFilter struct {
Type string // Filter type (*string, *timing, *rsr_filters, *cdr_stats)
FieldName string // Name of the field providing us the value to check
Values string // Filter definition
rsrFltrVals []*utils.RSRFilter // Cache here the RSRFilter values
cdrStats rpcclient.RpcClientConnection // Connection towards CDRStats service (eg: for *cdr_stats type)
Type string // Filter type (*string, *timing, *rsr_filters, *cdr_stats)
FieldName string // Name of the field providing us the Values to check (used in case of some )
Values string // Filter definition
rsrFields utils.RSRFields // Cache here the RSRFilter Values
tpDB RatingStorage
dataDB AccountingStorage
cdrStats rpcclient.RpcClientConnection // Connection towards CDRStats service (eg: for *cdr_stats type)
}
func (fltr *RequestFilter) Pass(req interface{}, extraFieldsLabel string) (bool, error) {
@@ -50,8 +74,8 @@ func (fltr *RequestFilter) Pass(req interface{}, extraFieldsLabel string) (bool,
return fltr.passTiming(req, extraFieldsLabel)
case MetaDestinations:
return fltr.passDestinations(req, extraFieldsLabel)
case MetaRSRFilters:
return fltr.passRSRFilters(req, extraFieldsLabel)
case MetaRSRFields:
return fltr.passRSRFields(req, extraFieldsLabel)
case MetaCDRStats:
return fltr.passCDRStats(req, extraFieldsLabel)
default:
@@ -84,9 +108,15 @@ func (fltr *RequestFilter) passDestinations(req interface{}, extraFieldsLabel st
return false, utils.ErrNotImplemented
}
// ToDo
func (fltr *RequestFilter) passRSRFilters(req interface{}, extraFieldsLabel string) (bool, error) {
return false, utils.ErrNotImplemented
func (fltr *RequestFilter) passRSRFields(req interface{}, extraFieldsLabel string) (bool, error) {
for _, rsrFld := range fltr.rsrFields {
if strVal, err := utils.ReflectFieldAsString(req, rsrFld.Id, extraFieldsLabel); err != nil {
return false, err
} else if !rsrFld.FilterPasses(strVal) {
return false, nil
}
}
return true, nil
}
// ToDo

View File

@@ -64,3 +64,36 @@ func TestPassStringPrefix(t *testing.T) {
t.Error(err)
}
}
func TestPassRSRFields(t *testing.T) {
cd := &CallDescriptor{Direction: "*out", Category: "call", Tenant: "cgrates.org", Subject: "dan", Destination: "+4986517174963",
TimeStart: time.Date(2013, time.October, 7, 14, 50, 0, 0, time.UTC), TimeEnd: time.Date(2013, time.October, 7, 14, 52, 12, 0, time.UTC),
DurationIndex: 132 * time.Second, ExtraFields: map[string]string{"navigation": "off"}}
rf, err := NewRequestFilter(MetaRSRFields, "", "Tenant(~^cgr.*\\.org$)", nil, nil)
if err != nil {
t.Error(err)
}
if passes, err := rf.passRSRFields(cd, "ExtraFields"); err != nil {
t.Error(err)
} else if !passes {
t.Error("Not passing")
}
rf, err = NewRequestFilter(MetaRSRFields, "", "navigation(on)", nil, nil)
if err != nil {
t.Error(err)
}
if passes, err := rf.passRSRFields(cd, "ExtraFields"); err != nil {
t.Error(err)
} else if passes {
t.Error("Passing")
}
rf, err = NewRequestFilter(MetaRSRFields, "", "navigation(off)", nil, nil)
if err != nil {
t.Error(err)
}
if passes, err := rf.passRSRFields(cd, "ExtraFields"); err != nil {
t.Error(err)
} else if !passes {
t.Error("Not passing")
}
}

View File

@@ -179,6 +179,42 @@ func (rsrFltr *RSRFilter) Pass(val string) bool {
return val == rsrFltr.filterRule != rsrFltr.negative
}
func ParseRSRFilters(fldsStr, sep string) (RSRFilters, error) {
if fldsStr == "" {
return nil, nil
}
fltrSplt := strings.Split(fldsStr, sep)
rsrFltrs := make(RSRFilters, len(fltrSplt))
for i, rlStr := range fltrSplt {
if rsrFltr, err := NewRSRFilter(rlStr); err != nil {
return nil, err
} else if rsrFltr == nil {
return nil, fmt.Errorf("Empty RSRFilter in rule: %s", rlStr)
} else {
rsrFltrs[i] = rsrFltr
}
}
return rsrFltrs, nil
}
type RSRFilters []*RSRFilter
// @all: specifies whether all filters should match or at least one
func (fltrs RSRFilters) Pass(val string, allMustMatch bool) bool {
if len(fltrs) == 0 {
return true
}
var matched bool
for _, fltr := range fltrs {
if fltr.Pass(val) {
matched = true
} else if allMustMatch {
return false
}
}
return matched
}
// Parses list of RSRFields, used for example as multiple filters in derived charging
func ParseRSRFields(fldsStr, sep string) (RSRFields, error) {
//rsrRlsPattern := regexp.MustCompile(`^(~\w+:s/.+/.*/)|(\^.+(/.+/)?)(;(~\w+:s/.+/.*/)|(\^.+(/.+/)?))*$`) //ToDo:Fix here rule able to confirm the content
@@ -198,6 +234,8 @@ func ParseRSRFieldsFromSlice(flds []string) (RSRFields, error) {
for idx, ruleStr := range flds {
if rsrField, err := NewRSRField(ruleStr); err != nil {
return nil, err
} else if rsrField == nil {
return nil, fmt.Errorf("Empty RSRField in rule: %s", ruleStr)
} else {
rsrFields[idx] = rsrField
}
@@ -217,9 +255,9 @@ func ParseRSRFieldsMustCompile(fldsStr, sep string) RSRFields {
type RSRFields []*RSRField
// Return first Id of the rsrFields, used in cdre
func (self RSRFields) Id() string {
if len(self) == 0 {
func (flds RSRFields) Id() string {
if len(flds) == 0 {
return ""
}
return self[0].Id
return flds[0].Id
}

View File

@@ -352,3 +352,23 @@ func TestRSRFilterPass(t *testing.T) {
t.Error("Not passing!")
}
}
func TestRSRFiltersPass(t *testing.T) {
rlStr := "~^C.+S$;CGRateS;ateS$"
fltrs, err := ParseRSRFilters(rlStr, INFIELD_SEP)
if err != nil {
t.Error(err)
}
if !fltrs.Pass("CGRateS", true) {
t.Error("Not passing")
}
if fltrs.Pass("ateS", true) {
t.Error("Passing")
}
if !fltrs.Pass("ateS", false) {
t.Error("Not passing")
}
if fltrs.Pass("teS", false) {
t.Error("Passing")
}
}