mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
NavigableMap with ordered items
This commit is contained in:
@@ -60,7 +60,7 @@ func (ha *HTTPAgent) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
}
|
||||
var processed bool
|
||||
procVars := make(processorVars)
|
||||
rpl := newHTTPReplyFields()
|
||||
rpl := engine.NewNavigableMap(nil)
|
||||
for _, reqProcessor := range ha.reqProcessors {
|
||||
var lclProcessed bool
|
||||
if lclProcessed, err = ha.processRequest(reqProcessor, dcdr,
|
||||
@@ -101,8 +101,7 @@ func (ha *HTTPAgent) ServeHTTP(w http.ResponseWriter, req *http.Request) {
|
||||
// processRequest represents one processor processing the request
|
||||
func (ha *HTTPAgent) processRequest(reqProcessor *config.HttpAgntProcCfg,
|
||||
dP engine.DataProvider, procVars processorVars,
|
||||
reply *httpReplyFields) (processed bool, err error) {
|
||||
|
||||
reply *engine.NavigableMap) (processed bool, err error) {
|
||||
tnt, err := dP.FieldAsString([]string{utils.Tenant})
|
||||
if err != nil {
|
||||
return false, err
|
||||
@@ -116,11 +115,11 @@ func (ha *HTTPAgent) processRequest(reqProcessor *config.HttpAgntProcCfg,
|
||||
procVars[k] = strconv.FormatBool(v)
|
||||
}
|
||||
if reqProcessor.DryRun {
|
||||
utils.Logger.Info(fmt.Sprintf("<%s> DRY_RUN, RADIUS request: %s", utils.RadiusAgent, dP))
|
||||
utils.Logger.Info(fmt.Sprintf("<%s> DRY_RUN, process variabiles: %+v", utils.RadiusAgent, procVars))
|
||||
utils.Logger.Info(fmt.Sprintf("<%s> DRY_RUN, HTTP request: %s", utils.HTTPAgent, dP))
|
||||
utils.Logger.Info(fmt.Sprintf("<%s> DRY_RUN, process variables: %+v", utils.HTTPAgent, procVars))
|
||||
}
|
||||
/*
|
||||
cgrEv, err := radReqAsCGREvent(req, procVars, reqProcessor.Flags, reqProcessor.RequestFields)
|
||||
ev, err := radReqAsCGREvent(req, procVars, reqProcessor.Flags, reqProcessor.RequestFields)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
@@ -27,7 +27,6 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/cgrates/cgrates/config"
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
"github.com/cgrates/cgrates/sessions"
|
||||
"github.com/cgrates/cgrates/utils"
|
||||
"github.com/fiorix/go-diameter/diam"
|
||||
@@ -215,24 +214,35 @@ func TestFieldOutVal(t *testing.T) {
|
||||
t.Errorf("Expecting:\n%s\nReceived:\n%s", eOut, fldOut)
|
||||
}
|
||||
// Without groupedAVP, we shoud get the first subscriptionId
|
||||
cfgFld = &config.CfgCdrField{Tag: "Grouped2", Type: utils.MetaGrouped, FieldId: "Account",
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("Subscription-Id>Subscription-Id-Type(1)", utils.INFIELD_SEP),
|
||||
Value: utils.ParseRSRFieldsMustCompile("Subscription-Id>Subscription-Id-Data", utils.INFIELD_SEP), Mandatory: true}
|
||||
cfgFld = &config.CfgCdrField{
|
||||
Tag: "Grouped2",
|
||||
Type: utils.MetaGrouped, FieldId: "Account",
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile(
|
||||
"Subscription-Id>Subscription-Id-Type(1)", utils.INFIELD_SEP),
|
||||
Value: utils.ParseRSRFieldsMustCompile(
|
||||
"Subscription-Id>Subscription-Id-Data", utils.INFIELD_SEP), Mandatory: true}
|
||||
eOut = "208708000003"
|
||||
if fldOut, err := fieldOutVal(m, cfgFld, time.Duration(0), nil); err != nil {
|
||||
t.Error(err)
|
||||
} else if fldOut != eOut {
|
||||
t.Errorf("Expecting:\n%s\nReceived:\n%s", eOut, fldOut)
|
||||
}
|
||||
cfgFld = &config.CfgCdrField{Tag: "TestMultipleFiltersEmptyReply", Type: utils.META_COMPOSED, FieldId: "Account",
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile("*cgrReply>Error(^$);*cgrReply>MaxUsage(!300);*cgrReply>MaxUsage(!0)", utils.INFIELD_SEP),
|
||||
Value: utils.ParseRSRFieldsMustCompile("Subscription-Id>Subscription-Id-Data", utils.INFIELD_SEP), Mandatory: true}
|
||||
cfgFld = &config.CfgCdrField{
|
||||
Tag: "TestMultipleFiltersEmptyReply",
|
||||
Type: utils.META_COMPOSED, FieldId: "Account",
|
||||
FieldFilter: utils.ParseRSRFieldsMustCompile(
|
||||
"*cgrReply>Error(^$);*cgrReply>MaxUsage(!300);*cgrReply>MaxUsage(!0)",
|
||||
utils.INFIELD_SEP),
|
||||
Value: utils.ParseRSRFieldsMustCompile(
|
||||
"Subscription-Id>Subscription-Id-Data", utils.INFIELD_SEP),
|
||||
Mandatory: true}
|
||||
procVars := processorVars{
|
||||
utils.MetaCGRReply: engine.NavigableMap{
|
||||
utils.MetaCGRReply: map[string]interface{}{
|
||||
utils.Error: "RALS_ERROR:NOT_FOUND",
|
||||
},
|
||||
}
|
||||
if _, err := fieldOutVal(m, cfgFld, time.Duration(0), procVars); err != ErrFilterNotPassing {
|
||||
if _, err := fieldOutVal(m, cfgFld, time.Duration(0),
|
||||
procVars); err != ErrFilterNotPassing {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,24 +25,6 @@ import (
|
||||
"github.com/cgrates/cgrates/engine"
|
||||
)
|
||||
|
||||
// httpReplyField is one field written in HTTP reply
|
||||
type httpReplyField struct {
|
||||
fldPath string
|
||||
fldVal string
|
||||
}
|
||||
|
||||
func newHTTPReplyFields() *httpReplyFields {
|
||||
return &httpReplyFields{indexed: make(map[string]*httpReplyField),
|
||||
ordered: make([]*httpReplyField, 0)}
|
||||
}
|
||||
|
||||
// httpReplyFields is the reply which will be written to HTTP
|
||||
// both flds and ordered are pointig towards same httpReplyField
|
||||
type httpReplyFields struct {
|
||||
indexed map[string]*httpReplyField // map[fldPath]*httpReplyField
|
||||
ordered []*httpReplyField // keep order for export
|
||||
}
|
||||
|
||||
// newHAReqDecoder produces decoders
|
||||
func newHADataProvider(dpType string,
|
||||
req *http.Request) (dP engine.DataProvider, err error) {
|
||||
@@ -61,8 +43,8 @@ func newHAReplyEncoder(encType string,
|
||||
}
|
||||
}
|
||||
|
||||
// httpAgentReplyEncoder will encode fields from httpReplyFields
|
||||
// httpAgentReplyEncoder will encode []*engine.NMElement
|
||||
// and write content to http writer
|
||||
type httpAgentReplyEncoder interface {
|
||||
encode(*httpReplyFields) error
|
||||
encode(*engine.NavigableMap) error
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ func (pv processorVars) valAsInterface(fldPath string) (val interface{}, err err
|
||||
err = errors.New("not found")
|
||||
return
|
||||
}
|
||||
return engine.NavigableMap(pv).FieldAsInterface(strings.Split(fldPath, utils.HIERARCHY_SEP))
|
||||
return engine.NewNavigableMap(pv).FieldAsInterface(strings.Split(fldPath, utils.HIERARCHY_SEP))
|
||||
}
|
||||
|
||||
// valAsString returns the string value for fldName
|
||||
@@ -75,7 +75,7 @@ func (pv processorVars) valAsString(fldPath string) (val string, err error) {
|
||||
if !pv.hasVar(fldName) {
|
||||
return "", utils.ErrNotFoundNoCaps
|
||||
}
|
||||
return engine.NavigableMap(pv).FieldAsString(strings.Split(fldPath, utils.HIERARCHY_SEP))
|
||||
return engine.NewNavigableMap(pv).FieldAsString(strings.Split(fldPath, utils.HIERARCHY_SEP))
|
||||
}
|
||||
|
||||
// asV1AuthorizeArgs returns the arguments needed by SessionSv1.AuthorizeEvent
|
||||
@@ -411,6 +411,7 @@ func NewCGRReply(rply engine.NavigableMapper,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nM[utils.Error] = "" // enforce empty error
|
||||
return map[string]interface{}(nM), nil // convert from NM to map due to decapsulation later
|
||||
mp = nM.AsMapStringInterface()
|
||||
mp[utils.Error] = "" // enforce empty error
|
||||
return mp, nil
|
||||
}
|
||||
|
||||
@@ -428,8 +428,8 @@ func TestRadReplyAppendAttributes(t *testing.T) {
|
||||
|
||||
type myEv map[string]interface{}
|
||||
|
||||
func (ev myEv) AsNavigableMap(tpl []*config.CfgCdrField) (engine.NavigableMap, error) {
|
||||
return engine.NavigableMap(ev), nil
|
||||
func (ev myEv) AsNavigableMap(tpl []*config.CfgCdrField) (*engine.NavigableMap, error) {
|
||||
return engine.NewNavigableMap(ev), nil
|
||||
}
|
||||
|
||||
func TestNewCGRReply(t *testing.T) {
|
||||
@@ -439,7 +439,8 @@ func TestNewCGRReply(t *testing.T) {
|
||||
if rpl, err := NewCGRReply(nil, errors.New("some")); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eCgrRply, rpl) {
|
||||
t.Errorf("Expecting: %+v, received: %+v", utils.ToJSON(eCgrRply), utils.ToJSON(rpl))
|
||||
t.Errorf("Expecting: %+v, received: %+v",
|
||||
utils.ToJSON(eCgrRply), utils.ToJSON(rpl))
|
||||
}
|
||||
ev := myEv{
|
||||
"FirstLevel": map[string]interface{}{
|
||||
|
||||
@@ -91,7 +91,7 @@ func (alS *AttributeService) matchingAttributeProfilesForEvent(ev *utils.CGREven
|
||||
continue
|
||||
}
|
||||
if pass, err := alS.filterS.Pass(ev.Tenant, aPrfl.FilterIDs,
|
||||
NavigableMap(ev.Event)); err != nil {
|
||||
NewNavigableMap(ev.Event)); err != nil {
|
||||
return nil, err
|
||||
} else if !pass {
|
||||
continue
|
||||
|
||||
@@ -1456,6 +1456,6 @@ func (cd *CallDescriptor) String() string {
|
||||
}
|
||||
|
||||
// AsNavigableMap is part of utils.DataProvider
|
||||
func (cd *CallDescriptor) AsNavigableMap(tpl []*config.CfgCdrField) (nM NavigableMap, err error) {
|
||||
return
|
||||
func (cd *CallDescriptor) AsNavigableMap(tpl []*config.CfgCdrField) (nM *NavigableMap, err error) {
|
||||
return nil, utils.ErrNotImplemented
|
||||
}
|
||||
|
||||
@@ -27,5 +27,5 @@ type DataProvider interface {
|
||||
FieldAsInterface(fldPath []string) (interface{}, error)
|
||||
FieldAsString(fldPath []string) (string, error)
|
||||
String() string // printable versin of data
|
||||
AsNavigableMap(cfgFlds []*config.CfgCdrField) (NavigableMap, error)
|
||||
AsNavigableMap([]*config.CfgCdrField) (*NavigableMap, error)
|
||||
}
|
||||
|
||||
@@ -154,16 +154,16 @@ func TestFilterPassGreaterThan(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
ev := NavigableMap{
|
||||
"ASR": 20,
|
||||
ev := &NavigableMap{
|
||||
data: map[string]interface{}{"ASR": 20},
|
||||
}
|
||||
if passes, err := rf.passGreaterThan(ev); err != nil {
|
||||
t.Error(err)
|
||||
} else if !passes {
|
||||
t.Error("not passing")
|
||||
}
|
||||
ev = map[string]interface{}{
|
||||
"ASR": 40,
|
||||
ev = &NavigableMap{
|
||||
data: map[string]interface{}{"ASR": 40},
|
||||
}
|
||||
if passes, err := rf.passGreaterThan(ev); err != nil {
|
||||
t.Error(err)
|
||||
@@ -188,8 +188,8 @@ func TestFilterPassGreaterThan(t *testing.T) {
|
||||
} else if !passes {
|
||||
t.Error("not passing")
|
||||
}
|
||||
ev = map[string]interface{}{
|
||||
"ASR": 20,
|
||||
ev = &NavigableMap{
|
||||
data: map[string]interface{}{"ASR": 20},
|
||||
}
|
||||
if passes, err := rf.passGreaterThan(ev); err != nil {
|
||||
t.Error(err)
|
||||
@@ -200,8 +200,8 @@ func TestFilterPassGreaterThan(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
ev = map[string]interface{}{
|
||||
"ACD": time.Duration(2 * time.Minute),
|
||||
ev = &NavigableMap{
|
||||
data: map[string]interface{}{"ACD": time.Duration(2 * time.Minute)},
|
||||
}
|
||||
if passes, err := rf.passGreaterThan(ev); err != nil {
|
||||
t.Error(err)
|
||||
@@ -296,13 +296,13 @@ func TestInlineFilterPassFiltersForEvent(t *testing.T) {
|
||||
t.Errorf(err.Error())
|
||||
}
|
||||
if pass, err := filterS.Pass("cgrates.org",
|
||||
[]string{"*string:Account:1007"}, NavigableMap(failEvent)); err != nil {
|
||||
[]string{"*string:Account:1007"}, NewNavigableMap(failEvent)); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
} else if pass {
|
||||
t.Errorf("Expecting: %+v, received: %+v", false, pass)
|
||||
}
|
||||
if pass, err := filterS.Pass("cgrates.org",
|
||||
[]string{"*string:Account:1007"}, NavigableMap(passEvent)); err != nil {
|
||||
[]string{"*string:Account:1007"}, NewNavigableMap(passEvent)); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
} else if !pass {
|
||||
t.Errorf("Expecting: %+v, received: %+v", true, pass)
|
||||
@@ -314,13 +314,13 @@ func TestInlineFilterPassFiltersForEvent(t *testing.T) {
|
||||
"Account": "1007",
|
||||
}
|
||||
if pass, err := filterS.Pass("cgrates.org",
|
||||
[]string{"*prefix:Account:10"}, NavigableMap(failEvent)); err != nil {
|
||||
[]string{"*prefix:Account:10"}, NewNavigableMap(failEvent)); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
} else if pass {
|
||||
t.Errorf("Expecting: %+v, received: %+v", false, pass)
|
||||
}
|
||||
if pass, err := filterS.Pass("cgrates.org",
|
||||
[]string{"*prefix:Account:10"}, NavigableMap(passEvent)); err != nil {
|
||||
[]string{"*prefix:Account:10"}, NewNavigableMap(passEvent)); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
} else if !pass {
|
||||
t.Errorf("Expecting: %+v, received: %+v", true, pass)
|
||||
@@ -332,13 +332,13 @@ func TestInlineFilterPassFiltersForEvent(t *testing.T) {
|
||||
"Tenant": "cgrates.org",
|
||||
}
|
||||
if pass, err := filterS.Pass("cgrates.org",
|
||||
[]string{"*rsr::Tenant(~^cgr.*\\.org$)"}, NavigableMap(failEvent)); err != nil {
|
||||
[]string{"*rsr::Tenant(~^cgr.*\\.org$)"}, NewNavigableMap(failEvent)); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
} else if pass {
|
||||
t.Errorf("Expecting: %+v, received: %+v", false, pass)
|
||||
}
|
||||
if pass, err := filterS.Pass("cgrates.org",
|
||||
[]string{"*rsr::Tenant(~^cgr.*\\.org$)"}, NavigableMap(passEvent)); err != nil {
|
||||
[]string{"*rsr::Tenant(~^cgr.*\\.org$)"}, NewNavigableMap(passEvent)); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
} else if !pass {
|
||||
t.Errorf("Expecting: %+v, received: %+v", true, pass)
|
||||
@@ -352,13 +352,13 @@ func TestInlineFilterPassFiltersForEvent(t *testing.T) {
|
||||
utils.Destination: "+4986517174963",
|
||||
}
|
||||
if pass, err := filterS.Pass("cgrates.org",
|
||||
[]string{"*destinations:Destination:EU"}, NavigableMap(failEvent)); err != nil {
|
||||
[]string{"*destinations:Destination:EU"}, NewNavigableMap(failEvent)); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
} else if pass {
|
||||
t.Errorf("Expecting: %+v, received: %+v", false, pass)
|
||||
}
|
||||
if pass, err := filterS.Pass("cgrates.org",
|
||||
[]string{"*destinations:Destination:EU_LANDLINE"}, NavigableMap(passEvent)); err != nil {
|
||||
[]string{"*destinations:Destination:EU_LANDLINE"}, NewNavigableMap(passEvent)); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
} else if !pass {
|
||||
t.Errorf("Expecting: %+v, received: %+v", true, pass)
|
||||
@@ -370,13 +370,13 @@ func TestInlineFilterPassFiltersForEvent(t *testing.T) {
|
||||
utils.Weight: 20,
|
||||
}
|
||||
if pass, err := filterS.Pass("cgrates.org",
|
||||
[]string{"*gte:Weight:20"}, NavigableMap(failEvent)); err != nil {
|
||||
[]string{"*gte:Weight:20"}, NewNavigableMap(failEvent)); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
} else if pass {
|
||||
t.Errorf("Expecting: %+v, received: %+v", false, pass)
|
||||
}
|
||||
if pass, err := filterS.Pass("cgrates.org",
|
||||
[]string{"*gte:Weight:10"}, NavigableMap(passEvent)); err != nil {
|
||||
[]string{"*gte:Weight:10"}, NewNavigableMap(passEvent)); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
} else if !pass {
|
||||
t.Errorf("Expecting: %+v, received: %+v", true, pass)
|
||||
@@ -404,13 +404,13 @@ func TestPassFiltersForEventWithEmptyFilter(t *testing.T) {
|
||||
utils.Weight: 20,
|
||||
}
|
||||
if pass, err := filterS.Pass("cgrates.org",
|
||||
[]string{}, NavigableMap(passEvent1)); err != nil {
|
||||
[]string{}, NewNavigableMap(passEvent1)); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
} else if !pass {
|
||||
t.Errorf("Expecting: %+v, received: %+v", false, pass)
|
||||
}
|
||||
if pass, err := filterS.Pass("itsyscom.com",
|
||||
[]string{}, NavigableMap(passEvent2)); err != nil {
|
||||
[]string{}, NewNavigableMap(passEvent2)); err != nil {
|
||||
t.Errorf(err.Error())
|
||||
} else if !pass {
|
||||
t.Errorf("Expecting: %+v, received: %+v", true, pass)
|
||||
|
||||
@@ -28,20 +28,50 @@ import (
|
||||
|
||||
// CGRReplier is the interface supported by replies convertible to CGRReply
|
||||
type NavigableMapper interface {
|
||||
AsNavigableMap([]*config.CfgCdrField) (NavigableMap, error)
|
||||
AsNavigableMap([]*config.CfgCdrField) (*NavigableMap, error)
|
||||
}
|
||||
|
||||
// NewNavigableMap constructs a NavigableMap
|
||||
func NewNavigableMap(data map[string]interface{}) *NavigableMap {
|
||||
if data == nil {
|
||||
data = make(map[string]interface{})
|
||||
}
|
||||
return &NavigableMap{data: data}
|
||||
}
|
||||
|
||||
// NavigableMap is a map who's values can be navigated via path
|
||||
type NavigableMap map[string]interface{}
|
||||
// data can be retrieved as ordered
|
||||
// NavigableMap is not thread safe due to performance demands, could come back if needed
|
||||
type NavigableMap struct {
|
||||
data map[string]interface{} // layered map
|
||||
order [][]string // order of field paths
|
||||
}
|
||||
|
||||
// Add will add items into NavigableMap populating also order
|
||||
func (nM *NavigableMap) Add(path []string, data interface{}) {
|
||||
nM.order = append(nM.order)
|
||||
mp := nM.data
|
||||
for i, spath := range path {
|
||||
_, has := mp[spath]
|
||||
if !has {
|
||||
if i == len(path)-1 { // last path
|
||||
mp[spath] = data
|
||||
return
|
||||
}
|
||||
mp[spath] = make(map[string]interface{})
|
||||
}
|
||||
mp = mp[spath].(map[string]interface{}) // so we can check further down
|
||||
}
|
||||
}
|
||||
|
||||
// FieldAsInterface returns the field value as interface{} for the path specified
|
||||
// implements DataProvider
|
||||
func (nM NavigableMap) FieldAsInterface(fldPath []string) (fldVal interface{}, err error) {
|
||||
func (nM *NavigableMap) FieldAsInterface(fldPath []string) (fldVal interface{}, err error) {
|
||||
lenPath := len(fldPath)
|
||||
if lenPath == 0 {
|
||||
return nil, errors.New("empty field path")
|
||||
}
|
||||
lastMp := nM // last map when layered
|
||||
lastMp := nM.data // last map when layered
|
||||
var canCast bool
|
||||
for i, spath := range fldPath {
|
||||
if i == lenPath-1 { // lastElement
|
||||
@@ -71,7 +101,7 @@ func (nM NavigableMap) FieldAsInterface(fldPath []string) (fldVal interface{}, e
|
||||
|
||||
// FieldAsString returns the field value as string for the path specified
|
||||
// implements DataProvider
|
||||
func (nM NavigableMap) FieldAsString(fldPath []string) (fldVal string, err error) {
|
||||
func (nM *NavigableMap) FieldAsString(fldPath []string) (fldVal string, err error) {
|
||||
var valIface interface{}
|
||||
valIface, err = nM.FieldAsInterface(fldPath)
|
||||
if err != nil {
|
||||
@@ -84,11 +114,51 @@ func (nM NavigableMap) FieldAsString(fldPath []string) (fldVal string, err error
|
||||
return
|
||||
}
|
||||
|
||||
func (nM NavigableMap) String() string {
|
||||
return utils.ToJSON(nM)
|
||||
func (nM *NavigableMap) String() string {
|
||||
return utils.ToJSON(nM.data)
|
||||
}
|
||||
|
||||
// AsMapStringInterface returns the data out of map, ignoring the order part
|
||||
func (nM *NavigableMap) AsMapStringInterface() map[string]interface{} {
|
||||
return nM.data
|
||||
}
|
||||
|
||||
type NMItem struct {
|
||||
Path []string // path in map
|
||||
Data interface{} // value of the element
|
||||
}
|
||||
|
||||
// indexMapElements will recursively go through map and index the element paths into elmns
|
||||
func indexMapElements(mp map[string]interface{}, path []string, elms *[]*NMItem) {
|
||||
for k, v := range mp {
|
||||
vPath := append(path, k)
|
||||
if mpIface, isMap := v.(map[string]interface{}); isMap {
|
||||
indexMapElements(mpIface, vPath, elms)
|
||||
} else {
|
||||
elmsOut := append(*elms, &NMItem{vPath, v})
|
||||
*elms = elmsOut
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Items returns the items in map, ordered by order information
|
||||
func (nM *NavigableMap) Items() (itms []*NMItem) {
|
||||
if len(nM.data) == 0 {
|
||||
return
|
||||
}
|
||||
if len(nM.order) == 0 {
|
||||
indexMapElements(nM.data, []string{}, &itms)
|
||||
return
|
||||
}
|
||||
itms = make([]*NMItem, len(nM.order))
|
||||
for i, path := range nM.order {
|
||||
val, _ := nM.FieldAsInterface(path)
|
||||
itms[i] = &NMItem{Data: val, Path: path}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// AsNavigableMap implements both NavigableMapper as well as DataProvider interfaces
|
||||
func (nM NavigableMap) AsNavigableMap(tpl []*config.CfgCdrField) (oNM NavigableMap, err error) {
|
||||
return
|
||||
func (nM *NavigableMap) AsNavigableMap(tpl []*config.CfgCdrField) (oNM *NavigableMap, err error) {
|
||||
return nil, utils.ErrNotImplemented
|
||||
}
|
||||
|
||||
@@ -24,15 +24,17 @@ import (
|
||||
)
|
||||
|
||||
func TestNavMapGetFieldAsString(t *testing.T) {
|
||||
nM := NavigableMap{
|
||||
"FirstLevel": map[string]interface{}{
|
||||
"SecondLevel": map[string]interface{}{
|
||||
"ThirdLevel": map[string]interface{}{
|
||||
"Fld1": "Val1",
|
||||
nM := &NavigableMap{
|
||||
data: map[string]interface{}{
|
||||
"FirstLevel": map[string]interface{}{
|
||||
"SecondLevel": map[string]interface{}{
|
||||
"ThirdLevel": map[string]interface{}{
|
||||
"Fld1": "Val1",
|
||||
},
|
||||
},
|
||||
},
|
||||
"AnotherFirstLevel": "ValAnotherFirstLevel",
|
||||
},
|
||||
"AnotherFirstLevel": "ValAnotherFirstLevel",
|
||||
}
|
||||
eVal := "Val1"
|
||||
if strVal, err := nM.FieldAsString(
|
||||
@@ -57,6 +59,6 @@ func TestNavMapGetFieldAsString(t *testing.T) {
|
||||
|
||||
type myEv map[string]interface{}
|
||||
|
||||
func (ev myEv) AsNavigableMap() (map[string]interface{}, error) {
|
||||
return NavigableMap(ev), nil
|
||||
func (ev myEv) AsNavigableMap() (*NavigableMap, error) {
|
||||
return NewNavigableMap(ev), nil
|
||||
}
|
||||
|
||||
@@ -464,7 +464,7 @@ func (rS *ResourceService) matchingResourcesForEvent(ev *utils.CGREvent, usageTT
|
||||
continue
|
||||
}
|
||||
if pass, err := rS.filterS.Pass(ev.Tenant, rPrf.FilterIDs,
|
||||
NavigableMap(ev.Event)); err != nil {
|
||||
NewNavigableMap(ev.Event)); err != nil {
|
||||
return nil, err
|
||||
} else if !pass {
|
||||
continue
|
||||
|
||||
@@ -169,7 +169,7 @@ func (sS *StatService) matchingStatQueuesForEvent(ev *utils.CGREvent) (sqs StatQ
|
||||
continue
|
||||
}
|
||||
if pass, err := sS.filterS.Pass(ev.Tenant, sqPrfl.FilterIDs,
|
||||
NavigableMap(ev.Event)); err != nil {
|
||||
NewNavigableMap(ev.Event)); err != nil {
|
||||
return nil, err
|
||||
} else if !pass {
|
||||
continue
|
||||
|
||||
@@ -137,7 +137,7 @@ func (spS *SupplierService) matchingSupplierProfilesForEvent(ev *utils.CGREvent)
|
||||
continue
|
||||
}
|
||||
if pass, err := spS.filterS.Pass(ev.Tenant, splPrfl.FilterIDs,
|
||||
NavigableMap(ev.Event)); err != nil {
|
||||
NewNavigableMap(ev.Event)); err != nil {
|
||||
return nil, err
|
||||
} else if !pass {
|
||||
continue
|
||||
@@ -277,7 +277,7 @@ func (spS *SupplierService) sortedSuppliersForEvent(args *ArgsGetSuppliers) (sor
|
||||
for _, s := range splPrfl.Suppliers {
|
||||
if len(s.FilterIDs) != 0 { // filters should be applied, check them here
|
||||
if pass, err := spS.filterS.Pass(args.Tenant, s.FilterIDs,
|
||||
NavigableMap(args.Event)); err != nil {
|
||||
NewNavigableMap(args.Event)); err != nil {
|
||||
return nil, err
|
||||
} else if !pass {
|
||||
continue
|
||||
|
||||
@@ -246,7 +246,7 @@ func (tS *ThresholdService) matchingThresholdsForEvent(args *ArgsProcessEvent) (
|
||||
continue
|
||||
}
|
||||
if pass, err := tS.filterS.Pass(args.Tenant, tPrfl.FilterIDs,
|
||||
NavigableMap(args.Event)); err != nil {
|
||||
NewNavigableMap(args.Event)); err != nil {
|
||||
return nil, err
|
||||
} else if !pass {
|
||||
continue
|
||||
|
||||
@@ -1337,8 +1337,9 @@ type V1AuthorizeReply struct {
|
||||
}
|
||||
|
||||
// AsNavigableMap is part of engine.NavigableMapper interface
|
||||
func (v1AuthReply *V1AuthorizeReply) AsNavigableMap(ignr []*config.CfgCdrField) (cgrReply engine.NavigableMap, err error) {
|
||||
cgrReply = make(map[string]interface{})
|
||||
func (v1AuthReply *V1AuthorizeReply) AsNavigableMap(
|
||||
ignr []*config.CfgCdrField) (*engine.NavigableMap, error) {
|
||||
cgrReply := make(map[string]interface{})
|
||||
if v1AuthReply.Attributes != nil {
|
||||
attrs := make(map[string]interface{})
|
||||
for _, fldName := range v1AuthReply.Attributes.AlteredFields {
|
||||
@@ -1363,8 +1364,7 @@ func (v1AuthReply *V1AuthorizeReply) AsNavigableMap(ignr []*config.CfgCdrField)
|
||||
if v1AuthReply.StatQueueIDs != nil {
|
||||
cgrReply[utils.CapStatQueues] = *v1AuthReply.StatQueueIDs
|
||||
}
|
||||
cgrReply[utils.Error] = "" // so we can compare in filters
|
||||
return
|
||||
return engine.NewNavigableMap(cgrReply), nil
|
||||
}
|
||||
|
||||
// BiRPCV1Authorize performs authorization for CGREvent based on specific components
|
||||
@@ -1552,8 +1552,9 @@ type V1InitSessionReply struct {
|
||||
}
|
||||
|
||||
// AsNavigableMap is part of engine.NavigableMapper interface
|
||||
func (v1Rply *V1InitSessionReply) AsNavigableMap(ignr []*config.CfgCdrField) (cgrReply engine.NavigableMap, err error) {
|
||||
cgrReply = make(map[string]interface{})
|
||||
func (v1Rply *V1InitSessionReply) AsNavigableMap(
|
||||
ignr []*config.CfgCdrField) (*engine.NavigableMap, error) {
|
||||
cgrReply := make(map[string]interface{})
|
||||
if v1Rply.Attributes != nil {
|
||||
attrs := make(map[string]interface{})
|
||||
for _, fldName := range v1Rply.Attributes.AlteredFields {
|
||||
@@ -1575,8 +1576,7 @@ func (v1Rply *V1InitSessionReply) AsNavigableMap(ignr []*config.CfgCdrField) (cg
|
||||
if v1Rply.StatQueueIDs != nil {
|
||||
cgrReply[utils.CapStatQueues] = *v1Rply.StatQueueIDs
|
||||
}
|
||||
cgrReply[utils.Error] = ""
|
||||
return
|
||||
return engine.NewNavigableMap(cgrReply), nil
|
||||
}
|
||||
|
||||
// BiRPCV2InitiateSession initiates a new session, returns the maximum duration the session can last
|
||||
@@ -1732,8 +1732,9 @@ type V1UpdateSessionReply struct {
|
||||
}
|
||||
|
||||
// AsNavigableMap is part of engine.NavigableMapper interface
|
||||
func (v1Rply *V1UpdateSessionReply) AsNavigableMap(ignr []*config.CfgCdrField) (cgrReply engine.NavigableMap, err error) {
|
||||
cgrReply = make(map[string]interface{})
|
||||
func (v1Rply *V1UpdateSessionReply) AsNavigableMap(
|
||||
ignr []*config.CfgCdrField) (*engine.NavigableMap, error) {
|
||||
cgrReply := make(map[string]interface{})
|
||||
if v1Rply.Attributes != nil {
|
||||
attrs := make(map[string]interface{})
|
||||
for _, fldName := range v1Rply.Attributes.AlteredFields {
|
||||
@@ -1746,8 +1747,7 @@ func (v1Rply *V1UpdateSessionReply) AsNavigableMap(ignr []*config.CfgCdrField) (
|
||||
if v1Rply.MaxUsage != nil {
|
||||
cgrReply[utils.CapMaxUsage] = *v1Rply.MaxUsage
|
||||
}
|
||||
cgrReply[utils.Error] = ""
|
||||
return
|
||||
return engine.NewNavigableMap(cgrReply), nil
|
||||
}
|
||||
|
||||
// BiRPCV1UpdateSession updates an existing session, returning the duration which the session can still last
|
||||
@@ -1899,8 +1899,9 @@ type V1ProcessEventReply struct {
|
||||
}
|
||||
|
||||
// AsNavigableMap is part of engine.NavigableMapper interface
|
||||
func (v1Rply *V1ProcessEventReply) AsNavigableMap(ignr []*config.CfgCdrField) (cgrReply engine.NavigableMap, err error) {
|
||||
cgrReply = make(map[string]interface{})
|
||||
func (v1Rply *V1ProcessEventReply) AsNavigableMap(
|
||||
ignr []*config.CfgCdrField) (*engine.NavigableMap, error) {
|
||||
cgrReply := make(map[string]interface{})
|
||||
if v1Rply.MaxUsage != nil {
|
||||
cgrReply[utils.CapMaxUsage] = *v1Rply.MaxUsage
|
||||
}
|
||||
@@ -1916,8 +1917,7 @@ func (v1Rply *V1ProcessEventReply) AsNavigableMap(ignr []*config.CfgCdrField) (c
|
||||
}
|
||||
cgrReply[utils.CapAttributes] = attrs
|
||||
}
|
||||
cgrReply[utils.Error] = ""
|
||||
return
|
||||
return engine.NewNavigableMap(cgrReply), nil
|
||||
}
|
||||
|
||||
// Called on session end, should send the CDR to CDRS
|
||||
|
||||
Reference in New Issue
Block a user