mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
Centralize DynamicDP and add support in AttributeS
This commit is contained in:
committed by
Dan Christian Bogos
parent
3e998f9d8e
commit
e29f34ac58
@@ -23,6 +23,9 @@ import "github.com/cgrates/cgrates/utils"
|
||||
// AttributeSCfg is the configuration of attribute service
|
||||
type AttributeSCfg struct {
|
||||
Enabled bool
|
||||
ResourceSConns []string
|
||||
StatSConns []string
|
||||
ApierSConns []string
|
||||
IndexedSelects bool
|
||||
StringIndexedFields *[]string
|
||||
PrefixIndexedFields *[]string
|
||||
@@ -38,6 +41,39 @@ func (alS *AttributeSCfg) loadFromJsonCfg(jsnCfg *AttributeSJsonCfg) (err error)
|
||||
if jsnCfg.Enabled != nil {
|
||||
alS.Enabled = *jsnCfg.Enabled
|
||||
}
|
||||
if jsnCfg.Stats_conns != nil {
|
||||
alS.StatSConns = make([]string, len(*jsnCfg.Stats_conns))
|
||||
for idx, connID := range *jsnCfg.Stats_conns {
|
||||
// if we have the connection internal we change the name so we can have internal rpc for each subsystem
|
||||
if connID == utils.MetaInternal {
|
||||
alS.StatSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaStatS)
|
||||
} else {
|
||||
alS.StatSConns[idx] = connID
|
||||
}
|
||||
}
|
||||
}
|
||||
if jsnCfg.Resources_conns != nil {
|
||||
alS.ResourceSConns = make([]string, len(*jsnCfg.Resources_conns))
|
||||
for idx, connID := range *jsnCfg.Resources_conns {
|
||||
// if we have the connection internal we change the name so we can have internal rpc for each subsystem
|
||||
if connID == utils.MetaInternal {
|
||||
alS.ResourceSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaResources)
|
||||
} else {
|
||||
alS.ResourceSConns[idx] = connID
|
||||
}
|
||||
}
|
||||
}
|
||||
if jsnCfg.Apiers_conns != nil {
|
||||
alS.ApierSConns = make([]string, len(*jsnCfg.Apiers_conns))
|
||||
for idx, connID := range *jsnCfg.Apiers_conns {
|
||||
// if we have the connection internal we change the name so we can have internal rpc for each subsystem
|
||||
if connID == utils.MetaInternal {
|
||||
alS.ApierSConns[idx] = utils.ConcatenatedKey(utils.MetaInternal, utils.MetaApier)
|
||||
} else {
|
||||
alS.ApierSConns[idx] = connID
|
||||
}
|
||||
}
|
||||
}
|
||||
if jsnCfg.Indexed_selects != nil {
|
||||
alS.IndexedSelects = *jsnCfg.Indexed_selects
|
||||
}
|
||||
@@ -74,6 +110,9 @@ func (alS *AttributeSCfg) loadFromJsonCfg(jsnCfg *AttributeSJsonCfg) (err error)
|
||||
func (alS *AttributeSCfg) AsMapInterface() (initialMP map[string]interface{}) {
|
||||
initialMP = map[string]interface{}{
|
||||
utils.EnabledCfg: alS.Enabled,
|
||||
utils.StatSConnsCfg: alS.StatSConns,
|
||||
utils.ResourceSConnsCfg: alS.ResourceSConns,
|
||||
utils.ApierSConnsCfg: alS.ApierSConns,
|
||||
utils.IndexedSelectsCfg: alS.IndexedSelects,
|
||||
utils.ProcessRunsCfg: alS.ProcessRuns,
|
||||
utils.NestedFieldsCfg: alS.NestedFields,
|
||||
|
||||
@@ -36,6 +36,9 @@ func TestAttributeSCfgloadFromJsonCfg(t *testing.T) {
|
||||
}
|
||||
expected := &AttributeSCfg{
|
||||
Enabled: true,
|
||||
ApierSConns: []string{},
|
||||
StatSConns: []string{},
|
||||
ResourceSConns: []string{},
|
||||
IndexedSelects: false,
|
||||
StringIndexedFields: &[]string{"*req.index1"},
|
||||
PrefixIndexedFields: &[]string{"*req.index1", "*req.index2"},
|
||||
@@ -63,6 +66,9 @@ func TestAttributeSCfgAsMapInterface(t *testing.T) {
|
||||
}`
|
||||
eMap := map[string]interface{}{
|
||||
utils.EnabledCfg: true,
|
||||
utils.StatSConnsCfg: []string{},
|
||||
utils.ResourceSConnsCfg: []string{},
|
||||
utils.ApierSConnsCfg: []string{},
|
||||
utils.StringIndexedFieldsCfg: []string{"*req.index1"},
|
||||
utils.PrefixIndexedFieldsCfg: []string{"*req.index1", "*req.index2"},
|
||||
utils.ProcessRunsCfg: 3,
|
||||
@@ -88,6 +94,9 @@ func TestAttributeSCfgAsMapInterface2(t *testing.T) {
|
||||
}`
|
||||
expectedMap := map[string]interface{}{
|
||||
utils.EnabledCfg: true,
|
||||
utils.StatSConnsCfg: []string{},
|
||||
utils.ResourceSConnsCfg: []string{},
|
||||
utils.ApierSConnsCfg: []string{},
|
||||
utils.IndexedSelectsCfg: true,
|
||||
utils.PrefixIndexedFieldsCfg: []string{},
|
||||
utils.SuffixIndexedFieldsCfg: []string{"*req.index1", "*req.index2"},
|
||||
@@ -109,6 +118,9 @@ func TestAttributeSCfgAsMapInterface3(t *testing.T) {
|
||||
`
|
||||
expectedMap := map[string]interface{}{
|
||||
utils.EnabledCfg: false,
|
||||
utils.StatSConnsCfg: []string{},
|
||||
utils.ResourceSConnsCfg: []string{},
|
||||
utils.ApierSConnsCfg: []string{},
|
||||
utils.IndexedSelectsCfg: true,
|
||||
utils.PrefixIndexedFieldsCfg: []string{},
|
||||
utils.SuffixIndexedFieldsCfg: []string{},
|
||||
|
||||
@@ -536,7 +536,10 @@ const CGRATES_CFG_JSON = `
|
||||
|
||||
|
||||
"attributes": { // AttributeS config
|
||||
"enabled": false, // starts attribute service: <true|false>.
|
||||
"enabled": false, // starts attribute service: <true|false>
|
||||
"stats_conns": [], // connections to StatS, empty to disable: <""|*internal|$rpc_conns_id>
|
||||
"resources_conns": [], // connections to ResourceS, empty to disable: <""|*internal|$rpc_conns_id>
|
||||
"apiers_conns": [], // connections to ApierS, empty to disable: <""|*internal|$rpc_conns_id>
|
||||
"indexed_selects": true, // enable profile matching exclusively on indexes
|
||||
//"string_indexed_fields": [], // query indexes based on these fields for faster processing
|
||||
"prefix_indexed_fields": [], // query indexes based on these fields for faster processing
|
||||
|
||||
@@ -134,6 +134,9 @@ func testCGRConfigReloadAttributeS(t *testing.T) {
|
||||
}
|
||||
expAttr := &AttributeSCfg{
|
||||
Enabled: true,
|
||||
ApierSConns: []string{},
|
||||
ResourceSConns: []string{},
|
||||
StatSConns: []string{},
|
||||
StringIndexedFields: &[]string{utils.MetaReq + utils.NestingSep + utils.Account},
|
||||
PrefixIndexedFields: &[]string{},
|
||||
SuffixIndexedFields: &[]string{},
|
||||
|
||||
@@ -825,12 +825,15 @@ func TestDNSAgentJsonCfg(t *testing.T) {
|
||||
func TestDfAttributeServJsonCfg(t *testing.T) {
|
||||
eCfg := &AttributeSJsonCfg{
|
||||
Enabled: utils.BoolPointer(false),
|
||||
Stats_conns: &[]string{},
|
||||
Resources_conns: &[]string{},
|
||||
Apiers_conns: &[]string{},
|
||||
Indexed_selects: utils.BoolPointer(true),
|
||||
String_indexed_fields: nil,
|
||||
Prefix_indexed_fields: &[]string{},
|
||||
Suffix_indexed_fields: &[]string{},
|
||||
Process_runs: utils.IntPointer(1),
|
||||
Nested_fields: utils.BoolPointer(false),
|
||||
Process_runs: utils.IntPointer(1),
|
||||
}
|
||||
if cfg, err := dfCgrJSONCfg.AttributeServJsonCfg(); err != nil {
|
||||
t.Error(err)
|
||||
|
||||
@@ -395,6 +395,9 @@ type ReqProcessorJsnCfg struct {
|
||||
// Attribute service config section
|
||||
type AttributeSJsonCfg struct {
|
||||
Enabled *bool
|
||||
Stats_conns *[]string
|
||||
Resources_conns *[]string
|
||||
Apiers_conns *[]string
|
||||
Indexed_selects *bool
|
||||
String_indexed_fields *[]string
|
||||
Prefix_indexed_fields *[]string
|
||||
|
||||
@@ -235,18 +235,21 @@ func (alS *AttributeService) processEvent(args *AttrArgsProcessEvent, evNm utils
|
||||
case utils.META_CONSTANT:
|
||||
substitute, err = attribute.Value.ParseValue(utils.EmptyString)
|
||||
case utils.MetaVariable, utils.META_COMPOSED:
|
||||
substitute, err = attribute.Value.ParseDataProvider(evNm)
|
||||
substitute, err = attribute.Value.ParseDataProvider(newDynamicDP(alS.cgrcfg.AttributeSCfg().ResourceSConns,
|
||||
alS.cgrcfg.AttributeSCfg().StatSConns, alS.cgrcfg.AttributeSCfg().ApierSConns, args.Tenant, evNm))
|
||||
case utils.META_USAGE_DIFFERENCE:
|
||||
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(evNm); err != nil {
|
||||
if strVal1, err = attribute.Value[0].ParseDataProvider(newDynamicDP(alS.cgrcfg.AttributeSCfg().ResourceSConns,
|
||||
alS.cgrcfg.AttributeSCfg().StatSConns, alS.cgrcfg.AttributeSCfg().ApierSConns, args.Tenant, evNm)); err != nil {
|
||||
rply = nil
|
||||
return
|
||||
}
|
||||
var strVal2 string
|
||||
if strVal2, err = attribute.Value[1].ParseDataProvider(evNm); err != nil {
|
||||
if strVal2, err = attribute.Value[1].ParseDataProvider(newDynamicDP(alS.cgrcfg.AttributeSCfg().ResourceSConns,
|
||||
alS.cgrcfg.AttributeSCfg().StatSConns, alS.cgrcfg.AttributeSCfg().ApierSConns, args.Tenant, evNm)); err != nil {
|
||||
rply = nil
|
||||
return
|
||||
}
|
||||
@@ -263,7 +266,8 @@ func (alS *AttributeService) processEvent(args *AttrArgsProcessEvent, evNm utils
|
||||
substitute = tEnd.Sub(tStart).String()
|
||||
case utils.MetaSum:
|
||||
var ifaceVals []interface{}
|
||||
if ifaceVals, err = attribute.Value.GetIfaceFromValues(evNm); err != nil {
|
||||
if ifaceVals, err = attribute.Value.GetIfaceFromValues(newDynamicDP(alS.cgrcfg.AttributeSCfg().ResourceSConns,
|
||||
alS.cgrcfg.AttributeSCfg().StatSConns, alS.cgrcfg.AttributeSCfg().ApierSConns, args.Tenant, evNm)); err != nil {
|
||||
rply = nil
|
||||
return
|
||||
}
|
||||
@@ -275,7 +279,8 @@ func (alS *AttributeService) processEvent(args *AttrArgsProcessEvent, evNm utils
|
||||
substitute = utils.IfaceAsString(ifaceSum)
|
||||
case utils.MetaDifference:
|
||||
var ifaceVals []interface{}
|
||||
if ifaceVals, err = attribute.Value.GetIfaceFromValues(evNm); err != nil {
|
||||
if ifaceVals, err = attribute.Value.GetIfaceFromValues(newDynamicDP(alS.cgrcfg.AttributeSCfg().ResourceSConns,
|
||||
alS.cgrcfg.AttributeSCfg().StatSConns, alS.cgrcfg.AttributeSCfg().ApierSConns, args.Tenant, evNm)); err != nil {
|
||||
rply = nil
|
||||
return
|
||||
}
|
||||
@@ -287,7 +292,8 @@ func (alS *AttributeService) processEvent(args *AttrArgsProcessEvent, evNm utils
|
||||
substitute = utils.IfaceAsString(ifaceSum)
|
||||
case utils.MetaMultiply:
|
||||
var ifaceVals []interface{}
|
||||
if ifaceVals, err = attribute.Value.GetIfaceFromValues(evNm); err != nil {
|
||||
if ifaceVals, err = attribute.Value.GetIfaceFromValues(newDynamicDP(alS.cgrcfg.AttributeSCfg().ResourceSConns,
|
||||
alS.cgrcfg.AttributeSCfg().StatSConns, alS.cgrcfg.AttributeSCfg().ApierSConns, args.Tenant, evNm)); err != nil {
|
||||
rply = nil
|
||||
return
|
||||
}
|
||||
@@ -299,7 +305,8 @@ func (alS *AttributeService) processEvent(args *AttrArgsProcessEvent, evNm utils
|
||||
substitute = utils.IfaceAsString(ifaceSum)
|
||||
case utils.MetaDivide:
|
||||
var ifaceVals []interface{}
|
||||
if ifaceVals, err = attribute.Value.GetIfaceFromValues(evNm); err != nil {
|
||||
if ifaceVals, err = attribute.Value.GetIfaceFromValues(newDynamicDP(alS.cgrcfg.AttributeSCfg().ResourceSConns,
|
||||
alS.cgrcfg.AttributeSCfg().StatSConns, alS.cgrcfg.AttributeSCfg().ApierSConns, args.Tenant, evNm)); err != nil {
|
||||
rply = nil
|
||||
return
|
||||
}
|
||||
@@ -315,7 +322,8 @@ func (alS *AttributeService) processEvent(args *AttrArgsProcessEvent, evNm utils
|
||||
utils.ToJSON(attribute.Value), utils.MetaValueExponent)
|
||||
}
|
||||
var strVal1 string
|
||||
if strVal1, err = attribute.Value[0].ParseDataProvider(evNm); err != nil {
|
||||
if strVal1, err = attribute.Value[0].ParseDataProvider(newDynamicDP(alS.cgrcfg.AttributeSCfg().ResourceSConns,
|
||||
alS.cgrcfg.AttributeSCfg().StatSConns, alS.cgrcfg.AttributeSCfg().ApierSConns, args.Tenant, evNm)); err != nil {
|
||||
rply = nil
|
||||
return
|
||||
}
|
||||
@@ -325,7 +333,8 @@ func (alS *AttributeService) processEvent(args *AttrArgsProcessEvent, evNm utils
|
||||
strVal1, utils.MetaValueExponent)
|
||||
}
|
||||
var strVal2 string
|
||||
if strVal2, err = attribute.Value[1].ParseDataProvider(evNm); err != nil {
|
||||
if strVal2, err = attribute.Value[1].ParseDataProvider(newDynamicDP(alS.cgrcfg.AttributeSCfg().ResourceSConns,
|
||||
alS.cgrcfg.AttributeSCfg().StatSConns, alS.cgrcfg.AttributeSCfg().ApierSConns, args.Tenant, evNm)); err != nil {
|
||||
rply = nil
|
||||
return
|
||||
}
|
||||
@@ -338,7 +347,8 @@ func (alS *AttributeService) processEvent(args *AttrArgsProcessEvent, evNm utils
|
||||
alS.cgrcfg.GeneralCfg().RoundingDecimals, utils.ROUNDING_MIDDLE), 'f', -1, 64)
|
||||
case utils.MetaUnixTimestamp:
|
||||
var val string
|
||||
if val, err = attribute.Value.ParseDataProvider(evNm); err != nil {
|
||||
if val, err = attribute.Value.ParseDataProvider(newDynamicDP(alS.cgrcfg.AttributeSCfg().ResourceSConns,
|
||||
alS.cgrcfg.AttributeSCfg().StatSConns, alS.cgrcfg.AttributeSCfg().ApierSConns, args.Tenant, evNm)); err != nil {
|
||||
rply = nil
|
||||
return
|
||||
}
|
||||
|
||||
125
engine/dynamicdp.go
Normal file
125
engine/dynamicdp.go
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
Real-time Online/Offline Charging System (OCS) for Telecom & ISP environments
|
||||
Copyright (C) ITsysCOM GmbH
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
*/
|
||||
|
||||
package engine
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
)
|
||||
|
||||
func newDynamicDP(resConns, stsConns, apiConns []string,
|
||||
tenant string, initialDP utils.DataProvider) *dynamicDP {
|
||||
return &dynamicDP{
|
||||
resConns: resConns,
|
||||
stsConns: stsConns,
|
||||
apiConns: apiConns,
|
||||
tenant: tenant,
|
||||
initialDP: initialDP,
|
||||
cache: utils.MapStorage{},
|
||||
}
|
||||
}
|
||||
|
||||
type dynamicDP struct {
|
||||
resConns []string
|
||||
stsConns []string
|
||||
apiConns []string
|
||||
tenant string
|
||||
initialDP utils.DataProvider
|
||||
|
||||
cache utils.MapStorage
|
||||
}
|
||||
|
||||
func (dDP *dynamicDP) String() string { return dDP.initialDP.String() }
|
||||
|
||||
func (dDP *dynamicDP) FieldAsString(fldPath []string) (string, error) {
|
||||
val, err := dDP.FieldAsInterface(fldPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return utils.IfaceAsString(val), nil
|
||||
}
|
||||
|
||||
func (dDP *dynamicDP) RemoteHost() net.Addr {
|
||||
return utils.LocalAddr()
|
||||
}
|
||||
|
||||
var initialDPPrefixes = utils.NewStringSet([]string{utils.MetaReq, utils.MetaVars,
|
||||
utils.MetaCgreq, utils.MetaCgrep, utils.MetaRep, utils.MetaCGRAReq,
|
||||
utils.MetaAct, utils.MetaEC, utils.MetaUCH, utils.MetaOpts})
|
||||
|
||||
func (dDP *dynamicDP) FieldAsInterface(fldPath []string) (val interface{}, err error) {
|
||||
if len(fldPath) == 0 {
|
||||
return nil, utils.ErrNotFound
|
||||
}
|
||||
if initialDPPrefixes.Has(fldPath[0]) {
|
||||
return dDP.initialDP.FieldAsInterface(fldPath)
|
||||
}
|
||||
val, err = dDP.cache.FieldAsInterface(fldPath)
|
||||
if err == utils.ErrNotFound { // in case not found in cache try to populate it
|
||||
return dDP.fieldAsInterface(fldPath)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (dDP *dynamicDP) fieldAsInterface(fldPath []string) (val interface{}, err error) {
|
||||
if len(fldPath) < 2 {
|
||||
return nil, fmt.Errorf("invalid fieldname <%s>", fldPath)
|
||||
}
|
||||
switch fldPath[0] {
|
||||
case utils.MetaAccounts:
|
||||
// sample of fieldName : ~*accounts.1001.BalanceMap.*monetary[0].Value
|
||||
// split the field name in 3 parts
|
||||
// fieldNameType (~*accounts), accountID(1001) and queried part (BalanceMap.*monetary[0].Value)
|
||||
|
||||
var account Account
|
||||
if err = connMgr.Call(dDP.apiConns, nil, utils.APIerSv2GetAccount,
|
||||
&utils.AttrGetAccount{Tenant: dDP.tenant, Account: fldPath[1]}, &account); err != nil {
|
||||
return
|
||||
}
|
||||
//construct dataProvider from account and set it further
|
||||
dp := config.NewObjectDP(account)
|
||||
dDP.cache.Set(fldPath[:2], dp)
|
||||
return dp.FieldAsInterface(fldPath[2:])
|
||||
case utils.MetaResources:
|
||||
// sample of fieldName : ~*resources.ResourceID.Field
|
||||
var reply *Resource
|
||||
if err := connMgr.Call(dDP.resConns, nil, utils.ResourceSv1GetResource,
|
||||
&utils.TenantID{Tenant: dDP.tenant, ID: fldPath[1]}, &reply); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dp := config.NewObjectDP(reply)
|
||||
dDP.cache.Set(fldPath[:2], dp)
|
||||
return dp.FieldAsInterface(fldPath[2:])
|
||||
case utils.MetaStats:
|
||||
// sample of fieldName : ~*stats.StatID.*acd
|
||||
var statValues map[string]float64
|
||||
|
||||
if err := connMgr.Call(dDP.stsConns, nil, utils.StatSv1GetQueueFloatMetrics,
|
||||
&utils.TenantIDWithOpts{TenantID: &utils.TenantID{Tenant: dDP.tenant, ID: fldPath[1]}},
|
||||
&statValues); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for k, v := range statValues {
|
||||
dDP.cache.Set([]string{utils.MetaStats, fldPath[1], k}, v)
|
||||
}
|
||||
return dDP.cache.FieldAsInterface(fldPath)
|
||||
default: // in case of constant we give an empty DataProvider ( empty navigable map )
|
||||
}
|
||||
return nil, utils.ErrNotFound
|
||||
}
|
||||
@@ -33,7 +33,6 @@ func NewFilterS(cfg *config.CGRConfig, connMgr *ConnManager, dm *DataManager) (f
|
||||
cfg: cfg,
|
||||
connMgr: connMgr,
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@@ -53,7 +52,8 @@ func (fS *FilterS) Pass(tenant string, filterIDs []string,
|
||||
if len(filterIDs) == 0 {
|
||||
return true, nil
|
||||
}
|
||||
dDP := newDynamicDP(fS.cfg, fS.connMgr, tenant, ev)
|
||||
dDP := newDynamicDP(fS.cfg.FilterSCfg().ResourceSConns, fS.cfg.FilterSCfg().StatSConns,
|
||||
fS.cfg.FilterSCfg().ApierSConns, tenant, ev)
|
||||
for _, fltrID := range filterIDs {
|
||||
f, err := fS.dm.GetFilter(tenant, fltrID,
|
||||
true, true, utils.NonTransactional)
|
||||
@@ -117,7 +117,8 @@ func (fS *FilterS) LazyPass(tenant string, filterIDs []string,
|
||||
return true, nil, nil
|
||||
}
|
||||
pass = true
|
||||
dDP := newDynamicDP(fS.cfg, fS.connMgr, tenant, ev)
|
||||
dDP := newDynamicDP(fS.cfg.FilterSCfg().ResourceSConns, fS.cfg.FilterSCfg().StatSConns,
|
||||
fS.cfg.FilterSCfg().ApierSConns, tenant, ev)
|
||||
for _, fltrID := range filterIDs {
|
||||
var f *Filter
|
||||
f, err = fS.dm.GetFilter(tenant, fltrID,
|
||||
@@ -617,104 +618,6 @@ func (fltr *FilterRule) passAPIBan(dDP utils.DataProvider) (bool, error) {
|
||||
return dm.GetAPIBan(strVal, config.CgrConfig().APIBanCfg().Keys, fltr.Values[0] != utils.MetaAll, true, true)
|
||||
}
|
||||
|
||||
func newDynamicDP(cfg *config.CGRConfig, connMgr *ConnManager,
|
||||
tenant string, initialDP utils.DataProvider) *dynamicDP {
|
||||
return &dynamicDP{
|
||||
cfg: cfg,
|
||||
connMgr: connMgr,
|
||||
tenant: tenant,
|
||||
initialDP: initialDP,
|
||||
cache: utils.MapStorage{},
|
||||
}
|
||||
}
|
||||
|
||||
type dynamicDP struct {
|
||||
cfg *config.CGRConfig
|
||||
connMgr *ConnManager
|
||||
tenant string
|
||||
initialDP utils.DataProvider
|
||||
|
||||
cache utils.MapStorage
|
||||
}
|
||||
|
||||
func (dDP *dynamicDP) String() string { return dDP.initialDP.String() }
|
||||
|
||||
func (dDP *dynamicDP) FieldAsString(fldPath []string) (string, error) {
|
||||
val, err := dDP.FieldAsInterface(fldPath)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return utils.IfaceAsString(val), nil
|
||||
}
|
||||
|
||||
func (dDP *dynamicDP) RemoteHost() net.Addr {
|
||||
return utils.LocalAddr()
|
||||
}
|
||||
|
||||
var initialDPPrefixes = utils.NewStringSet([]string{utils.MetaReq, utils.MetaVars,
|
||||
utils.MetaCgreq, utils.MetaCgrep, utils.MetaRep, utils.MetaCGRAReq,
|
||||
utils.MetaAct, utils.MetaEC, utils.MetaUCH, utils.MetaOpts})
|
||||
|
||||
func (dDP *dynamicDP) FieldAsInterface(fldPath []string) (val interface{}, err error) {
|
||||
if len(fldPath) == 0 {
|
||||
return nil, utils.ErrNotFound
|
||||
}
|
||||
if initialDPPrefixes.Has(fldPath[0]) {
|
||||
return dDP.initialDP.FieldAsInterface(fldPath)
|
||||
}
|
||||
val, err = dDP.cache.FieldAsInterface(fldPath)
|
||||
if err == utils.ErrNotFound { // in case not found in cache try to populate it
|
||||
return dDP.fieldAsInterface(fldPath)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (dDP *dynamicDP) fieldAsInterface(fldPath []string) (val interface{}, err error) {
|
||||
if len(fldPath) < 2 {
|
||||
return nil, fmt.Errorf("invalid fieldname <%s>", fldPath)
|
||||
}
|
||||
switch fldPath[0] {
|
||||
case utils.MetaAccounts:
|
||||
// sample of fieldName : ~*accounts.1001.BalanceMap.*monetary[0].Value
|
||||
// split the field name in 3 parts
|
||||
// fieldNameType (~*accounts), accountID(1001) and quried part (BalanceMap.*monetary[0].Value)
|
||||
|
||||
var account Account
|
||||
if err = dDP.connMgr.Call(dDP.cfg.FilterSCfg().ApierSConns, nil, utils.APIerSv2GetAccount,
|
||||
&utils.AttrGetAccount{Tenant: dDP.tenant, Account: fldPath[1]}, &account); err != nil {
|
||||
return
|
||||
}
|
||||
//construct dataProvider from account and set it furthder
|
||||
dp := config.NewObjectDP(account)
|
||||
dDP.cache.Set(fldPath[:2], dp)
|
||||
return dp.FieldAsInterface(fldPath[2:])
|
||||
case utils.MetaResources:
|
||||
// sample of fieldName : ~*resources.ResourceID.Field
|
||||
var reply *Resource
|
||||
if err := dDP.connMgr.Call(dDP.cfg.FilterSCfg().ResourceSConns, nil, utils.ResourceSv1GetResource,
|
||||
&utils.TenantID{Tenant: dDP.tenant, ID: fldPath[1]}, &reply); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dp := config.NewObjectDP(reply)
|
||||
dDP.cache.Set(fldPath[:2], dp)
|
||||
return dp.FieldAsInterface(fldPath[2:])
|
||||
case utils.MetaStats:
|
||||
// sample of fieldName : ~*stats.StatID.*acd
|
||||
var statValues map[string]float64
|
||||
|
||||
if err := dDP.connMgr.Call(dDP.cfg.FilterSCfg().StatSConns, nil, utils.StatSv1GetQueueFloatMetrics,
|
||||
&utils.TenantIDWithOpts{TenantID: &utils.TenantID{Tenant: dDP.tenant, ID: fldPath[1]}},
|
||||
&statValues); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for k, v := range statValues {
|
||||
dDP.cache.Set([]string{utils.MetaStats, fldPath[1], k}, v)
|
||||
}
|
||||
return dDP.cache.FieldAsInterface(fldPath)
|
||||
default: // in case of constant we give an empty DataProvider ( empty navigable map )
|
||||
}
|
||||
return nil, utils.ErrNotFound
|
||||
}
|
||||
func verifyInlineFilterS(fltrs []string) (err error) {
|
||||
for _, fl := range fltrs {
|
||||
if strings.HasPrefix(fl, utils.Meta) {
|
||||
|
||||
@@ -496,10 +496,12 @@ func (rpS *RouteService) populateSortingData(ev *utils.CGREvent, route *Route,
|
||||
//filter the route
|
||||
if len(route.lazyCheckRules) != 0 {
|
||||
//construct the DP and pass it to filterS
|
||||
dynDP := newDynamicDP(rpS.cgrcfg, rpS.connMgr, ev.Tenant, utils.MapStorage{
|
||||
utils.MetaReq: ev.Event,
|
||||
utils.MetaVars: sortedSpl.SortingData,
|
||||
})
|
||||
dynDP := newDynamicDP(rpS.cgrcfg.FilterSCfg().ResourceSConns, rpS.cgrcfg.FilterSCfg().StatSConns,
|
||||
rpS.cgrcfg.FilterSCfg().ApierSConns,
|
||||
ev.Tenant, utils.MapStorage{
|
||||
utils.MetaReq: ev.Event,
|
||||
utils.MetaVars: sortedSpl.SortingData,
|
||||
})
|
||||
|
||||
for _, rule := range route.lazyCheckRules { // verify the rules remaining from PartialPass
|
||||
if pass, err = rule.Pass(dynDP); err != nil {
|
||||
|
||||
Reference in New Issue
Block a user