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

@@ -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)
}