From 763710fb80cdbf37ed393f8d3346a58e78008ae4 Mon Sep 17 00:00:00 2001 From: Trial97 Date: Tue, 5 May 2020 17:02:37 +0300 Subject: [PATCH] Updated AgentRequest --- agents/agentreq.go | 325 +++++++++++++++++++++-------------- agents/libdiam.go | 2 +- agents/libdns.go | 2 +- agents/libhttpagent.go | 6 +- agents/librad.go | 2 +- config/dataprovider.go | 51 ------ config/fctemplate.go | 73 +++++--- config/fwvdp.go | 16 +- config/navigablemap.go | 78 +++++++-- config/objdp.go | 14 +- config/rsrparser.go | 8 +- config/slicedp.go | 16 +- config/xmldp.go | 16 +- engine/action.go | 2 +- engine/filters.go | 58 +++---- engine/mapevent_test.go | 9 +- engine/safevent_test.go | 9 +- engine/task.go | 10 +- ers/filefwv.go | 4 +- loaders/libloader.go | 2 +- utils/dataprovider.go | 14 +- utils/orderednavigablemap.go | 25 ++- 22 files changed, 411 insertions(+), 331 deletions(-) delete mode 100644 config/dataprovider.go diff --git a/agents/agentreq.go b/agents/agentreq.go index 9d003b169..bed171730 100644 --- a/agents/agentreq.go +++ b/agents/agentreq.go @@ -32,27 +32,31 @@ import ( ) // NewAgentRequest returns a new AgentRequest -func NewAgentRequest(req config.DataProvider, - vars map[string]interface{}, - cgrRply, rply, opts *config.NavigableMap, +func NewAgentRequest(req utils.DataProvider, + vars utils.NavigableMap2, + cgrRply *utils.NavigableMap2, + rply, opts *utils.OrderedNavigableMap, tntTpl config.RSRParsers, dfltTenant, timezone string, filterS *engine.FilterS, - header, trailer config.DataProvider) (ar *AgentRequest) { + header, trailer utils.DataProvider) (ar *AgentRequest) { if cgrRply == nil { - cgrRply = config.NewNavigableMap(nil) + cgrRply = &utils.NavigableMap2{} + } + if vars == nil { + vars = make(utils.NavigableMap2) } if rply == nil { - rply = config.NewNavigableMap(nil) + rply = utils.NewOrderedNavigableMap() } if opts == nil { - opts = config.NewNavigableMap(nil) + opts = utils.NewOrderedNavigableMap() } ar = &AgentRequest{ Request: req, - Vars: config.NewNavigableMap(vars), - CGRRequest: config.NewNavigableMap(nil), - diamreq: config.NewNavigableMap(nil), // special case when CGRateS is building the request + Vars: vars, + CGRRequest: utils.NewOrderedNavigableMap(), + diamreq: utils.NewOrderedNavigableMap(), // special case when CGRateS is building the request CGRReply: cgrRply, Reply: rply, Timezone: timezone, @@ -69,39 +73,39 @@ func NewAgentRequest(req config.DataProvider, } else { ar.Tenant = dfltTenant } - ar.Vars.Set([]string{utils.NodeID}, config.CgrConfig().GeneralCfg().NodeID, false, true) + ar.Vars.Set(utils.PathItems{{Field: utils.NodeID}}, utils.NewNMData(config.CgrConfig().GeneralCfg().NodeID)) return } // AgentRequest represents data related to one request towards agent -// implements engine.DataProvider so we can pass it to filters +// implements utils.DataProvider so we can pass it to filters type AgentRequest struct { - Request config.DataProvider // request - Vars *config.NavigableMap // shared data - CGRRequest *config.NavigableMap // Used in reply to access the request that was send - CGRReply *config.NavigableMap - Reply *config.NavigableMap - Tenant, - Timezone string - filterS *engine.FilterS - Header config.DataProvider - Trailer config.DataProvider - diamreq *config.NavigableMap // used in case of building requests (ie. DisconnectSession) - tmp *config.NavigableMap // used in case you want to store temporary items and access them later - Opts *config.NavigableMap + Request utils.DataProvider // request + Vars utils.NavigableMap2 // shared data + CGRRequest *utils.OrderedNavigableMap // Used in reply to access the request that was send + CGRReply *utils.NavigableMap2 + Reply *utils.OrderedNavigableMap + Tenant string + Timezone string + filterS *engine.FilterS + Header utils.DataProvider + Trailer utils.DataProvider + diamreq *utils.OrderedNavigableMap // used in case of building requests (ie. DisconnectSession) + tmp utils.NavigableMap2 // used in case you want to store temporary items and access them later + Opts *utils.OrderedNavigableMap } -// String implements engine.DataProvider +// String implements utils.DataProvider func (ar *AgentRequest) String() string { return utils.ToIJSON(ar) } -// RemoteHost implements engine.DataProvider +// RemoteHost implements utils.DataProvider func (ar *AgentRequest) RemoteHost() net.Addr { return ar.Request.RemoteHost() } -// FieldAsInterface implements engine.DataProvider +// FieldAsInterface implements utils.DataProvider func (ar *AgentRequest) FieldAsInterface(fldPath []string) (val interface{}, err error) { switch fldPath[0] { default: @@ -109,15 +113,15 @@ func (ar *AgentRequest) FieldAsInterface(fldPath []string) (val interface{}, err case utils.MetaReq: val, err = ar.Request.FieldAsInterface(fldPath[1:]) case utils.MetaVars: - val, err = ar.Vars.GetField(fldPath[1:]) + val, err = ar.Vars.FieldAsInterface(fldPath[1:]) case utils.MetaCgreq: - val, err = ar.CGRRequest.GetField(fldPath[1:]) + val, err = ar.CGRRequest.FieldAsInterface(fldPath[1:]) case utils.MetaCgrep: - val, err = ar.CGRReply.GetField(fldPath[1:]) + val, err = ar.CGRReply.FieldAsInterface(fldPath[1:]) case utils.MetaDiamreq: val, err = ar.diamreq.FieldAsInterface(fldPath[1:]) case utils.MetaRep: - val, err = ar.Reply.GetField(fldPath[1:]) + val, err = ar.Reply.FieldAsInterface(fldPath[1:]) case utils.MetaHdr: val, err = ar.Header.FieldAsInterface(fldPath[1:]) case utils.MetaTrl: @@ -136,27 +140,44 @@ func (ar *AgentRequest) FieldAsInterface(fldPath []string) (val interface{}, err return } -// FieldAsString implements engine.DataProvider +// Field implements utils.NMInterface +func (ar *AgentRequest) Field(fldPath utils.PathItems) (val utils.NMInterface, err error) { + switch fldPath[0].Field { + default: + return nil, fmt.Errorf("unsupported field prefix: <%s>", fldPath[0]) + case utils.MetaVars: + val, err = ar.Vars.Field(fldPath[1:]) + case utils.MetaCgreq: + val, err = ar.CGRRequest.Field(fldPath[1:]) + case utils.MetaCgrep: + val, err = ar.CGRReply.Field(fldPath[1:]) + case utils.MetaDiamreq: + val, err = ar.diamreq.Field(fldPath[1:]) + case utils.MetaRep: + val, err = ar.Reply.Field(fldPath[1:]) + case utils.MetaTmp: + val, err = ar.tmp.Field(fldPath[1:]) + case utils.MetaOpts: + val, err = ar.tmp.Field(fldPath[1:]) + } + return +} + +// FieldAsString implements utils.DataProvider func (ar *AgentRequest) FieldAsString(fldPath []string) (val string, err error) { var iface interface{} if iface, err = ar.FieldAsInterface(fldPath); err != nil { return } - if nmItems, isNMItems := iface.([]*config.NMItem); isNMItems { // special handling of NMItems, take the last value out of it - iface = nmItems[len(nmItems)-1].Data // could be we need nil protection here + if nmItems, isNMItems := iface.(*utils.NMSlice); isNMItems { // special handling of NMItems, take the last value out of it + iface = (*nmItems)[len(*nmItems)-1].Interface() } return utils.IfaceAsString(iface), nil } -// AsNavigableMap implements engine.DataProvider -func (ar *AgentRequest) AsNavigableMap(tplFlds []*config.FCTemplate) ( - nM *config.NavigableMap, err error) { - return nil, utils.ErrNotImplemented -} - //SetFields will populate fields of AgentRequest out of templates func (ar *AgentRequest) SetFields(tplFlds []*config.FCTemplate) (err error) { - ar.tmp = config.NewNavigableMap(nil) + ar.tmp = utils.NavigableMap2{} for _, tplFld := range tplFlds { if pass, err := ar.filterS.Pass(ar.Tenant, tplFld.Filters, ar); err != nil { @@ -167,51 +188,19 @@ func (ar *AgentRequest) SetFields(tplFlds []*config.FCTemplate) (err error) { switch tplFld.Type { case utils.META_NONE: case utils.MetaRemove: - fldPath := strings.Split(tplFld.Path, utils.NestingSep) - switch fldPath[0] { - default: - return fmt.Errorf("unsupported field prefix: <%s> when set fields", fldPath[0]) - case utils.MetaVars: - ar.Vars.Remove(fldPath[1:]) - case utils.MetaCgreq: - ar.CGRRequest.Remove(fldPath[1:]) - case utils.MetaCgrep: - ar.CGRReply.Remove(fldPath[1:]) - case utils.MetaRep: - ar.Reply.Remove(fldPath[1:]) - case utils.MetaDiamreq: - ar.diamreq.Remove(fldPath[1:]) - case utils.MetaTmp: - ar.tmp.Remove(fldPath[1:]) - case utils.MetaCache: - engine.Cache.Remove(utils.CacheUCH, strings.Join(fldPath[1:], utils.NestingSep), true, utils.NonTransactional) - case utils.MetaOpts: - ar.Opts.Remove(fldPath[1:]) + if err = ar.Remove(&utils.FullPath{ + PathItems: tplFld.GetPathItems(), + Path: tplFld.Path, + }); err != nil { + return } case utils.MetaRemoveAll: - fldPath := strings.Split(tplFld.Path, utils.NestingSep) - switch fldPath[0] { - default: - return fmt.Errorf("unsupported field prefix: <%s> when set fields", fldPath[0]) - case utils.MetaVars: - ar.Vars.RemoveAll() - case utils.MetaCgreq: - ar.CGRRequest.RemoveAll() - case utils.MetaCgrep: - ar.CGRReply.RemoveAll() - case utils.MetaRep: - ar.Reply.RemoveAll() - case utils.MetaDiamreq: - ar.diamreq.RemoveAll() - case utils.MetaTmp: - ar.tmp.RemoveAll() - case utils.MetaCache: - engine.Cache.Clear([]string{utils.CacheUCH}) - case utils.MetaOpts: - ar.Opts.RemoveAll() + if err = ar.RemoveAll(tplFld.GetPathSlice()[0]); err != nil { + return } default: - out, err := ar.ParseField(tplFld) + var out interface{} + out, err = ar.ParseField(tplFld) if err != nil { if err == utils.ErrNotFound { if !tplFld.Mandatory { @@ -220,49 +209,24 @@ func (ar *AgentRequest) SetFields(tplFlds []*config.FCTemplate) (err error) { } err = utils.ErrPrefixNotFound(tplFld.Tag) } - return err + return + } + fullPath := &utils.FullPath{ + PathItems: tplFld.GetPathItems().Clone(), // need to clone so me do not modify the template + Path: tplFld.Path, } - var valSet []*config.NMItem - fldPath := strings.Split(tplFld.Path, utils.NestingSep) - nMItm := &config.NMItem{Data: out, Path: fldPath[1:], Config: tplFld} - if nMFields, err := ar.FieldAsInterface(fldPath); err != nil { - if err != utils.ErrNotFound { - return err - } - } else { - valSet = nMFields.([]*config.NMItem) // start from previous stored fields - switch tplFld.Type { - case utils.META_COMPOSED: - prevNMItem := valSet[len(valSet)-1] // could be we need nil protection here - *nMItm = *prevNMItem // inherit the particularities, ie AttributeName - nMItm.Data = utils.IfaceAsString(prevNMItem.Data) + utils.IfaceAsString(out) - valSet = valSet[:len(valSet)-1] // discard the last item since we have captured it in nmItem - case utils.MetaGroup: // in case of *group type simply append to valSet - default: - valSet = nil - } - } - valSet = append(valSet, nMItm) - switch fldPath[0] { + nMItm := &config.NMItem{Data: out, Path: tplFld.GetPathSlice()[1:], Config: tplFld} + switch tplFld.Type { + case utils.META_COMPOSED: + err = utils.ComposeNavMapVal(ar, fullPath, nMItm) + case utils.MetaGroup: // in case of *group type simply append to valSet + err = utils.AppendNavMapVal(ar, fullPath, nMItm) default: - return fmt.Errorf("unsupported field prefix: <%s> when set fields", fldPath[0]) - case utils.MetaVars: - ar.Vars.Set(fldPath[1:], valSet, false, true) - case utils.MetaCgreq: - ar.CGRRequest.Set(fldPath[1:], valSet, false, true) - case utils.MetaCgrep: - ar.CGRReply.Set(fldPath[1:], valSet, false, true) - case utils.MetaRep: - ar.Reply.Set(fldPath[1:], valSet, false, true) - case utils.MetaDiamreq: - ar.diamreq.Set(fldPath[1:], valSet, false, true) - case utils.MetaTmp: - ar.tmp.Set(fldPath[1:], valSet, false, true) - case utils.MetaCache: - engine.Cache.Set(utils.CacheUCH, strings.Join(fldPath[1:], utils.NestingSep), valSet, nil, true, utils.NonTransactional) - case utils.MetaOpts: - ar.Opts.Set(fldPath[1:], valSet, false, true) + _, err = ar.Set(fullPath, &utils.NMSlice{nMItm}) + } + if err != nil { + return } } if tplFld.Blocker { // useful in case of processing errors first @@ -272,6 +236,104 @@ func (ar *AgentRequest) SetFields(tplFlds []*config.FCTemplate) (err error) { return } +// Set implements utils.NMInterface +func (ar *AgentRequest) Set(fullPath *utils.FullPath, nm utils.NMInterface) (added bool, err error) { + switch fullPath.PathItems[0].Field { + default: + return false, fmt.Errorf("unsupported field prefix: <%s> when set field", fullPath.PathItems[0].Field) + case utils.MetaVars: + return ar.Vars.Set(fullPath.PathItems[1:], nm) + case utils.MetaCgreq: + return ar.CGRRequest.Set(&utils.FullPath{ + PathItems: fullPath.PathItems[1:], + Path: fullPath.Path[7:], + }, nm) + case utils.MetaCgrep: + return ar.CGRReply.Set(fullPath.PathItems[1:], nm) + case utils.MetaRep: + return ar.Reply.Set(&utils.FullPath{ + PathItems: fullPath.PathItems[1:], + Path: fullPath.Path[5:], + }, nm) + case utils.MetaDiamreq: + return ar.diamreq.Set(&utils.FullPath{ + PathItems: fullPath.PathItems[1:], + Path: fullPath.Path[9:], + }, nm) + case utils.MetaTmp: + return ar.tmp.Set(fullPath.PathItems[1:], nm) + case utils.MetaOpts: + return ar.diamreq.Set(&utils.FullPath{ + PathItems: fullPath.PathItems[1:], + Path: fullPath.Path[6:], + }, nm) + case utils.MetaCache: + err = engine.Cache.Set(utils.CacheUCH, fullPath.Path[7:], nm, nil, true, utils.NonTransactional) + } + return false, err +} + +// RemoveAll deletes all fields at given prefix +func (ar *AgentRequest) RemoveAll(prefix string) error { + switch prefix { + default: + return fmt.Errorf("unsupported field prefix: <%s> when set fields", prefix) + case utils.MetaVars: + ar.Vars = utils.NavigableMap2{} + case utils.MetaCgreq: + ar.CGRRequest.RemoveAll() + case utils.MetaCgrep: + ar.CGRReply = &utils.NavigableMap2{} + case utils.MetaRep: + ar.Reply.RemoveAll() + case utils.MetaDiamreq: + ar.diamreq.RemoveAll() + case utils.MetaTmp: + ar.tmp = utils.NavigableMap2{} + case utils.MetaCache: + engine.Cache.Clear([]string{utils.CacheUCH}) + case utils.MetaOpts: + ar.Opts.RemoveAll() + } + return nil +} + +// Remove deletes the fields found at path with the given prefix +func (ar *AgentRequest) Remove(fullPath *utils.FullPath) error { + switch fullPath.PathItems[0].Field { + default: + return fmt.Errorf("unsupported field prefix: <%s> when set fields", fullPath.PathItems[0].Field) + case utils.MetaVars: + return ar.Vars.Remove(fullPath.PathItems[1:]) + case utils.MetaCgreq: + return ar.CGRRequest.Remove(&utils.FullPath{ + PathItems: fullPath.PathItems[1:].Clone(), + Path: fullPath.Path[7:], + }) + case utils.MetaCgrep: + return ar.CGRReply.Remove(fullPath.PathItems[1:]) + case utils.MetaRep: + return ar.Reply.Remove(&utils.FullPath{ + PathItems: fullPath.PathItems[1:].Clone(), + Path: fullPath.Path[5:], + }) + case utils.MetaDiamreq: + return ar.diamreq.Remove(&utils.FullPath{ + PathItems: fullPath.PathItems[1:].Clone(), + Path: fullPath.Path[9:], + }) + case utils.MetaTmp: + return ar.tmp.Remove(fullPath.PathItems[1:]) + case utils.MetaOpts: + return ar.Opts.Remove(&utils.FullPath{ + PathItems: fullPath.PathItems[1:].Clone(), + Path: fullPath.Path[6:], + }) + case utils.MetaCache: + return engine.Cache.Remove(utils.CacheUCH, fullPath.Path[7:], true, utils.NonTransactional) + } +} + // ParseField outputs the value based on the template item func (ar *AgentRequest) ParseField( cfgFld *config.FCTemplate) (out interface{}, err error) { @@ -443,20 +505,17 @@ func (ar *AgentRequest) ParseField( // setCGRReply will set the aReq.cgrReply based on reply coming from upstream or error // returns error in case of reply not converting to NavigableMap -func (ar *AgentRequest) setCGRReply(rply config.NavigableMapper, errRply error) (err error) { - var nm *config.NavigableMap +func (ar *AgentRequest) setCGRReply(rply utils.NavigableMapper, errRply error) (err error) { + var nm utils.NavigableMap2 if errRply != nil { - nm = config.NewNavigableMap(map[string]interface{}{ - utils.Error: errRply.Error()}) + nm = utils.NavigableMap2{utils.Error: utils.NewNMData(errRply.Error())} } else { - nm = config.NewNavigableMap(nil) + nm = utils.NavigableMap2{} if rply != nil { - if nm, err = rply.AsNavigableMap(nil); err != nil { - return - } + nm = rply.AsNavigableMap() } - nm.Set([]string{utils.Error}, "", false, false) // enforce empty error + nm.Set(utils.PathItems{{Field: utils.Error}}, utils.NewNMData("")) // enforce empty error } - *ar.CGRReply = *nm // update value so we can share CGRReply + *ar.CGRReply = nm // update value so we can share CGRReply return } diff --git a/agents/libdiam.go b/agents/libdiam.go index aaf15232a..dda880f91 100644 --- a/agents/libdiam.go +++ b/agents/libdiam.go @@ -288,7 +288,7 @@ func writeOnConn(c diam.Conn, m *diam.Message) (err error) { } // newDADataProvider constructs a DataProvider for a diameter message -func newDADataProvider(c diam.Conn, m *diam.Message) config.DataProvider { +func newDADataProvider(c diam.Conn, m *diam.Message) utils.DataProvider { return &diameterDP{c: c, m: m, cache: config.NewNavigableMap(nil)} } diff --git a/agents/libdns.go b/agents/libdns.go index 3ed11d7d2..9b9302778 100644 --- a/agents/libdns.go +++ b/agents/libdns.go @@ -60,7 +60,7 @@ func domainNameFromNAPTR(name string) (dName string) { // newDADataProvider constructs a DataProvider for a diameter message func newDNSDataProvider(req *dns.Msg, - w dns.ResponseWriter) config.DataProvider { + w dns.ResponseWriter) utils.DataProvider { return &dnsDP{req: req, w: w, cache: config.NewNavigableMap(nil)} } diff --git a/agents/libhttpagent.go b/agents/libhttpagent.go index 9308019c2..50d3417b2 100644 --- a/agents/libhttpagent.go +++ b/agents/libhttpagent.go @@ -35,7 +35,7 @@ import ( // newHADataProvider constructs a DataProvider func newHADataProvider(reqPayload string, - req *http.Request) (dP config.DataProvider, err error) { + req *http.Request) (dP utils.DataProvider, err error) { switch reqPayload { default: return nil, fmt.Errorf("unsupported decoder type <%s>", reqPayload) @@ -47,7 +47,7 @@ func newHADataProvider(reqPayload string, } } -func newHTTPUrlDP(req *http.Request) (dP config.DataProvider, err error) { +func newHTTPUrlDP(req *http.Request) (dP utils.DataProvider, err error) { dP = &httpUrlDP{req: req, cache: config.NewNavigableMap(nil)} return } @@ -105,7 +105,7 @@ func (hU *httpUrlDP) RemoteHost() net.Addr { return utils.NewNetAddr("TCP", hU.req.RemoteAddr) } -func newHTTPXmlDP(req *http.Request) (dP config.DataProvider, err error) { +func newHTTPXmlDP(req *http.Request) (dP utils.DataProvider, err error) { byteData, err := ioutil.ReadAll(req.Body) if err != nil { return nil, err diff --git a/agents/librad.go b/agents/librad.go index ba61b6e12..b23f1301e 100644 --- a/agents/librad.go +++ b/agents/librad.go @@ -60,7 +60,7 @@ func radReplyAppendAttributes(reply *radigo.Packet, rplNM *config.NavigableMap) } // newRADataProvider constructs a DataProvider -func newRADataProvider(req *radigo.Packet) (dP config.DataProvider) { +func newRADataProvider(req *radigo.Packet) (dP utils.DataProvider) { dP = &radiusDP{req: req, cache: config.NewNavigableMap(nil)} return } diff --git a/config/dataprovider.go b/config/dataprovider.go deleted file mode 100644 index 1f62c868b..000000000 --- a/config/dataprovider.go +++ /dev/null @@ -1,51 +0,0 @@ -/* -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 -*/ - -package config - -import ( - "net" - "strings" - - "github.com/cgrates/cgrates/utils" -) - -// DataProvider is a data source from multiple formats -type DataProvider interface { - String() string // printable version of data - FieldAsInterface(fldPath []string) (interface{}, error) - FieldAsString(fldPath []string) (string, error) - AsNavigableMap([]*FCTemplate) (*NavigableMap, error) - RemoteHost() net.Addr -} - -func DPDynamicInterface(dnVal string, dP DataProvider) (interface{}, error) { - if strings.HasPrefix(dnVal, utils.DynamicDataPrefix) { - dnVal = strings.TrimPrefix(dnVal, utils.DynamicDataPrefix) - return dP.FieldAsInterface(strings.Split(dnVal, utils.NestingSep)) - } - return utils.StringToInterface(dnVal), nil -} - -func DPDynamicString(dnVal string, dP DataProvider) (string, error) { - if strings.HasPrefix(dnVal, utils.DynamicDataPrefix) { - dnVal = strings.TrimPrefix(dnVal, utils.DynamicDataPrefix) - return dP.FieldAsString(strings.Split(dnVal, utils.NestingSep)) - } - return dnVal, nil -} diff --git a/config/fctemplate.go b/config/fctemplate.go index 2a9e9058d..18e283dba 100755 --- a/config/fctemplate.go +++ b/config/fctemplate.go @@ -20,6 +20,7 @@ package config import ( "fmt" + "strings" "time" "github.com/cgrates/cgrates/utils" @@ -33,6 +34,9 @@ func NewFCTemplateFromFCTemplateJsonCfg(jsnCfg *FcTemplateJsonCfg, separator str } if jsnCfg.Path != nil { fcTmp.Path = *jsnCfg.Path + fcTmp.pathSlice = strings.Split(*jsnCfg.Path, utils.NestingSep) + fcTmp.pathItems = utils.NewPathToItem(fcTmp.pathSlice) + fcTmp.Tag = fcTmp.Path } fcTmp.Tag = fcTmp.Path if jsnCfg.Tag != nil { @@ -116,6 +120,8 @@ type FCTemplate struct { RoundingDecimals *int MaskDestID string MaskLen int + pathItems utils.PathItems // Field identifier + pathSlice []string // Used when we set a NMItem to not recreate this slice for every itemsc } func FCTemplatesFromFCTemplatesJsonCfg(jsnCfgFlds []*FcTemplateJsonCfg, separator string) ([]*FCTemplate, error) { @@ -161,36 +167,41 @@ func InflateTemplates(fcts []*FCTemplate, msgTpls map[string][]*FCTemplate) ([]* return fcts, nil } -func (self *FCTemplate) Clone() *FCTemplate { +func (fc *FCTemplate) Clone() *FCTemplate { cln := new(FCTemplate) - cln.Tag = self.Tag - cln.Type = self.Type - cln.Path = self.Path - if len(self.Filters) != 0 { - cln.Filters = make([]string, len(self.Filters)) - for idx, val := range self.Filters { + cln.Tag = fc.Tag + cln.Type = fc.Type + cln.Path = fc.Path + cln.pathItems = fc.pathItems.Clone() + cln.pathSlice = make([]string, len(fc.pathSlice)) + for i, v := range fc.pathSlice { + cln.pathSlice[i] = v + } + if len(fc.Filters) != 0 { + cln.Filters = make([]string, len(fc.Filters)) + for idx, val := range fc.Filters { cln.Filters[idx] = val } } - cln.Value = make(RSRParsers, len(self.Value)) - for idx, val := range self.Value { + cln.Value = make(RSRParsers, len(fc.Value)) + for idx, val := range fc.Value { clnVal := *val cln.Value[idx] = &clnVal } - cln.Width = self.Width - cln.Strip = self.Strip - cln.Padding = self.Padding - cln.Mandatory = self.Mandatory - cln.AttributeID = self.AttributeID - cln.NewBranch = self.NewBranch - cln.Timezone = self.Timezone - cln.Blocker = self.Blocker - cln.BreakOnSuccess = self.BreakOnSuccess - cln.Layout = self.Layout - cln.CostShiftDigits = self.CostShiftDigits - cln.RoundingDecimals = self.RoundingDecimals - cln.MaskDestID = self.MaskDestID - cln.MaskLen = self.MaskLen + cln.Width = fc.Width + cln.Strip = fc.Strip + cln.Padding = fc.Padding + cln.Mandatory = fc.Mandatory + cln.AttributeID = fc.AttributeID + cln.NewBranch = fc.NewBranch + cln.Timezone = fc.Timezone + cln.Blocker = fc.Blocker + cln.BreakOnSuccess = fc.BreakOnSuccess + cln.Layout = fc.Layout + cln.CostShiftDigits = fc.CostShiftDigits + cln.RoundingDecimals = fc.RoundingDecimals + cln.MaskDestID = fc.MaskDestID + cln.MaskLen = fc.MaskLen return cln } @@ -265,3 +276,19 @@ func (fc *FCTemplate) AsMapInterface(separator string) (mp map[string]interface{ return } + +// GetPathSlice returns the cached split of the path +func (fc *FCTemplate) GetPathSlice() []string { + return fc.pathSlice +} + +// GetPathItems returns the cached path as PathItems +func (fc *FCTemplate) GetPathItems() utils.PathItems { + return fc.pathItems +} + +// ComputePath used in test to populate private fields used to store the path +func (fc *FCTemplate) ComputePath() { + fc.pathSlice = strings.Split(fc.Path, utils.NestingSep) + fc.pathItems = utils.NewPathToItem(fc.pathSlice) +} diff --git a/config/fwvdp.go b/config/fwvdp.go index 5d5c1cc45..3b7cf6b67 100644 --- a/config/fwvdp.go +++ b/config/fwvdp.go @@ -27,25 +27,25 @@ import ( "github.com/cgrates/cgrates/utils" ) -// NewfwvProvider constructs a DataProvider -func NewFWVProvider(record string) (dP DataProvider) { +// NewfwvProvider constructs a utils.DataProvider +func NewFWVProvider(record string) (dP utils.DataProvider) { dP = &FWVProvider{req: record, cache: NewNavigableMap(nil)} return } -// fwvProvider implements engine.DataProvider so we can pass it to filters +// fwvProvider implements engine.utils.DataProvider so we can pass it to filters type FWVProvider struct { req string cache *NavigableMap } -// String is part of engine.DataProvider interface +// String is part of engine.utils.DataProvider interface // when called, it will display the already parsed values out of cache func (fP *FWVProvider) String() string { return utils.ToJSON(fP) } -// FieldAsInterface is part of engine.DataProvider interface +// FieldAsInterface is part of engine.utils.DataProvider interface func (fP *FWVProvider) FieldAsInterface(fldPath []string) (data interface{}, err error) { if len(fldPath) == 0 { return @@ -79,7 +79,7 @@ func (fP *FWVProvider) FieldAsInterface(fldPath []string) (data interface{}, err return } -// FieldAsString is part of engine.DataProvider interface +// FieldAsString is part of engine.utils.DataProvider interface func (fP *FWVProvider) FieldAsString(fldPath []string) (data string, err error) { var valIface interface{} valIface, err = fP.FieldAsInterface(fldPath) @@ -89,13 +89,13 @@ func (fP *FWVProvider) FieldAsString(fldPath []string) (data string, err error) return utils.IfaceAsString(valIface), nil } -// AsNavigableMap is part of engine.DataProvider interface +// AsNavigableMap is part of engine.utils.DataProvider interface func (fP *FWVProvider) AsNavigableMap([]*FCTemplate) ( nm *NavigableMap, err error) { return nil, utils.ErrNotImplemented } -// RemoteHost is part of engine.DataProvider interface +// RemoteHost is part of engine.utils.DataProvider interface func (fP *FWVProvider) RemoteHost() net.Addr { return utils.LocalAddr() } diff --git a/config/navigablemap.go b/config/navigablemap.go index ff872895f..f9f48b701 100644 --- a/config/navigablemap.go +++ b/config/navigablemap.go @@ -31,9 +31,56 @@ import ( "github.com/cgrates/cgrates/utils" ) -// CGRReplier is the interface supported by replies convertible to CGRReply -type NavigableMapper interface { - AsNavigableMap([]*FCTemplate) (*NavigableMap, error) +// NMItem is an item in the NavigableMap +type NMItem struct { + Path []string // path in map + Data interface{} // value of the element + Config *FCTemplate // so we can store additional configuration +} + +func (nmi *NMItem) String() string { + return utils.ToJSON(nmi) +} + +// Interface returns the wraped interface +func (nmi *NMItem) Interface() interface{} { + return nmi.Data +} + +// Field not implemented only used in order to implement the NM interface +func (nmi *NMItem) Field(path utils.PathItems) (val utils.NMInterface, err error) { + return nil, utils.ErrNotImplemented +} + +// Set not implemented only used in order to implement the NM interface +// special case when the path is empty the interface should be seted +// this is in order to modify the wraped interface +func (nmi *NMItem) Set(path utils.PathItems, val utils.NMInterface) (added bool, err error) { + if len(path) != 0 { + return false, utils.ErrWrongPath + } + nmi.Data = val.Interface() + return +} + +// Remove not implemented only used in order to implement the NM interface +func (nmi *NMItem) Remove(path utils.PathItems) (err error) { + return utils.ErrNotImplemented +} + +// Type returns the type of the NM interface +func (nmi *NMItem) Type() utils.NMType { + return utils.NMDataType +} + +// Empty returns true if the NM is empty(no data) +func (nmi *NMItem) Empty() bool { + return nmi == nil || nmi.Data == nil +} + +// Len not implemented only used in order to implement the NM interface +func (nmi *NMItem) Len() int { + return 0 } // NewNavigableMap constructs a NavigableMap @@ -44,13 +91,6 @@ func NewNavigableMap(data map[string]interface{}) *NavigableMap { return &NavigableMap{data: data} } -// NMItem is an item in the NavigableMap -type NMItem struct { - Path []string // path in map - Data interface{} // value of the element - Config *FCTemplate // so we can store additional configuration -} - // NavigableMap is a map who's values can be navigated via path // data can be retrieved as ordered // NavigableMap is not thread safe due to performance demands, could come back if needed @@ -111,7 +151,7 @@ func (nM *NavigableMap) GetField(path []string) (fldVal interface{}, err error) switch mv := dp.(type) { // used for cdr when populating eventCost whitin case map[string]interface{}: lastMp = mv - case DataProvider: + case utils.DataProvider: return mv.FieldAsInterface(path[i+1:]) default: return nil, fmt.Errorf("cannot cast field: <%+v> type: %T with path: <%s> to map[string]interface{}", @@ -157,7 +197,7 @@ func (nM *NavigableMap) getLastRealItem(mp map[string]interface{}, spath string) } // FieldAsInterface returns the field value as interface{} for the path specified -// implements DataProvider +// implements utils.DataProvider // supports spath with selective elements in case of []*NMItem func (nM *NavigableMap) FieldAsInterface(fldPath []string) (fldVal interface{}, err error) { lenPath := len(fldPath) @@ -176,7 +216,7 @@ func (nM *NavigableMap) FieldAsInterface(fldPath []string) (fldVal interface{}, switch mv := dp.(type) { // used for cdr when populating eventCost whitin case map[string]interface{}: lastMp = mv - case DataProvider: + case utils.DataProvider: return mv.FieldAsInterface(fldPath[i+1:]) default: return nil, fmt.Errorf("cannot cast field: <%+v> type: %T with path: <%s> to map[string]interface{}", @@ -250,7 +290,7 @@ func (nM *NavigableMap) getNextMap(mp map[string]interface{}, spath string) (int return mv.data, nil case *NavigableMap: return mv.data, nil - case DataProvider: // used for cdr when populating eventCost whitin + case utils.DataProvider: // used for cdr when populating eventCost whitin return mv, nil default: } @@ -286,7 +326,7 @@ func (nM *NavigableMap) getNextMap(mp map[string]interface{}, spath string) (int if *idx < len(mv) { return mv[*idx].data, nil } - case []DataProvider: // used for cdr when populating eventCost whitin + case []utils.DataProvider: // used for cdr when populating eventCost whitin if *idx < len(mv) { return mv[*idx], nil } @@ -319,7 +359,7 @@ func (nM *NavigableMap) getIndex(spath string) (opath string, idx *int) { } // FieldAsString returns the field value as string for the path specified -// implements DataProvider +// implements utils.DataProvider func (nM *NavigableMap) FieldAsString(fldPath []string) (fldVal string, err error) { var valIface interface{} valIface, err = nM.FieldAsInterface(fldPath) @@ -329,12 +369,12 @@ func (nM *NavigableMap) FieldAsString(fldPath []string) (fldVal string, err erro return utils.IfaceAsString(valIface), nil } -// String is part of engine.DataProvider interface +// String is part of engine.utils.DataProvider interface func (nM *NavigableMap) String() string { return utils.ToJSON(nM.data) } -// RemoteHost is part of engine.DataProvider interface +// RemoteHost is part of engine.utils.DataProvider interface func (nM *NavigableMap) RemoteHost() net.Addr { return utils.LocalAddr() } @@ -369,7 +409,7 @@ func (nM *NavigableMap) Values() (vals []interface{}) { return } -// AsNavigableMap implements both NavigableMapper as well as DataProvider interfaces +// AsNavigableMap implements both NavigableMapper as well as utils.DataProvider interfaces func (nM *NavigableMap) AsNavigableMap( tpl []*FCTemplate) (oNM *NavigableMap, err error) { return nil, utils.ErrNotImplemented diff --git a/config/objdp.go b/config/objdp.go index 6c19028f6..2e48dd7cf 100644 --- a/config/objdp.go +++ b/config/objdp.go @@ -26,8 +26,8 @@ import ( "github.com/cgrates/cgrates/utils" ) -//NewObjectDP constructs a DataProvider -func NewObjectDP(obj interface{}) (dP DataProvider) { +//NewObjectDP constructs a utils.DataProvider +func NewObjectDP(obj interface{}) (dP utils.DataProvider) { dP = &ObjectDP{obj: obj, cache: make(map[string]interface{})} return } @@ -46,13 +46,13 @@ func (objDP *ObjectDP) getCache(path string) (val interface{}, has bool) { return } -// String is part of engine.DataProvider interface +// String is part of engine.utils.DataProvider interface // when called, it will display the already parsed values out of cache func (objDP *ObjectDP) String() string { return utils.ToJSON(objDP.obj) } -// FieldAsInterface is part of engine.DataProvider interface +// FieldAsInterface is part of engine.utils.DataProvider interface func (objDP *ObjectDP) FieldAsInterface(fldPath []string) (data interface{}, err error) { obj := objDP.obj // []string{ BalanceMap *monetary[0] Value } @@ -109,7 +109,7 @@ func (objDP *ObjectDP) FieldAsInterface(fldPath []string) (data interface{}, err return } -// FieldAsString is part of engine.DataProvider interface +// FieldAsString is part of engine.utils.DataProvider interface func (objDP *ObjectDP) FieldAsString(fldPath []string) (data string, err error) { var valIface interface{} valIface, err = objDP.FieldAsInterface(fldPath) @@ -119,13 +119,13 @@ func (objDP *ObjectDP) FieldAsString(fldPath []string) (data string, err error) return utils.IfaceAsString(valIface), nil } -// AsNavigableMap is part of engine.DataProvider interface +// AsNavigableMap is part of engine.utils.DataProvider interface func (objDP *ObjectDP) AsNavigableMap([]*FCTemplate) ( nm *NavigableMap, err error) { return nil, utils.ErrNotImplemented } -// RemoteHost is part of engine.DataProvider interface +// RemoteHost is part of engine.utils.DataProvider interface func (objDP *ObjectDP) RemoteHost() net.Addr { return utils.LocalAddr() } diff --git a/config/rsrparser.go b/config/rsrparser.go index 282cfbb7e..d61b40844 100644 --- a/config/rsrparser.go +++ b/config/rsrparser.go @@ -107,7 +107,7 @@ func (prsrs RSRParsers) ParseEvent(ev map[string]interface{}) (out string, err e return } -func (prsrs RSRParsers) ParseDataProvider(dP DataProvider, separator string) (out string, err error) { +func (prsrs RSRParsers) ParseDataProvider(dP utils.DataProvider, separator string) (out string, err error) { for _, prsr := range prsrs { if outPrsr, err := prsr.ParseDataProvider(dP, separator); err != nil { return "", err @@ -118,7 +118,7 @@ func (prsrs RSRParsers) ParseDataProvider(dP DataProvider, separator string) (ou return } -func (prsrs RSRParsers) ParseDataProviderWithInterfaces(dP DataProvider, separator string) (out string, err error) { +func (prsrs RSRParsers) ParseDataProviderWithInterfaces(dP utils.DataProvider, separator string) (out string, err error) { for _, prsr := range prsrs { if outPrsr, err := prsr.ParseDataProviderWithInterfaces(dP, separator); err != nil { return "", err @@ -280,7 +280,7 @@ func (prsr *RSRParser) ParseEvent(ev map[string]interface{}) (out string, err er return prsr.ParseValue(val) } -func (prsr *RSRParser) ParseDataProvider(dP DataProvider, separator string) (out string, err error) { +func (prsr *RSRParser) ParseDataProvider(dP utils.DataProvider, separator string) (out string, err error) { var outStr string if prsr.attrValue == "" { if outStr, err = dP.FieldAsString( @@ -292,7 +292,7 @@ func (prsr *RSRParser) ParseDataProvider(dP DataProvider, separator string) (out return prsr.ParseValue(outStr) } -func (prsr *RSRParser) ParseDataProviderWithInterfaces(dP DataProvider, separator string) (out string, err error) { +func (prsr *RSRParser) ParseDataProviderWithInterfaces(dP utils.DataProvider, separator string) (out string, err error) { var outIface interface{} if prsr.attrValue == "" { if outIface, err = dP.FieldAsInterface( diff --git a/config/slicedp.go b/config/slicedp.go index 3ab7793a4..ecf70f20a 100644 --- a/config/slicedp.go +++ b/config/slicedp.go @@ -26,25 +26,25 @@ import ( "github.com/cgrates/cgrates/utils" ) -// NewSliceDP constructs a DataProvider -func NewSliceDP(record []string) (dP DataProvider) { +// NewSliceDP constructs a utils.DataProvider +func NewSliceDP(record []string) (dP utils.DataProvider) { dP = &SliceDP{req: record, cache: NewNavigableMap(nil)} return } -// SliceDP implements engine.DataProvider so we can pass it to filters +// SliceDP implements engine.utils.DataProvider so we can pass it to filters type SliceDP struct { req []string cache *NavigableMap } -// String is part of engine.DataProvider interface +// String is part of engine.utils.DataProvider interface // when called, it will display the already parsed values out of cache func (cP *SliceDP) String() string { return utils.ToJSON(cP) } -// FieldAsInterface is part of engine.DataProvider interface +// FieldAsInterface is part of engine.utils.DataProvider interface func (cP *SliceDP) FieldAsInterface(fldPath []string) (data interface{}, err error) { if len(fldPath) == 0 { return @@ -69,7 +69,7 @@ func (cP *SliceDP) FieldAsInterface(fldPath []string) (data interface{}, err err return } -// FieldAsString is part of engine.DataProvider interface +// FieldAsString is part of engine.utils.DataProvider interface func (cP *SliceDP) FieldAsString(fldPath []string) (data string, err error) { var valIface interface{} valIface, err = cP.FieldAsInterface(fldPath) @@ -79,13 +79,13 @@ func (cP *SliceDP) FieldAsString(fldPath []string) (data string, err error) { return utils.IfaceAsString(valIface), nil } -// AsNavigableMap is part of engine.DataProvider interface +// AsNavigableMap is part of engine.utils.DataProvider interface func (cP *SliceDP) AsNavigableMap([]*FCTemplate) ( nm *NavigableMap, err error) { return nil, utils.ErrNotImplemented } -// RemoteHost is part of engine.DataProvider interface +// RemoteHost is part of engine.utils.DataProvider interface func (cP *SliceDP) RemoteHost() net.Addr { return utils.LocalAddr() } diff --git a/config/xmldp.go b/config/xmldp.go index c59326cd2..508c9681e 100644 --- a/config/xmldp.go +++ b/config/xmldp.go @@ -28,26 +28,26 @@ import ( "github.com/cgrates/cgrates/utils" ) -// NewXmlProvider constructs a DataProvider -func NewXmlProvider(req *xmlquery.Node, cdrPath utils.HierarchyPath) (dP DataProvider) { +// NewXmlProvider constructs a utils.DataProvider +func NewXmlProvider(req *xmlquery.Node, cdrPath utils.HierarchyPath) (dP utils.DataProvider) { dP = &XmlProvider{req: req, cdrPath: cdrPath, cache: NewNavigableMap(nil)} return } -// XmlProvider implements engine.DataProvider so we can pass it to filters +// XmlProvider implements engine.utils.DataProvider so we can pass it to filters type XmlProvider struct { req *xmlquery.Node cdrPath utils.HierarchyPath //used to compute relative path cache *NavigableMap } -// String is part of engine.DataProvider interface +// String is part of engine.utils.DataProvider interface // when called, it will display the already parsed values out of cache func (xP *XmlProvider) String() string { return utils.ToJSON(xP) } -// FieldAsInterface is part of engine.DataProvider interface +// FieldAsInterface is part of engine.utils.DataProvider interface func (xP *XmlProvider) FieldAsInterface(fldPath []string) (data interface{}, err error) { if len(fldPath) == 0 { return nil, utils.ErrNotFound @@ -81,7 +81,7 @@ func (xP *XmlProvider) FieldAsInterface(fldPath []string) (data interface{}, err return } -// FieldAsString is part of engine.DataProvider interface +// FieldAsString is part of engine.utils.DataProvider interface func (xP *XmlProvider) FieldAsString(fldPath []string) (data string, err error) { var valIface interface{} valIface, err = xP.FieldAsInterface(fldPath) @@ -91,13 +91,13 @@ func (xP *XmlProvider) FieldAsString(fldPath []string) (data string, err error) return utils.IfaceAsString(valIface), nil } -// AsNavigableMap is part of engine.DataProvider interface +// AsNavigableMap is part of engine.utils.DataProvider interface func (xP *XmlProvider) AsNavigableMap([]*FCTemplate) ( nm *NavigableMap, err error) { return nil, utils.ErrNotImplemented } -// RemoteHost is part of engine.DataProvider interface +// RemoteHost is part of engine.utils.DataProvider interface func (xP *XmlProvider) RemoteHost() net.Addr { return utils.LocalAddr() } diff --git a/engine/action.go b/engine/action.go index 491992083..6305427bc 100644 --- a/engine/action.go +++ b/engine/action.go @@ -893,7 +893,7 @@ func (apl Actions) Clone() (interface{}, error) { } // newCdrLogProvider constructs a DataProvider -func newCdrLogProvider(acnt *Account, action *Action) (dP config.DataProvider) { +func newCdrLogProvider(acnt *Account, action *Action) (dP utils.DataProvider) { dP = &cdrLogProvider{acnt: acnt, action: action, cache: config.NewNavigableMap(nil)} return } diff --git a/engine/filters.go b/engine/filters.go index 1bc870d6b..a28b4798b 100644 --- a/engine/filters.go +++ b/engine/filters.go @@ -49,7 +49,7 @@ type FilterS struct { // there should be at least one filter passing, ie: if filters are not active event will fail to pass // receives the event as DataProvider so we can accept undecoded data (ie: HttpRequest) func (fS *FilterS) Pass(tenant string, filterIDs []string, - ev config.DataProvider) (pass bool, err error) { + ev utils.DataProvider) (pass bool, err error) { if len(filterIDs) == 0 { return true, nil } @@ -112,7 +112,7 @@ func verifyPrefixes(rule *FilterRule, prefixes []string) (hasPrefix bool) { //LazyPass is almost the same as Pass except that it verify if the //Element of the Values from FilterRules has as prefix one of the pathPrfxs func (fS *FilterS) LazyPass(tenant string, filterIDs []string, - ev config.DataProvider, pathPrfxs []string) (pass bool, lazyCheckRules []*FilterRule, err error) { + ev utils.DataProvider, pathPrfxs []string) (pass bool, lazyCheckRules []*FilterRule, err error) { if len(filterIDs) == 0 { return true, nil, nil } @@ -270,7 +270,7 @@ func (fltr *FilterRule) CompileValues() (err error) { } // Pass is the method which should be used from outside. -func (fltr *FilterRule) Pass(dDP config.DataProvider) (result bool, err error) { +func (fltr *FilterRule) Pass(dDP utils.DataProvider) (result bool, err error) { if fltr.negative == nil { fltr.negative = utils.BoolPointer(strings.HasPrefix(fltr.Type, utils.MetaNot)) } @@ -305,8 +305,8 @@ func (fltr *FilterRule) Pass(dDP config.DataProvider) (result bool, err error) { return result != *(fltr.negative), nil } -func (fltr *FilterRule) passString(dDP config.DataProvider) (bool, error) { - strVal, err := config.DPDynamicString(fltr.Element, dDP) +func (fltr *FilterRule) passString(dDP utils.DataProvider) (bool, error) { + strVal, err := utils.DPDynamicString(fltr.Element, dDP) if err != nil { if err == utils.ErrNotFound { return false, nil @@ -314,7 +314,7 @@ func (fltr *FilterRule) passString(dDP config.DataProvider) (bool, error) { return false, err } for _, val := range fltr.Values { - sval, err := config.DPDynamicString(val, dDP) + sval, err := utils.DPDynamicString(val, dDP) if err != nil { continue } @@ -325,7 +325,7 @@ func (fltr *FilterRule) passString(dDP config.DataProvider) (bool, error) { return false, nil } -func (fltr *FilterRule) passExists(dDP config.DataProvider) (bool, error) { +func (fltr *FilterRule) passExists(dDP utils.DataProvider) (bool, error) { var err error path := fltr.Element if fltr.rsrFields != nil { @@ -333,7 +333,7 @@ func (fltr *FilterRule) passExists(dDP config.DataProvider) (bool, error) { return false, err } } - if _, err = config.DPDynamicInterface(path, dDP); err != nil { + if _, err = utils.DPDynamicInterface(path, dDP); err != nil { if err == utils.ErrNotFound { return false, nil } @@ -342,8 +342,8 @@ func (fltr *FilterRule) passExists(dDP config.DataProvider) (bool, error) { return true, nil } -func (fltr *FilterRule) passEmpty(fielNameDP config.DataProvider) (bool, error) { - val, err := config.DPDynamicInterface(fltr.Element, fielNameDP) +func (fltr *FilterRule) passEmpty(fielNameDP utils.DataProvider) (bool, error) { + val, err := utils.DPDynamicInterface(fltr.Element, fielNameDP) if err != nil { if err == utils.ErrNotFound { return true, nil @@ -372,8 +372,8 @@ func (fltr *FilterRule) passEmpty(fielNameDP config.DataProvider) (bool, error) } } -func (fltr *FilterRule) passStringPrefix(dDP config.DataProvider) (bool, error) { - strVal, err := config.DPDynamicString(fltr.Element, dDP) +func (fltr *FilterRule) passStringPrefix(dDP utils.DataProvider) (bool, error) { + strVal, err := utils.DPDynamicString(fltr.Element, dDP) if err != nil { if err == utils.ErrNotFound { return false, nil @@ -381,7 +381,7 @@ func (fltr *FilterRule) passStringPrefix(dDP config.DataProvider) (bool, error) return false, err } for _, prfx := range fltr.Values { - prfx, err := config.DPDynamicString(prfx, dDP) + prfx, err := utils.DPDynamicString(prfx, dDP) if err != nil { continue } @@ -392,8 +392,8 @@ func (fltr *FilterRule) passStringPrefix(dDP config.DataProvider) (bool, error) return false, nil } -func (fltr *FilterRule) passStringSuffix(dDP config.DataProvider) (bool, error) { - strVal, err := config.DPDynamicString(fltr.Element, dDP) +func (fltr *FilterRule) passStringSuffix(dDP utils.DataProvider) (bool, error) { + strVal, err := utils.DPDynamicString(fltr.Element, dDP) if err != nil { if err == utils.ErrNotFound { return false, nil @@ -401,7 +401,7 @@ func (fltr *FilterRule) passStringSuffix(dDP config.DataProvider) (bool, error) return false, err } for _, prfx := range fltr.Values { - prfx, err := config.DPDynamicString(prfx, dDP) + prfx, err := utils.DPDynamicString(prfx, dDP) if err != nil { continue } @@ -413,12 +413,12 @@ func (fltr *FilterRule) passStringSuffix(dDP config.DataProvider) (bool, error) } // ToDo when Timings will be available in DataDb -func (fltr *FilterRule) passTimings(dDP config.DataProvider) (bool, error) { +func (fltr *FilterRule) passTimings(dDP utils.DataProvider) (bool, error) { return false, utils.ErrNotImplemented } -func (fltr *FilterRule) passDestinations(dDP config.DataProvider) (bool, error) { - dst, err := config.DPDynamicString(fltr.Element, dDP) +func (fltr *FilterRule) passDestinations(dDP utils.DataProvider) (bool, error) { + dst, err := utils.DPDynamicString(fltr.Element, dDP) if err != nil { if err == utils.ErrNotFound { return false, nil @@ -433,7 +433,7 @@ func (fltr *FilterRule) passDestinations(dDP config.DataProvider) (bool, error) } for _, dID := range destIDs { for _, valDstID := range fltr.Values { - valDstID, err := config.DPDynamicString(valDstID, dDP) + valDstID, err := utils.DPDynamicString(valDstID, dDP) if err != nil { continue } @@ -446,7 +446,7 @@ func (fltr *FilterRule) passDestinations(dDP config.DataProvider) (bool, error) return false, nil } -func (fltr *FilterRule) passRSR(dDP config.DataProvider) (bool, error) { +func (fltr *FilterRule) passRSR(dDP utils.DataProvider) (bool, error) { _, err := fltr.rsrFields.ParseDataProviderWithInterfaces(dDP, utils.NestingSep) if err != nil { if err == utils.ErrNotFound || err == utils.ErrFilterNotPassingNoCaps { @@ -457,8 +457,8 @@ func (fltr *FilterRule) passRSR(dDP config.DataProvider) (bool, error) { return true, nil } -func (fltr *FilterRule) passGreaterThan(dDP config.DataProvider) (bool, error) { - fldIf, err := config.DPDynamicInterface(fltr.Element, dDP) +func (fltr *FilterRule) passGreaterThan(dDP utils.DataProvider) (bool, error) { + fldIf, err := utils.DPDynamicInterface(fltr.Element, dDP) if err != nil { if err == utils.ErrNotFound { return false, nil @@ -474,7 +474,7 @@ func (fltr *FilterRule) passGreaterThan(dDP config.DataProvider) (bool, error) { orEqual = true } for _, val := range fltr.Values { - sval, err := config.DPDynamicInterface(val, dDP) + sval, err := utils.DPDynamicInterface(val, dDP) if err != nil { continue } @@ -489,8 +489,8 @@ func (fltr *FilterRule) passGreaterThan(dDP config.DataProvider) (bool, error) { return false, nil } -func (fltr *FilterRule) passEqualTo(dDP config.DataProvider) (bool, error) { - fldIf, err := config.DPDynamicInterface(fltr.Element, dDP) +func (fltr *FilterRule) passEqualTo(dDP utils.DataProvider) (bool, error) { + fldIf, err := utils.DPDynamicInterface(fltr.Element, dDP) if err != nil { if err == utils.ErrNotFound { return false, nil @@ -501,7 +501,7 @@ func (fltr *FilterRule) passEqualTo(dDP config.DataProvider) (bool, error) { fldIf = utils.StringToInterface(fldStr) } for _, val := range fltr.Values { - sval, err := config.DPDynamicInterface(val, dDP) + sval, err := utils.DPDynamicInterface(val, dDP) if err != nil { continue } @@ -515,7 +515,7 @@ func (fltr *FilterRule) passEqualTo(dDP config.DataProvider) (bool, error) { } func newDynamicDP(cfg *config.CGRConfig, connMgr *ConnManager, - tenant string, initialDP config.DataProvider) *dynamicDP { + tenant string, initialDP utils.DataProvider) *dynamicDP { return &dynamicDP{ cfg: cfg, connMgr: connMgr, @@ -529,7 +529,7 @@ type dynamicDP struct { cfg *config.CGRConfig connMgr *ConnManager tenant string - initialDP config.DataProvider + initialDP utils.DataProvider cache *config.NavigableMap } diff --git a/engine/mapevent_test.go b/engine/mapevent_test.go index a906a15d7..1184c388b 100644 --- a/engine/mapevent_test.go +++ b/engine/mapevent_test.go @@ -56,7 +56,7 @@ func TestMapEventNewMapEvent(t *testing.T) { } func TestMapEventFieldAsInterface(t *testing.T) { - data := config.DataProvider(mapEv) + data := utils.DataProvider(mapEv) if _, err := data.FieldAsInterface([]string{"first", "second"}); err != utils.ErrNotFound { t.Error(err) } @@ -76,7 +76,7 @@ func TestMapEventFieldAsInterface(t *testing.T) { } func TestMapEventFieldAsString(t *testing.T) { - data := config.DataProvider(mapEv) + data := utils.DataProvider(mapEv) if _, err := data.FieldAsString([]string{"first", "second"}); err != utils.ErrNotFound { t.Error(err) } @@ -96,8 +96,7 @@ func TestMapEventFieldAsString(t *testing.T) { } func TestMapEventAsNavigableMap(t *testing.T) { - data := config.DataProvider(mapEv) - if rply, err := data.AsNavigableMap(nil); err != nil { + if rply, err := mapEv.AsNavigableMap(nil); err != nil { t.Error(err) } else if expected := config.NewNavigableMap(mapEv); !reflect.DeepEqual(expected, rply) { t.Errorf("Expecting %+v, received: %+v", expected, rply) @@ -105,7 +104,7 @@ func TestMapEventAsNavigableMap(t *testing.T) { } func TestMapEventRemoteHost(t *testing.T) { - data := config.DataProvider(mapEv) + data := utils.DataProvider(mapEv) if rply, expected := data.RemoteHost(), utils.LocalAddr(); !reflect.DeepEqual(expected, rply) { t.Errorf("Expecting %+v, received: %+v", expected, rply) } diff --git a/engine/safevent_test.go b/engine/safevent_test.go index 86a7bf726..265c1e340 100644 --- a/engine/safevent_test.go +++ b/engine/safevent_test.go @@ -53,7 +53,7 @@ func TestSafEventMapEvent(t *testing.T) { } func TestSafEventFieldAsInterface(t *testing.T) { - data := config.DataProvider(safEv) + data := utils.DataProvider(safEv) if _, err := data.FieldAsInterface([]string{"first", "second"}); err != utils.ErrNotFound { t.Error(err) } @@ -73,7 +73,7 @@ func TestSafEventFieldAsInterface(t *testing.T) { } func TestSafEventFieldAsString(t *testing.T) { - data := config.DataProvider(safEv) + data := utils.DataProvider(safEv) if _, err := data.FieldAsString([]string{"first", "second"}); err != utils.ErrNotFound { t.Error(err) } @@ -93,8 +93,7 @@ func TestSafEventFieldAsString(t *testing.T) { } func TestSafEventAsNavigableMap(t *testing.T) { - data := config.DataProvider(safEv) - if rply, err := data.AsNavigableMap(nil); err != nil { + if rply, err := safEv.AsNavigableMap(nil); err != nil { t.Error(err) } else if expected := config.NewNavigableMap(sMap); !reflect.DeepEqual(expected, rply) { t.Errorf("Expecting %+v, received: %+v", expected, rply) @@ -102,7 +101,7 @@ func TestSafEventAsNavigableMap(t *testing.T) { } func TestSafEventRemoteHost(t *testing.T) { - data := config.DataProvider(safEv) + data := utils.DataProvider(safEv) if rply, expected := data.RemoteHost(), utils.LocalAddr(); !reflect.DeepEqual(expected, rply) { t.Errorf("Expecting %+v, received: %+v", expected, rply) } diff --git a/engine/task.go b/engine/task.go index 5ef89c824..9635ce23d 100644 --- a/engine/task.go +++ b/engine/task.go @@ -41,12 +41,12 @@ func (t *Task) Execute() error { }).Execute(nil, nil) } -// String implements config.DataProvider +// String implements utils.DataProvider func (t *Task) String() string { return utils.ToJSON(t) } -// AsNavigableMap implements config.DataProvider +// AsNavigableMap implements utils.DataProvider func (t *Task) AsNavigableMap(_ []*config.FCTemplate) (nm *config.NavigableMap, err error) { nm = config.NewNavigableMap(nil) nm.Set([]string{utils.UUID}, t.Uuid, false, false) @@ -55,13 +55,13 @@ func (t *Task) AsNavigableMap(_ []*config.FCTemplate) (nm *config.NavigableMap, return } -// FieldAsInterface implements config.DataProvider +// FieldAsInterface implements utils.DataProvider // ToDo: support Action fields func (t *Task) FieldAsInterface(fldPath []string) (iface interface{}, err error) { return t.FieldAsString(fldPath) } -// FieldAsInterface implements config.DataProvider +// FieldAsInterface implements utils.DataProvider // ToDo: support Action fields func (t *Task) FieldAsString(fldPath []string) (s string, err error) { if len(fldPath) == 0 { @@ -82,7 +82,7 @@ func (t *Task) FieldAsString(fldPath []string) (s string, err error) { } } -// RemoteHost implements config.DataProvider +// RemoteHost implements utils.DataProvider func (t *Task) RemoteHost() (rh net.Addr) { return } diff --git a/ers/filefwv.go b/ers/filefwv.go index 18480e881..7295d3ecb 100644 --- a/ers/filefwv.go +++ b/ers/filefwv.go @@ -74,8 +74,8 @@ type FWVFileER struct { headerOffset int64 trailerOffset int64 // Index where trailer starts, to be used as boundary when reading cdrs trailerLenght int64 - headerDP config.DataProvider - trailerDP config.DataProvider + headerDP utils.DataProvider + trailerDP utils.DataProvider } func (rdr *FWVFileER) Config() *config.EventReaderCfg { diff --git a/loaders/libloader.go b/loaders/libloader.go index 1bbca6ced..8985d0c12 100644 --- a/loaders/libloader.go +++ b/loaders/libloader.go @@ -84,7 +84,7 @@ func (ld LoaderData) UpdateFromCSV(fileName string, record []string, } // newCsvProvider constructs a DataProvider -func newCsvProvider(record []string, fileName string) (dP config.DataProvider) { +func newCsvProvider(record []string, fileName string) (dP utils.DataProvider) { dP = &csvProvider{req: record, fileName: fileName, cache: config.NewNavigableMap(nil)} return } diff --git a/utils/dataprovider.go b/utils/dataprovider.go index e7bc6e9c2..2f46668c4 100644 --- a/utils/dataprovider.go +++ b/utils/dataprovider.go @@ -79,30 +79,30 @@ type NMInterface interface { // navMap subset of function for NM interface type navMap interface { Field(path PathItems) (val NMInterface, err error) - Set(path PathItems, val NMInterface) (addedNew bool, err error) + Set(fullpath *FullPath, val NMInterface) (addedNew bool, err error) } // AppendNavMapVal appends value to the map -func AppendNavMapVal(nm navMap, fldPath PathItems, val NMInterface) (err error) { +func AppendNavMapVal(nm navMap, fldPath *FullPath, val NMInterface) (err error) { var prevItm NMInterface var indx int - if prevItm, err = nm.Field(fldPath); err != nil { + if prevItm, err = nm.Field(fldPath.PathItems); err != nil { if err != ErrNotFound { return } } else { indx = prevItm.Len() } - fldPath[len(fldPath)-1].Index = &indx + fldPath.PathItems[len(fldPath.PathItems)-1].Index = &indx _, err = nm.Set(fldPath, val) return } // ComposeNavMapVal compose adds value to prevision item -func ComposeNavMapVal(nm navMap, fldPath PathItems, val NMInterface) (err error) { +func ComposeNavMapVal(nm navMap, fldPath *FullPath, val NMInterface) (err error) { var prevItmSlice NMInterface var indx int - if prevItmSlice, err = nm.Field(fldPath); err != nil { + if prevItmSlice, err = nm.Field(fldPath.PathItems); err != nil { if err != ErrNotFound { return } @@ -117,7 +117,7 @@ func ComposeNavMapVal(nm navMap, fldPath PathItems, val NMInterface) (err error) return } } - fldPath[len(fldPath)-1].Index = &indx + fldPath.PathItems[len(fldPath.PathItems)-1].Index = &indx _, err = nm.Set(fldPath, val) return } diff --git a/utils/orderednavigablemap.go b/utils/orderednavigablemap.go index 92e02d07f..940e0cad3 100644 --- a/utils/orderednavigablemap.go +++ b/utils/orderednavigablemap.go @@ -70,7 +70,7 @@ func (onm *OrderedNavigableMap) Empty() bool { } // Remove removes the item for the given path and updates the order -func (onm *OrderedNavigableMap) Remove(fullPath FullPath) (err error) { +func (onm *OrderedNavigableMap) Remove(fullPath *FullPath) (err error) { path := stripIdxFromLastPathElm(fullPath.Path) if path == EmptyString || fullPath.PathItems[len(fullPath.PathItems)-1].Index != nil { return ErrWrongPath @@ -91,16 +91,16 @@ func (onm *OrderedNavigableMap) Remove(fullPath FullPath) (err error) { return } -// Set sets the value at the given path -// this is the old to be capable of building the code without updating all the code -// will be replaced with Set2 after we decide that is the optimal solution -func (onm *OrderedNavigableMap) Set(fldPath PathItems, val NMInterface) (addedNew bool, err error) { - return onm.Set2(&FullPath{PathItems: fldPath, Path: fldPath.String()}, val) -} +// // Set sets the value at the given path +// // this is the old to be capable of building the code without updating all the code +// // will be replaced with Set2 after we decide that is the optimal solution +// func (onm *OrderedNavigableMap) Set(fldPath PathItems, val NMInterface) (addedNew bool, err error) { +// return onm.Set2(&FullPath{PathItems: fldPath, Path: fldPath.String()}, val) +// } -// Set2 sets the value at the given path +// Set sets the value at the given path // this used with full path and the processed path to not calculate them for every set -func (onm *OrderedNavigableMap) Set2(fullPath *FullPath, val NMInterface) (addedNew bool, err error) { +func (onm *OrderedNavigableMap) Set(fullPath *FullPath, val NMInterface) (addedNew bool, err error) { if len(fullPath.PathItems) == 0 { return false, ErrWrongPath } @@ -182,3 +182,10 @@ func (onm *OrderedNavigableMap) GetOrder() (order []PathItems) { } return } + +// RemoveAll will clean the data and the odrder from OrderedNavigableMap +func (onm *OrderedNavigableMap) RemoveAll() { + onm.nm = NavigableMap2{} + onm.orderIdx = NewPathItemList() + onm.orderRef = make(map[string][]*PathItemElement) +}