Merged template parsing functions

This commit is contained in:
Trial97
2021-05-05 13:02:38 +03:00
committed by Dan Christian Bogos
parent d63418f260
commit 1db592ea8d
6 changed files with 283 additions and 519 deletions

View File

@@ -20,11 +20,8 @@ package agents
import (
"fmt"
"math"
"net"
"strconv"
"strings"
"time"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/engine"
@@ -321,164 +318,21 @@ func (ar *AgentRequest) Remove(fullPath *utils.FullPath) error {
// ParseField outputs the value based on the template item
func (ar *AgentRequest) ParseField(
cfgFld *config.FCTemplate) (out interface{}, err error) {
var isString bool
switch cfgFld.Type {
default:
return utils.EmptyString, fmt.Errorf("unsupported type: <%s>", cfgFld.Type)
case utils.MetaNone:
return
tmpType := cfgFld.Type
switch tmpType {
case utils.MetaFiller:
out, err = cfgFld.Value.ParseValue(utils.EmptyString)
cfgFld.Padding = utils.MetaRight
isString = true
case utils.MetaConstant:
out, err = cfgFld.Value.ParseValue(utils.EmptyString)
isString = true
case utils.MetaRemoteHost:
out = ar.RemoteHost().String()
isString = true
case utils.MetaVariable, utils.MetaComposed, utils.MetaGroup:
out, err = cfgFld.Value.ParseDataProvider(ar)
isString = true
case utils.MetaUsageDifference:
if len(cfgFld.Value) != 2 {
return nil, fmt.Errorf("invalid arguments <%s> to %s",
utils.ToJSON(cfgFld.Value), utils.MetaUsageDifference)
}
var strVal1 string
if strVal1, err = cfgFld.Value[0].ParseDataProvider(ar); err != nil {
return
}
var strVal2 string
if strVal2, err = cfgFld.Value[1].ParseDataProvider(ar); err != nil {
return
}
var tEnd time.Time
if tEnd, err = utils.ParseTimeDetectLayout(strVal1, ar.Timezone); err != nil {
return
}
var tStart time.Time
if tStart, err = utils.ParseTimeDetectLayout(strVal2, ar.Timezone); err != nil {
return
}
out = tEnd.Sub(tStart).String()
isString = true
case utils.MetaCCUsage:
if len(cfgFld.Value) != 3 {
return nil, fmt.Errorf("invalid arguments <%s> to %s",
utils.ToJSON(cfgFld.Value), utils.MetaCCUsage)
}
var strVal1 string
if strVal1, err = cfgFld.Value[0].ParseDataProvider(ar); err != nil {
return
}
var reqNr int64
if reqNr, err = strconv.ParseInt(strVal1, 10, 64); err != nil {
err = fmt.Errorf("invalid requestNumber <%s> to %s",
strVal1, utils.MetaCCUsage)
return
}
var strVal2 string
if strVal2, err = cfgFld.Value[1].ParseDataProvider(ar); err != nil {
return
}
var usedCCTime time.Duration
if usedCCTime, err = utils.ParseDurationWithNanosecs(strVal2); err != nil {
err = fmt.Errorf("invalid usedCCTime <%s> to %s",
strVal2, utils.MetaCCUsage)
return
}
var strVal3 string
if strVal3, err = cfgFld.Value[2].ParseDataProvider(ar); err != nil {
return
}
var debitItvl time.Duration
if debitItvl, err = utils.ParseDurationWithNanosecs(strVal3); err != nil {
err = fmt.Errorf("invalid debitInterval <%s> to %s",
strVal3, utils.MetaCCUsage)
return
}
if reqNr--; reqNr < 0 { // terminate will be ignored (init request should always be 0)
reqNr = 0
}
return usedCCTime + time.Duration(debitItvl.Nanoseconds()*reqNr), nil
case utils.MetaSum:
var iFaceVals []interface{}
if iFaceVals, err = cfgFld.Value.GetIfaceFromValues(ar); err != nil {
return
}
out, err = utils.Sum(iFaceVals...)
case utils.MetaDifference:
var iFaceVals []interface{}
if iFaceVals, err = cfgFld.Value.GetIfaceFromValues(ar); err != nil {
return
}
out, err = utils.Difference(iFaceVals...)
case utils.MetaMultiply:
var iFaceVals []interface{}
if iFaceVals, err = cfgFld.Value.GetIfaceFromValues(ar); err != nil {
return
}
out, err = utils.Multiply(iFaceVals...)
case utils.MetaDivide:
var iFaceVals []interface{}
if iFaceVals, err = cfgFld.Value.GetIfaceFromValues(ar); err != nil {
return
}
out, err = utils.Divide(iFaceVals...)
case utils.MetaValueExponent:
if len(cfgFld.Value) != 2 {
return nil, fmt.Errorf("invalid arguments <%s> to %s",
utils.ToJSON(cfgFld.Value), utils.MetaValueExponent)
}
var strVal1 string
if strVal1, err = cfgFld.Value[0].ParseDataProvider(ar); err != nil {
return
}
var val float64
if val, err = strconv.ParseFloat(strVal1, 64); err != nil {
err = fmt.Errorf("invalid value <%s> to %s",
strVal1, utils.MetaValueExponent)
return
}
var strVal2 string
if strVal2, err = cfgFld.Value[1].ParseDataProvider(ar); err != nil {
return
}
var exp int
if exp, err = strconv.Atoi(strVal2); err != nil {
return
}
out = strconv.FormatFloat(utils.Round(val*math.Pow10(exp),
config.CgrConfig().GeneralCfg().RoundingDecimals, utils.MetaRoundingMiddle), 'f', -1, 64)
case utils.MetaUnixTimestamp:
var val string
if val, err = cfgFld.Value.ParseDataProvider(ar); err != nil {
return
}
var t1 time.Time
if t1, err = utils.ParseTimeDetectLayout(val, cfgFld.Timezone); err != nil {
return
}
out = strconv.Itoa(int(t1.Unix()))
case utils.MetaDateTime: // Convert the requested field value into datetime with layout
var val string
if val, err = cfgFld.Value.ParseDataProvider(ar); err != nil {
return
}
var dtFld time.Time
dtFld, err = utils.ParseTimeDetectLayout(val, utils.FirstNonEmpty(cfgFld.Timezone, config.CgrConfig().GeneralCfg().DefaultTimezone))
if err != nil {
return
}
out = dtFld.Format(cfgFld.Layout)
tmpType = utils.MetaConstant
case utils.MetaGroup:
tmpType = utils.MetaVariable
}
out, err = engine.ParseAttribute(ar, tmpType, cfgFld.Path, cfgFld.Value, config.CgrConfig().GeneralCfg().RoundingDecimals, utils.FirstNonEmpty(cfgFld.Timezone, config.CgrConfig().GeneralCfg().DefaultTimezone), cfgFld.Layout, config.CgrConfig().GeneralCfg().RSRSep)
if err != nil &&
!strings.HasPrefix(err.Error(), "Could not find") {
return
}
if isString { // format the string additionally with fmtFieldWidth
if utils.StringTmplType.Has(tmpType) { // format the string additionally with fmtFieldWidth
out, err = utils.FmtFieldWidth(cfgFld.Tag, out.(string), cfgFld.Width,
cfgFld.Strip, cfgFld.Padding, cfgFld.Mandatory)
}

View File

@@ -219,168 +219,12 @@ func (alS *AttributeService) processEvent(tnt string, args *AttrArgsProcessEvent
continue
}
}
var substitute string
switch attribute.Type {
case utils.MetaConstant:
substitute, err = attribute.Value.ParseValue(utils.EmptyString)
case utils.MetaVariable, utils.MetaComposed:
substitute, err = attribute.Value.ParseDataProvider(dynDP)
case utils.MetaUsageDifference:
if len(attribute.Value) != 2 {
return nil, fmt.Errorf("invalid arguments <%s>", utils.ToJSON(attribute.Value))
}
var strVal1 string
if strVal1, err = attribute.Value[0].ParseDataProvider(dynDP); err != nil {
rply = nil
return
}
var strVal2 string
if strVal2, err = attribute.Value[1].ParseDataProvider(dynDP); err != nil {
rply = nil
return
}
var tEnd time.Time
if tEnd, err = utils.ParseTimeDetectLayout(strVal1, utils.EmptyString); err != nil {
rply = nil
return
}
var tStart time.Time
if tStart, err = utils.ParseTimeDetectLayout(strVal2, utils.EmptyString); err != nil {
rply = nil
return
}
substitute = tEnd.Sub(tStart).String()
case utils.MetaSum:
var ifaceVals []interface{}
if ifaceVals, err = attribute.Value.GetIfaceFromValues(dynDP); err != nil {
rply = nil
return
}
var ifaceSum interface{}
if ifaceSum, err = utils.Sum(ifaceVals...); err != nil {
rply = nil
return
}
substitute = utils.IfaceAsString(ifaceSum)
case utils.MetaDifference:
var ifaceVals []interface{}
if ifaceVals, err = attribute.Value.GetIfaceFromValues(dynDP); err != nil {
rply = nil
return
}
var ifaceSum interface{}
if ifaceSum, err = utils.Difference(ifaceVals...); err != nil {
rply = nil
return
}
substitute = utils.IfaceAsString(ifaceSum)
case utils.MetaMultiply:
var ifaceVals []interface{}
if ifaceVals, err = attribute.Value.GetIfaceFromValues(dynDP); err != nil {
rply = nil
return
}
var ifaceSum interface{}
if ifaceSum, err = utils.Multiply(ifaceVals...); err != nil {
rply = nil
return
}
substitute = utils.IfaceAsString(ifaceSum)
case utils.MetaDivide:
var ifaceVals []interface{}
if ifaceVals, err = attribute.Value.GetIfaceFromValues(dynDP); err != nil {
rply = nil
return
}
var ifaceSum interface{}
if ifaceSum, err = utils.Divide(ifaceVals...); err != nil {
rply = nil
return
}
substitute = utils.IfaceAsString(ifaceSum)
case utils.MetaValueExponent:
if len(attribute.Value) != 2 {
return nil, fmt.Errorf("invalid arguments <%s> to %s",
utils.ToJSON(attribute.Value), utils.MetaValueExponent)
}
var strVal1 string
if strVal1, err = attribute.Value[0].ParseDataProvider(dynDP); err != nil {
rply = nil
return
}
var val float64
if val, err = strconv.ParseFloat(strVal1, 64); err != nil {
return nil, fmt.Errorf("invalid value <%s> to %s",
strVal1, utils.MetaValueExponent)
}
var strVal2 string
if strVal2, err = attribute.Value[1].ParseDataProvider(dynDP); err != nil {
rply = nil
return
}
var exp int
if exp, err = strconv.Atoi(strVal2); err != nil {
rply = nil
return
}
substitute = strconv.FormatFloat(utils.Round(val*math.Pow10(exp),
alS.cgrcfg.GeneralCfg().RoundingDecimals, utils.MetaRoundingMiddle), 'f', -1, 64)
case utils.MetaUnixTimestamp:
var val string
if val, err = attribute.Value.ParseDataProvider(dynDP); err != nil {
rply = nil
return
}
var t time.Time
if t, err = utils.ParseTimeDetectLayout(val, alS.cgrcfg.GeneralCfg().DefaultTimezone); err != nil {
rply = nil
return
}
substitute = strconv.Itoa(int(t.Unix()))
case utils.MetaPrefix:
var pathRsr config.RSRParsers
pathRsr, err = config.NewRSRParsers(utils.DynamicDataPrefix+attribute.Path, alS.cgrcfg.GeneralCfg().RSRSep)
if err != nil {
rply = nil
return
}
var pathVal string
if pathVal, err = pathRsr.ParseDataProvider(dynDP); err != nil {
rply = nil
return
}
var val string
if val, err = attribute.Value.ParseDataProvider(dynDP); err != nil {
rply = nil
return
}
substitute = val + pathVal
case utils.MetaSuffix:
var pathRsr config.RSRParsers
pathRsr, err = config.NewRSRParsers(utils.DynamicDataPrefix+attribute.Path, alS.cgrcfg.GeneralCfg().RSRSep)
if err != nil {
rply = nil
return
}
var pathVal string
if pathVal, err = pathRsr.ParseDataProvider(dynDP); err != nil {
rply = nil
return
}
var val string
if val, err = attribute.Value.ParseDataProvider(dynDP); err != nil {
rply = nil
return
}
substitute = pathVal + val
default: // backwards compatible in case that Type is empty
substitute, err = attribute.Value.ParseDataProvider(dynDP)
}
if err != nil {
var out interface{}
if out, err = ParseAttribute(dynDP, utils.FirstNonEmpty(attribute.Type, utils.MetaVariable), utils.DynamicDataPrefix+attribute.Path, attribute.Value, alS.cgrcfg.GeneralCfg().RoundingDecimals, alS.cgrcfg.GeneralCfg().DefaultTimezone, time.RFC3339, alS.cgrcfg.GeneralCfg().RSRSep); err != nil {
rply = nil
return
}
substitute := utils.IfaceAsString(out)
//add only once the Path in AlteredFields
if !utils.IsSliceMember(rply.AlteredFields, attribute.Path) {
rply.AlteredFields = append(rply.AlteredFields, attribute.Path)
@@ -517,3 +361,180 @@ func (alS *AttributeService) V1ProcessEvent(args *AttrArgsProcessEvent,
}
return
}
func ParseAttribute(dp utils.DataProvider, attrType, path string, value config.RSRParsers, roundingDec int, timeZone, layout, rsrSep string) (
out interface{}, err error) {
switch attrType {
case utils.MetaNone:
return
case utils.MetaConstant:
out, err = value.ParseValue(utils.EmptyString)
case utils.MetaVariable, utils.MetaComposed:
out, err = value.ParseDataProvider(dp)
case utils.MetaUsageDifference:
if len(value) != 2 {
return "", fmt.Errorf("invalid arguments <%s> to %s",
utils.ToJSON(value), utils.MetaUsageDifference)
}
var strVal1 string
if strVal1, err = value[0].ParseDataProvider(dp); err != nil {
return
}
var strVal2 string
if strVal2, err = value[1].ParseDataProvider(dp); err != nil {
return
}
var tEnd time.Time
if tEnd, err = utils.ParseTimeDetectLayout(strVal1, utils.EmptyString); err != nil {
return
}
var tStart time.Time
if tStart, err = utils.ParseTimeDetectLayout(strVal2, utils.EmptyString); err != nil {
return
}
out = tEnd.Sub(tStart).String()
case utils.MetaSum:
var ifaceVals []interface{}
if ifaceVals, err = value.GetIfaceFromValues(dp); err != nil {
return
}
out, err = utils.Sum(ifaceVals...)
case utils.MetaDifference:
var ifaceVals []interface{}
if ifaceVals, err = value.GetIfaceFromValues(dp); err != nil {
return
}
out, err = utils.Difference(timeZone, ifaceVals...)
case utils.MetaMultiply:
var ifaceVals []interface{}
if ifaceVals, err = value.GetIfaceFromValues(dp); err != nil {
return
}
out, err = utils.Multiply(ifaceVals...)
case utils.MetaDivide:
var ifaceVals []interface{}
if ifaceVals, err = value.GetIfaceFromValues(dp); err != nil {
return
}
out, err = utils.Divide(ifaceVals...)
case utils.MetaValueExponent:
if len(value) != 2 {
return "", fmt.Errorf("invalid arguments <%s> to %s",
utils.ToJSON(value), utils.MetaValueExponent)
}
var strVal1 string
if strVal1, err = value[0].ParseDataProvider(dp); err != nil {
return
}
var val float64
if val, err = strconv.ParseFloat(strVal1, 64); err != nil {
return "", fmt.Errorf("invalid value <%s> to %s",
strVal1, utils.MetaValueExponent)
}
var strVal2 string
if strVal2, err = value[1].ParseDataProvider(dp); err != nil {
return
}
var exp int
if exp, err = strconv.Atoi(strVal2); err != nil {
return
}
out = strconv.FormatFloat(utils.Round(val*math.Pow10(exp),
roundingDec, utils.MetaRoundingMiddle), 'f', -1, 64)
case utils.MetaUnixTimestamp:
var val string
if val, err = value.ParseDataProvider(dp); err != nil {
return
}
var t time.Time
if t, err = utils.ParseTimeDetectLayout(val, timeZone); err != nil {
return
}
out = strconv.Itoa(int(t.Unix()))
case utils.MetaDateTime: // Convert the requested field value into datetime with layout
var val string
if val, err = value.ParseDataProvider(dp); err != nil {
return
}
var dtFld time.Time
dtFld, err = utils.ParseTimeDetectLayout(val, timeZone)
if err != nil {
return
}
out = dtFld.Format(layout)
case utils.MetaPrefix:
var pathRsr config.RSRParsers
pathRsr, err = config.NewRSRParsers(path, rsrSep)
if err != nil {
return
}
var pathVal string
if pathVal, err = pathRsr.ParseDataProvider(dp); err != nil {
return
}
var val string
if val, err = value.ParseDataProvider(dp); err != nil {
return
}
out = val + pathVal
case utils.MetaSuffix:
var pathRsr config.RSRParsers
pathRsr, err = config.NewRSRParsers(path, rsrSep)
if err != nil {
return
}
var pathVal string
if pathVal, err = pathRsr.ParseDataProvider(dp); err != nil {
return
}
var val string
if val, err = value.ParseDataProvider(dp); err != nil {
return
}
out = pathVal + val
case utils.MetaRemoteHost:
out = dp.RemoteHost().String()
case utils.MetaCCUsage:
if len(value) != 3 {
return nil, fmt.Errorf("invalid arguments <%s> to %s",
utils.ToJSON(value), utils.MetaCCUsage)
}
var strVal1 string
if strVal1, err = value[0].ParseDataProvider(dp); err != nil {
return
}
var reqNr int64
if reqNr, err = strconv.ParseInt(strVal1, 10, 64); err != nil {
err = fmt.Errorf("invalid requestNumber <%s> to %s",
strVal1, utils.MetaCCUsage)
return
}
var strVal2 string
if strVal2, err = value[1].ParseDataProvider(dp); err != nil {
return
}
var usedCCTime time.Duration
if usedCCTime, err = utils.ParseDurationWithNanosecs(strVal2); err != nil {
err = fmt.Errorf("invalid usedCCTime <%s> to %s",
strVal2, utils.MetaCCUsage)
return
}
var strVal3 string
if strVal3, err = value[2].ParseDataProvider(dp); err != nil {
return
}
var debitItvl time.Duration
if debitItvl, err = utils.ParseDurationWithNanosecs(strVal3); err != nil {
err = fmt.Errorf("invalid debitInterval <%s> to %s",
strVal3, utils.MetaCCUsage)
return
}
if reqNr--; reqNr < 0 { // terminate will be ignored (init request should always be 0)
reqNr = 0
}
return usedCCTime + time.Duration(debitItvl.Nanoseconds()*reqNr), nil
default:
return utils.EmptyString, fmt.Errorf("unsupported type: <%s>", attrType)
}
return
}

View File

@@ -20,11 +20,8 @@ package engine
import (
"fmt"
"math"
"net"
"strconv"
"strings"
"time"
"github.com/cgrates/cgrates/config"
"github.com/cgrates/cgrates/utils"
@@ -191,158 +188,8 @@ func (eeR *EventRequest) SetAsSlice(fullPath *utils.FullPath, val *utils.DataLea
// ParseField outputs the value based on the template item
func (eeR *EventRequest) ParseField(
cfgFld *config.FCTemplate) (out interface{}, err error) {
var isString bool
switch cfgFld.Type {
default:
return utils.EmptyString, fmt.Errorf("unsupported type: <%s>", cfgFld.Type)
case utils.MetaNone:
return
case utils.MetaFiller:
out, err = cfgFld.Value.ParseValue(utils.EmptyString)
cfgFld.Padding = utils.MetaRight
isString = true
case utils.MetaConstant:
out, err = cfgFld.Value.ParseValue(utils.EmptyString)
isString = true
case utils.MetaRemoteHost:
out = eeR.RemoteHost().String()
isString = true
case utils.MetaVariable, utils.MetaComposed, utils.MetaGroup:
out, err = cfgFld.Value.ParseDataProvider(eeR)
isString = true
case utils.MetaUsageDifference:
if len(cfgFld.Value) != 2 {
return nil, fmt.Errorf("invalid arguments <%s> to %s",
utils.ToJSON(cfgFld.Value), utils.MetaUsageDifference)
}
var strVal1 string
if strVal1, err = cfgFld.Value[0].ParseDataProvider(eeR); err != nil {
return
}
var strVal2 string
if strVal2, err = cfgFld.Value[1].ParseDataProvider(eeR); err != nil {
return
}
var tEnd time.Time
if tEnd, err = utils.ParseTimeDetectLayout(strVal1, eeR.Timezone); err != nil {
return
}
var tStart time.Time
if tStart, err = utils.ParseTimeDetectLayout(strVal2, eeR.Timezone); err != nil {
return
}
out = tEnd.Sub(tStart).String()
isString = true
case utils.MetaCCUsage:
if len(cfgFld.Value) != 3 {
return nil, fmt.Errorf("invalid arguments <%s> to %s",
utils.ToJSON(cfgFld.Value), utils.MetaCCUsage)
}
var strVal1 string
if strVal1, err = cfgFld.Value[0].ParseDataProvider(eeR); err != nil {
return
}
var reqNr int64
if reqNr, err = strconv.ParseInt(strVal1, 10, 64); err != nil {
err = fmt.Errorf("invalid requestNumber <%s> to %s",
strVal1, utils.MetaCCUsage)
return
}
var strVal2 string
if strVal2, err = cfgFld.Value[1].ParseDataProvider(eeR); err != nil {
return
}
var usedCCTime time.Duration
if usedCCTime, err = utils.ParseDurationWithNanosecs(strVal2); err != nil {
err = fmt.Errorf("invalid usedCCTime <%s> to %s",
strVal2, utils.MetaCCUsage)
return
}
var strVal3 string
if strVal3, err = cfgFld.Value[2].ParseDataProvider(eeR); err != nil {
return
}
var debitItvl time.Duration
if debitItvl, err = utils.ParseDurationWithNanosecs(strVal3); err != nil {
err = fmt.Errorf("invalid debitInterval <%s> to %s",
strVal3, utils.MetaCCUsage)
return
}
if reqNr--; reqNr < 0 { // terminate will be ignored (init request should always be 0)
reqNr = 0
}
return usedCCTime + time.Duration(debitItvl.Nanoseconds()*reqNr), nil
case utils.MetaSum:
var iFaceVals []interface{}
if iFaceVals, err = cfgFld.Value.GetIfaceFromValues(eeR); err != nil {
return
}
out, err = utils.Sum(iFaceVals...)
case utils.MetaDifference:
var iFaceVals []interface{}
if iFaceVals, err = cfgFld.Value.GetIfaceFromValues(eeR); err != nil {
return
}
out, err = utils.Difference(iFaceVals...)
case utils.MetaMultiply:
var iFaceVals []interface{}
if iFaceVals, err = cfgFld.Value.GetIfaceFromValues(eeR); err != nil {
return
}
out, err = utils.Multiply(iFaceVals...)
case utils.MetaDivide:
var iFaceVals []interface{}
if iFaceVals, err = cfgFld.Value.GetIfaceFromValues(eeR); err != nil {
return
}
out, err = utils.Divide(iFaceVals...)
case utils.MetaValueExponent:
if len(cfgFld.Value) != 2 {
return nil, fmt.Errorf("invalid arguments <%s> to %s",
utils.ToJSON(cfgFld.Value), utils.MetaValueExponent)
}
var strVal1 string
if strVal1, err = cfgFld.Value[0].ParseDataProvider(eeR); err != nil {
return
}
var val float64
if val, err = strconv.ParseFloat(strVal1, 64); err != nil {
err = fmt.Errorf("invalid value <%s> to %s",
strVal1, utils.MetaValueExponent)
return
}
var strVal2 string
if strVal2, err = cfgFld.Value[1].ParseDataProvider(eeR); err != nil {
return
}
var exp int
if exp, err = strconv.Atoi(strVal2); err != nil {
return
}
out = strconv.FormatFloat(utils.Round(val*math.Pow10(exp),
config.CgrConfig().GeneralCfg().RoundingDecimals, utils.MetaRoundingMiddle), 'f', -1, 64)
case utils.MetaUnixTimestamp:
var val string
if val, err = cfgFld.Value.ParseDataProvider(eeR); err != nil {
return
}
var t1 time.Time
if t1, err = utils.ParseTimeDetectLayout(val, cfgFld.Timezone); err != nil {
return
}
out = strconv.Itoa(int(t1.Unix()))
case utils.MetaDateTime: // Convert the requested field value into datetime with layout
var val string
if val, err = cfgFld.Value.ParseDataProvider(eeR); err != nil {
return
}
var dtFld time.Time
dtFld, err = utils.ParseTimeDetectLayout(val, utils.FirstNonEmpty(cfgFld.Timezone, config.CgrConfig().GeneralCfg().DefaultTimezone))
if err != nil {
return
}
out = dtFld.Format(cfgFld.Layout)
tmpType := cfgFld.Type
switch tmpType {
case utils.MetaMaskedDestination:
//check if we have destination in the event
var dst string
@@ -355,14 +202,20 @@ func (eeR *EventRequest) ParseField(
CachedDestHasPrefix(cfgFld.MaskDestID, dst) {
out = utils.MaskSuffix(dst, cfgFld.MaskLen)
}
return
case utils.MetaFiller:
cfgFld.Padding = utils.MetaRight
tmpType = utils.MetaConstant
case utils.MetaGroup:
tmpType = utils.MetaVariable
}
out, err = ParseAttribute(eeR, tmpType, cfgFld.Path, cfgFld.Value, config.CgrConfig().GeneralCfg().RoundingDecimals, utils.FirstNonEmpty(cfgFld.Timezone, config.CgrConfig().GeneralCfg().DefaultTimezone), cfgFld.Layout, config.CgrConfig().GeneralCfg().RSRSep)
if err != nil &&
!strings.HasPrefix(err.Error(), "Could not find") {
return
}
if isString { // format the string additionally with fmtFieldWidth
if utils.StringTmplType.Has(tmpType) { // format the string additionally with fmtFieldWidth
out, err = utils.FmtFieldWidth(cfgFld.Tag, out.(string), cfgFld.Width,
cfgFld.Strip, cfgFld.Padding, cfgFld.Mandatory)
}

View File

@@ -2660,6 +2660,17 @@ var (
}
)
// StringTmplType a string set used, by agentRequest and eventRequest to determine if the returned template type is string
var StringTmplType = StringSet{
MetaConstant: struct{}{},
MetaRemoteHost: struct{}{},
MetaVariable: struct{}{},
MetaComposed: struct{}{},
MetaUsageDifference: struct{}{},
MetaPrefix: struct{}{},
MetaSuffix: struct{}{},
}
// Time duration suffix
const (
NsSuffix = "ns"

View File

@@ -550,107 +550,126 @@ func Sum(items ...interface{}) (sum interface{}, err error) {
switch dt := items[0].(type) {
case time.Duration:
sum = dt
s := dt
for _, item := range items[1:] {
if itmVal, err := IfaceAsDuration(item); err != nil {
return nil, err
} else {
sum = sum.(time.Duration) + itmVal
s += itmVal
}
}
sum = s
case time.Time:
sum = dt
s := dt
for _, item := range items[1:] {
if itmVal, err := IfaceAsDuration(item); err != nil {
return nil, err
} else {
sum = sum.(time.Time).Add(itmVal)
s = s.Add(itmVal)
}
}
sum = s
case float64:
sum = dt
s := dt
for _, item := range items[1:] {
if itmVal, err := IfaceAsFloat64(item); err != nil {
return nil, err
} else {
sum = sum.(float64) + itmVal
s += itmVal
}
}
sum = s
case int64:
sum = dt
s := dt
for _, item := range items[1:] {
if itmVal, err := IfaceAsInt64(item); err != nil {
return nil, err
} else {
sum = sum.(int64) + itmVal
s += itmVal
}
}
sum = s
case int:
sum = int64(dt)
s := int64(dt)
for _, item := range items[1:] {
if itmVal, err := IfaceAsInt64(item); err != nil {
return nil, err
} else {
sum = sum.(int64) + itmVal
s += itmVal
}
}
sum = s
}
return
}
// Difference attempts to sum multiple items
// returns the result or error if not comparable
func Difference(items ...interface{}) (diff interface{}, err error) {
func Difference(tm string, items ...interface{}) (diff interface{}, err error) {
//we need at least 2 items to diff them
if len(items) < 2 {
return nil, ErrNotEnoughParameters
}
switch dt := items[0].(type) {
case time.Duration:
diff = dt
d := dt
for _, item := range items[1:] {
if itmVal, err := IfaceAsDuration(item); err != nil {
return nil, err
} else {
diff = diff.(time.Duration) - itmVal
d -= itmVal
}
}
diff = d
case time.Time:
diff = dt
for _, item := range items[1:] {
d := dt
for i, item := range items[1:] {
if itmVal, err := IfaceAsTime(item, tm); err == nil {
diff = d.Sub(itmVal)
if len(items) == i+1 {
return diff, nil
}
items[i] = diff
return Difference(tm, items[i:]...)
}
if itmVal, err := IfaceAsDuration(item); err != nil {
return nil, err
} else {
diff = diff.(time.Time).Add(-itmVal)
d = d.Add(-itmVal)
}
}
diff = d
case float64:
diff = dt
d := dt
for _, item := range items[1:] {
if itmVal, err := IfaceAsFloat64(item); err != nil {
return nil, err
} else {
diff = diff.(float64) - itmVal
d -= itmVal
}
}
diff = d
case int64:
diff = dt
d := dt
for _, item := range items[1:] {
if itmVal, err := IfaceAsInt64(item); err != nil {
return nil, err
} else {
diff = diff.(int64) - itmVal
d -= itmVal
}
}
diff = d
case int:
diff = int64(dt)
d := int64(dt)
for _, item := range items[1:] {
if itmVal, err := IfaceAsInt64(item); err != nil {
return nil, err
} else {
diff = diff.(int64) - itmVal
d -= itmVal
}
}
diff = d
default: // unsupported comparison
return nil, fmt.Errorf("unsupported type")
}
@@ -666,32 +685,35 @@ func Multiply(items ...interface{}) (mlt interface{}, err error) {
}
switch dt := items[0].(type) {
case float64:
mlt = dt
m := dt
for _, item := range items[1:] {
if itmVal, err := IfaceAsFloat64(item); err != nil {
return nil, err
} else {
mlt = mlt.(float64) * itmVal
m *= itmVal
}
}
mlt = m
case int64:
mlt = dt
m := dt
for _, item := range items[1:] {
if itmVal, err := IfaceAsInt64(item); err != nil {
return nil, err
} else {
mlt = mlt.(int64) * itmVal
m *= itmVal
}
}
mlt = m
case int:
mlt = int64(dt)
m := int64(dt)
for _, item := range items[1:] {
if itmVal, err := IfaceAsInt64(item); err != nil {
return nil, err
} else {
mlt = mlt.(int64) * itmVal
m *= itmVal
}
}
mlt = m
default: // unsupported comparison
return nil, fmt.Errorf("unsupported type")
}
@@ -700,39 +722,42 @@ func Multiply(items ...interface{}) (mlt interface{}, err error) {
// Divide attempts to divide multiple items
// returns the result or error if not comparable
func Divide(items ...interface{}) (mlt interface{}, err error) {
func Divide(items ...interface{}) (div interface{}, err error) {
//we need at least 2 items to diff them
if len(items) < 2 {
return nil, ErrNotEnoughParameters
}
switch dt := items[0].(type) {
case float64:
mlt = dt
d := dt
for _, item := range items[1:] {
if itmVal, err := IfaceAsFloat64(item); err != nil {
return nil, err
} else {
mlt = mlt.(float64) / itmVal
d /= itmVal
}
}
div = d
case int64:
mlt = dt
d := dt
for _, item := range items[1:] {
if itmVal, err := IfaceAsInt64(item); err != nil {
return nil, err
} else {
mlt = mlt.(int64) / itmVal
d /= itmVal
}
}
div = d
case int:
mlt = int64(dt)
d := int64(dt)
for _, item := range items[1:] {
if itmVal, err := IfaceAsInt64(item); err != nil {
return nil, err
} else {
mlt = mlt.(int64) / itmVal
d /= itmVal
}
}
div = d
default: // unsupported comparison
return nil, fmt.Errorf("unsupported type")
}

View File

@@ -573,49 +573,49 @@ func TestGetUniformType(t *testing.T) {
}
func TestDifference(t *testing.T) {
if _, err := Difference(10); err == nil || err != ErrNotEnoughParameters {
if _, err := Difference("", 10); err == nil || err != ErrNotEnoughParameters {
t.Error(err)
}
if _, err := Difference(10, 1.2, false); err == nil || err.Error() != "cannot convert field: 1.2 to int" {
if _, err := Difference("", 10, 1.2, false); err == nil || err.Error() != "cannot convert field: 1.2 to int" {
t.Error(err)
}
if diff, err := Difference(12, 1, 2, 3); err != nil {
if diff, err := Difference("", 12, 1, 2, 3); err != nil {
t.Error(err)
} else if diff != int64(6) {
t.Errorf("Expecting: 6, received: %+v", diff)
}
if diff, err := Difference(8.0, 4.0, 2.0, -1.0); err != nil {
if diff, err := Difference("", 8.0, 4.0, 2.0, -1.0); err != nil {
t.Error(err)
} else if diff != 3.0 {
t.Errorf("Expecting: 3.0, received: %+v", diff)
}
if diff, err := Difference(8.0, 4, 2.0, -1.0); err != nil {
if diff, err := Difference("", 8.0, 4, 2.0, -1.0); err != nil {
t.Error(err)
} else if diff != 3.0 {
t.Errorf("Expecting: 3.0, received: %+v", diff)
}
if diff, err := Difference(10*time.Second, time.Second, 2*time.Second,
if diff, err := Difference("", 10*time.Second, time.Second, 2*time.Second,
4*time.Millisecond); err != nil {
t.Error(err)
} else if diff != 6*time.Second+996*time.Millisecond {
t.Errorf("Expecting: 6.996ms, received: %+v", diff)
}
if diff, err := Difference(2*time.Second,
if diff, err := Difference("", 2*time.Second,
10*time.Millisecond); err != nil {
t.Error(err)
} else if diff != time.Second+990*time.Millisecond {
t.Errorf("Expecting: 1.99s, received: %+v", diff)
}
if diff, err := Difference(time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC),
if diff, err := Difference("", time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC),
10*time.Second); err != nil {
t.Error(err)
} else if diff != time.Date(2009, 11, 10, 22, 59, 50, 0, time.UTC) {
t.Errorf("Expecting: %+v, received: %+v", time.Date(2009, 11, 10, 22, 59, 50, 0, time.UTC), diff)
}
if diff, err := Difference(time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC),
if diff, err := Difference("", time.Date(2009, 11, 10, 23, 0, 0, 0, time.UTC),
10*time.Second, 10000000000); err != nil {
t.Error(err)
} else if diff != time.Date(2009, 11, 10, 22, 59, 40, 0, time.UTC) {
@@ -1405,7 +1405,7 @@ func TestReflectDifferenceTimeDurationError(t *testing.T) {
var test2Var bool
testVar = 25354
test2Var = true
_, err := Difference(testVar, test2Var)
_, err := Difference("", testVar, test2Var)
if err == nil || err.Error() != "cannot convert field: true to time.Duration" {
t.Errorf("Expected <cannot convert field: true to time.Duration> ,received: <%+v>", err)
}
@@ -1416,7 +1416,7 @@ func TestReflectDifferenceFloat64Error(t *testing.T) {
var test2Var bool
testVar = 2.5
test2Var = true
_, err := Difference(testVar, test2Var)
_, err := Difference("", testVar, test2Var)
if err == nil || err.Error() != "cannot convert field: true to float64" {
t.Errorf("Expected <cannot convert field: true to float64> ,received: <%+v>", err)
}
@@ -1429,7 +1429,7 @@ func TestReflectDifferenceInt64Error(t *testing.T) {
testVar = 6
test2Var = 5
expected = 1
dif, _ := Difference(testVar, test2Var)
dif, _ := Difference("", testVar, test2Var)
if !reflect.DeepEqual(dif, expected) {
t.Errorf("Expected <%+v> ,received: <%+v>", expected, dif)
}
@@ -1440,7 +1440,7 @@ func TestReflectDifferenceDefault(t *testing.T) {
var test2Var bool
testVar = true
test2Var = true
_, err := Difference(testVar, test2Var)
_, err := Difference("", testVar, test2Var)
if err == nil || err.Error() != "unsupported type" {
t.Errorf("Expected <unsupported type> ,received: <%+v>", err)
}
@@ -1615,14 +1615,14 @@ func TestSumTimeTime(t *testing.T) {
}
func TestDifferenceTimeTimeError(t *testing.T) {
_, err := Difference(time.Now(), "cat")
_, err := Difference("", time.Now(), "cat")
if err == nil || err.Error() != "time: invalid duration \"cat\"" {
t.Errorf("Expected <time: invalid duration \"cat\"> ,received: <%+v>", err)
}
}
func TestDifferenceInt64Error(t *testing.T) {
_, err := Difference(int64(2), "cat")
_, err := Difference("", int64(2), "cat")
if err == nil || err.Error() != "strconv.ParseInt: parsing \"cat\": invalid syntax" {
t.Errorf("Expected <strconv.ParseInt: parsing \"cat\": invalid syntax> ,received: <%+v>", err)
}