mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-15 05:09:54 +05:00
RequestFilter with *rsr_fields type
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user