RequestFilter.passCDRStats

This commit is contained in:
DanB
2016-07-14 21:08:11 +02:00
parent 6ecd726867
commit 9254e5b5b2
3 changed files with 97 additions and 31 deletions

View File

@@ -21,6 +21,7 @@ package engine
import (
"errors"
"fmt"
"strconv"
"strings"
"github.com/cgrates/cgrates/utils"
@@ -33,6 +34,8 @@ const (
MetaRSRFields = "*rsr_fields"
MetaCDRStats = "*cdr_stats"
MetaDestinations = "*destinations"
MetaMinCapPrefix = "*MIN_"
MetaMaxCapPrefix = "*MAX_"
)
func NewRequestFilter(rfType, fieldName string, vals []string, cdrStats rpcclient.RpcClientConnection) (*RequestFilter, error) {
@@ -42,13 +45,33 @@ func NewRequestFilter(rfType, fieldName string, vals []string, cdrStats rpcclien
if fieldName == "" && utils.IsSliceMember([]string{MetaStringPrefix, MetaTimings, MetaDestinations}, rfType) {
return nil, fmt.Errorf("FieldName is mandatory for Type: %s", rfType)
}
if len(vals) == 0 && utils.IsSliceMember([]string{MetaStringPrefix, MetaTimings, MetaRSRFields, MetaDestinations}, rfType) {
if len(vals) == 0 && utils.IsSliceMember([]string{MetaStringPrefix, MetaTimings, MetaRSRFields, MetaDestinations, MetaDestinations}, rfType) {
return nil, fmt.Errorf("Values is mandatory for Type: %s", rfType)
}
if rfType == MetaCDRStats && cdrStats == nil {
return nil, errors.New("Missing cdrStats information")
rf := &RequestFilter{Type: rfType, FieldName: fieldName, Values: vals, cdrStats: cdrStats, cdrStatSThresholds: make([]*RFStatSThreshold, len(vals))}
if rfType == MetaCDRStats {
if cdrStats == nil {
return nil, errors.New("Missing cdrStats information")
}
for i, val := range vals {
valSplt := strings.Split(val, utils.InInFieldSep)
if len(valSplt) != 3 {
return nil, fmt.Errorf("Value %s needs to contain at least 3 items", val)
}
st := &RFStatSThreshold{QueueID: valSplt[0], ThresholdType: strings.ToUpper(valSplt[1])}
if len(st.ThresholdType) < len(MetaMinCapPrefix)+1 {
return nil, fmt.Errorf("Value %s contains a unsupported ThresholdType format", val)
} else if !strings.HasPrefix(st.ThresholdType, MetaMinCapPrefix) && !strings.HasPrefix(st.ThresholdType, MetaMaxCapPrefix) {
return nil, fmt.Errorf("Value %s contains unsupported ThresholdType prefix", val)
}
if tv, err := strconv.ParseFloat(valSplt[2], 64); err != nil {
return nil, err
} else {
st.ThresholdValue = tv
}
rf.cdrStatSThresholds[i] = st
}
}
rf := &RequestFilter{Type: rfType, FieldName: fieldName, Values: vals, cdrStats: cdrStats}
if rfType == MetaRSRFields {
var err error
if rf.rsrFields, err = utils.ParseRSRFieldsFromSlice(vals); err != nil {
@@ -58,15 +81,22 @@ func NewRequestFilter(rfType, fieldName string, vals []string, cdrStats rpcclien
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 Values to check (used in case of some )
Values []string // Filter definition
rsrFields utils.RSRFields // Cache here the RSRFilter Values
dataDB AccountingStorage
cdrStats rpcclient.RpcClientConnection // Connection towards CDRStats service (eg: for *cdr_stats type)
type RFStatSThreshold struct {
QueueID string
ThresholdType string
ThresholdValue float64
}
// RequestFilter filters requests coming into various places
// Pass rule: default negative, one mathing rule should pass the filter
type RequestFilter struct {
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
dataDB AccountingStorage
cdrStats rpcclient.RpcClientConnection // Connection towards CDRStats service (eg: for *cdr_stats type)
cdrStatSThresholds []*RFStatSThreshold
}
func (fltr *RequestFilter) Pass(req interface{}, extraFieldsLabel string) (bool, error) {
@@ -91,14 +121,12 @@ func (fltr *RequestFilter) passStringPrefix(req interface{}, extraFieldsLabel st
if err != nil {
return false, err
}
matchedPrefix := false
for _, prfx := range fltr.Values {
if strings.HasPrefix(strVal, prfx) {
matchedPrefix = true
break
return true, nil
}
}
return matchedPrefix, nil
return false, nil
}
// ToDo when Timings will be available in TPdb
@@ -111,41 +139,48 @@ func (fltr *RequestFilter) passDestinations(req interface{}, extraFieldsLabel st
if err != nil {
return false, err
}
var matched bool
for _, p := range utils.SplitPrefix(dst, MIN_PREFIX_MATCH) {
if x, err := CacheGet(utils.DESTINATION_PREFIX + p); err == nil {
destIds := x.(map[string]struct{})
for dID := range destIds {
for _, valDstID := range fltr.Values {
if valDstID == dID {
matched = true
break
return true, nil
}
}
if matched {
break
}
}
if matched {
break
}
}
}
return matched, nil
return false, nil
}
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
} else if rsrFld.FilterPasses(strVal) {
return true, nil
}
}
return true, nil
return false, nil
}
// ToDo
/*
func (fltr *RequestFilter) passCDRStats(req interface{}, extraFieldsLabel string) (bool, error) {
return false, utils.ErrNotImplemented
for _, threshold := range fltr.cdrStatSThresholds {
statValues := make(map[string]float64)
fmt.Printf("Threshold: %+v", threshold)
if err := fltr.cdrStats.Call("CDRStatsV1.GetValues", threshold.QueueID, &statValues); err != nil {
return false, err
}
if val, hasIt := statValues[threshold.ThresholdType[len(MetaMinCapPrefix):]]; !hasIt {
continue
} else if strings.HasPrefix(threshold.ThresholdType, MetaMinCapPrefix) && val >= threshold.ThresholdValue {
return true, nil
} else if strings.HasPrefix(threshold.ThresholdType, MetaMaxCapPrefix) && val < threshold.ThresholdValue {
return true, nil
}
}
return false, nil
}
*/

View File

@@ -123,3 +123,33 @@ func TestPassDestinations(t *testing.T) {
t.Error("Passing")
}
}
func TestPassCDRStats(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"}}
cdrStats := NewStats(ratingStorage, accountingStorage, 0)
cdr := &CDR{
Tenant: "cgrates.org",
Category: "call",
AnswerTime: time.Now(),
SetupTime: time.Now(),
Usage: 10 * time.Second,
Cost: 10,
Supplier: "suppl1",
DisconnectCause: "NORMAL_CLEARNING",
}
err := cdrStats.AppendCDR(cdr, nil)
if err != nil {
t.Error("Error appending cdr to stats: ", err)
}
rf, err := NewRequestFilter(MetaCDRStats, "", []string{"CDRST1:*min_asr:20", "CDRST2:*min_acd:120"}, cdrStats)
if err != nil {
t.Fatal(err)
}
if passes, err := rf.passCDRStats(cd, "ExtraFields"); err != nil {
t.Error(err)
} else if !passes {
t.Error("Not passing")
}
}

View File

@@ -106,6 +106,7 @@ const (
FALLBACK_SEP = ';'
INFIELD_SEP = ";"
FIELDS_SEP = ","
InInFieldSep = ":"
STATIC_HDRVAL_SEP = "::"
REGEXP_PREFIX = "~"
FILTER_VAL_START = "("