mirror of
https://github.com/cgrates/cgrates.git
synced 2026-02-11 18:16:24 +05:00
Initial AgentRequest with SetFields
This commit is contained in:
@@ -83,6 +83,7 @@ type AgentRequest struct {
|
||||
filterS *engine.FilterS
|
||||
Header config.DataProvider
|
||||
Trailer config.DataProvider
|
||||
diamreq *config.NavigableMap // used in case of building requests (ie. DisconnectSession)
|
||||
}
|
||||
|
||||
// String implements engine.DataProvider
|
||||
@@ -103,23 +104,18 @@ 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.FieldAsInterface(fldPath[1:])
|
||||
val, err = ar.Vars.GetField(fldPath[1:])
|
||||
case utils.MetaCgreq:
|
||||
val, err = ar.CGRRequest.FieldAsInterface(fldPath[1:])
|
||||
val, err = ar.CGRRequest.GetField(fldPath[1:])
|
||||
case utils.MetaCgrep:
|
||||
val, err = ar.CGRReply.FieldAsInterface(fldPath[1:])
|
||||
val, err = ar.CGRReply.GetField(fldPath[1:])
|
||||
case utils.MetaRep:
|
||||
val, err = ar.Reply.FieldAsInterface(fldPath[1:])
|
||||
case utils.MetaCGRAReq:
|
||||
val, err = ar.CGRAReq.FieldAsInterface(fldPath[1:])
|
||||
val, err = ar.Reply.GetField(fldPath[1:])
|
||||
case utils.MetaHdr:
|
||||
val, err = ar.Header.FieldAsInterface(fldPath[1:])
|
||||
case utils.MetaTrl:
|
||||
val, err = ar.Trailer.FieldAsInterface(fldPath[1:])
|
||||
}
|
||||
if nmItems, isNMItems := val.([]*config.NMItem); isNMItems { // special handling of NMItems, take the last value out of it
|
||||
val = nmItems[len(nmItems)-1].Data // could be we need nil protection here
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -129,17 +125,24 @@ func (ar *AgentRequest) FieldAsString(fldPath []string) (val string, err error)
|
||||
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
|
||||
}
|
||||
return utils.IfaceAsString(iface), nil
|
||||
}
|
||||
|
||||
// AsNavigableMap implements engine.DataProvider
|
||||
func (ar *AgentRequest) AsNavigableMap(tplFlds []*config.FCTemplate) (
|
||||
nM *config.NavigableMap, err error) {
|
||||
ar.CGRAReq = config.NewNavigableMap(nil)
|
||||
return nil, utils.ErrNotImplemented
|
||||
}
|
||||
|
||||
//SetFields will populate fields of AgentRequest out of templates
|
||||
func (ar *AgentRequest) SetFields(tplFlds []*config.FCTemplate) (err error) {
|
||||
for _, tplFld := range tplFlds {
|
||||
if pass, err := ar.filterS.Pass(ar.Tenant,
|
||||
tplFld.Filters, ar); err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
} else if !pass {
|
||||
continue
|
||||
}
|
||||
@@ -153,15 +156,15 @@ func (ar *AgentRequest) AsNavigableMap(tplFlds []*config.FCTemplate) (
|
||||
}
|
||||
err = utils.ErrPrefixNotFound(tplFld.Tag)
|
||||
}
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
var valSet []*config.NMItem
|
||||
fldPath := strings.Split(tplFld.Path, utils.NestingSep)
|
||||
|
||||
nMItm := &config.NMItem{Data: out, Path: fldPath, Config: tplFld}
|
||||
if nMFields, err := ar.CGRAReq.FieldAsInterface(fldPath); err != nil {
|
||||
nMItm := &config.NMItem{Data: out, Path: fldPath[1:], Config: tplFld}
|
||||
if nMFields, err := ar.FieldAsInterface(fldPath); err != nil {
|
||||
if err != utils.ErrNotFound {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
valSet = nMFields.([]*config.NMItem) // start from previous stored fields
|
||||
@@ -173,13 +176,29 @@ func (ar *AgentRequest) AsNavigableMap(tplFlds []*config.FCTemplate) (
|
||||
valSet = valSet[:len(valSet)-1] // discard the last item
|
||||
}
|
||||
valSet = append(valSet, nMItm)
|
||||
ar.CGRAReq.Set(fldPath, valSet, false, true)
|
||||
switch fldPath[0] {
|
||||
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:
|
||||
if ar.diamreq == nil {
|
||||
ar.diamreq = config.NewNavigableMap(nil) // special case when CGRateS is building the request
|
||||
}
|
||||
ar.diamreq.Set(fldPath[1:], valSet, false, true)
|
||||
}
|
||||
}
|
||||
if tplFld.Blocker { // useful in case of processing errors first
|
||||
break
|
||||
}
|
||||
}
|
||||
return ar.CGRAReq, nil
|
||||
return
|
||||
}
|
||||
|
||||
// ParseField outputs the value based on the template item
|
||||
|
||||
@@ -93,6 +93,59 @@ func (nM *NavigableMap) Set(path []string, data interface{}, apnd, ordered bool)
|
||||
}
|
||||
}
|
||||
|
||||
// GetField returns a field in it's original format, without converting from ie. *NMItem
|
||||
func (nM *NavigableMap) GetField(path []string) (fldVal interface{}, err error) {
|
||||
lenPath := len(path)
|
||||
if lenPath == 0 {
|
||||
return nil, errors.New("empty field path")
|
||||
}
|
||||
lastMp := nM.data // last map when layered
|
||||
for i, spath := range path {
|
||||
if i == lenPath-1 { // lastElement
|
||||
return nM.getLastRealItem(lastMp, spath)
|
||||
}
|
||||
if lastMp, err = nM.getNextMap(lastMp, spath); err != nil {
|
||||
return
|
||||
}
|
||||
}
|
||||
panic("BUG") // should never make it here
|
||||
}
|
||||
|
||||
// getLastItem returns the item from the map
|
||||
// checking if it needs to return the item or an element of him if the item is a slice
|
||||
func (nM *NavigableMap) getLastRealItem(mp map[string]interface{}, spath string) (val interface{}, err error) {
|
||||
var idx *int
|
||||
spath, idx = nM.getIndex(spath)
|
||||
var has bool
|
||||
val, has = mp[spath]
|
||||
if !has {
|
||||
return nil, utils.ErrNotFound
|
||||
}
|
||||
if idx == nil {
|
||||
return val, nil
|
||||
}
|
||||
switch vt := val.(type) {
|
||||
case []string:
|
||||
if *idx > len(vt) {
|
||||
return nil, fmt.Errorf("selector index %d out of range", *idx)
|
||||
}
|
||||
return vt[*idx], nil
|
||||
default:
|
||||
}
|
||||
// only if all above fails use reflect:
|
||||
vr := reflect.ValueOf(val)
|
||||
if vr.Kind() == reflect.Ptr {
|
||||
vr = vr.Elem()
|
||||
}
|
||||
if vr.Kind() != reflect.Slice && vr.Kind() != reflect.Array {
|
||||
return nil, fmt.Errorf("selector index used on non slice type(%T)", val)
|
||||
}
|
||||
if *idx > vr.Len() {
|
||||
return nil, fmt.Errorf("selector index %d out of range", *idx)
|
||||
}
|
||||
return vr.Index(*idx).Interface(), nil
|
||||
}
|
||||
|
||||
// FieldAsInterface returns the field value as interface{} for the path specified
|
||||
// implements DataProvider
|
||||
// supports spath with selective elements in case of []*NMItem
|
||||
|
||||
@@ -997,6 +997,77 @@ func TestNavMapgetLastItem(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestNavMapGetField(t *testing.T) {
|
||||
nM := &NavigableMap{
|
||||
data: map[string]interface{}{
|
||||
"FirstLevel": map[string]interface{}{
|
||||
"SecondLevel": map[string]interface{}{
|
||||
"ThirdLevel": map[string]interface{}{
|
||||
"Fld1": []*NMItem{
|
||||
{
|
||||
Path: []string{"FirstLevel", "SecondLevel", "ThirdLevel", "Fld1"},
|
||||
Data: "Val1",
|
||||
},
|
||||
{
|
||||
Path: []string{"FirstLevel", "SecondLevel", "ThirdLevel", "Fld1"},
|
||||
Data: "Val2",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"FirstLevel2": map[string]interface{}{
|
||||
"SecondLevel2": []map[string]interface{}{
|
||||
map[string]interface{}{
|
||||
"ThirdLevel2": map[string]interface{}{
|
||||
"Fld1": "Val1",
|
||||
},
|
||||
},
|
||||
map[string]interface{}{
|
||||
"Count": 10,
|
||||
"ThirdLevel2": map[string]interface{}{
|
||||
"Fld2": []string{"Val1", "Val2", "Val3"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
"AnotherFirstLevel": "ValAnotherFirstLevel",
|
||||
},
|
||||
}
|
||||
pth := []string{"FirstLevel", "SecondLevel", "ThirdLevel", "Fld1[0]"}
|
||||
eFld := &NMItem{
|
||||
Path: []string{"FirstLevel", "SecondLevel", "ThirdLevel", "Fld1"},
|
||||
Data: "Val1",
|
||||
}
|
||||
if fld, err := nM.GetField(pth); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eFld, fld) {
|
||||
t.Errorf("expecting: %s, received: %s", utils.ToIJSON(eFld), utils.ToIJSON(fld))
|
||||
}
|
||||
eFld2 := map[string]interface{}{"Fld1": "Val1"}
|
||||
pth = []string{"FirstLevel2", "SecondLevel2[0]", "ThirdLevel2"}
|
||||
if fld, err := nM.GetField(pth); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eFld2, fld) {
|
||||
t.Errorf("expecting: %s, received: %s", utils.ToIJSON(eFld2), utils.ToIJSON(fld))
|
||||
}
|
||||
eFld3 := "ValAnotherFirstLevel"
|
||||
pth = []string{"AnotherFirstLevel"}
|
||||
if fld, err := nM.GetField(pth); err != nil {
|
||||
t.Error(err)
|
||||
} else if !reflect.DeepEqual(eFld3, fld) {
|
||||
t.Errorf("expecting: %s, received: %s", utils.ToIJSON(eFld3), utils.ToIJSON(fld))
|
||||
}
|
||||
pth = []string{"AnotherFirstLevel2"}
|
||||
if _, err := nM.GetField(pth); err == nil || err != utils.ErrNotFound {
|
||||
t.Error(err)
|
||||
}
|
||||
pth = []string{"FirstLevel", "SecondLevel[1]", "ThirdLevel", "Fld1[0]"}
|
||||
if _, err := nM.GetField(pth); err == nil || err != utils.ErrNotFound {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestNavMapFieldAsInterface(t *testing.T) {
|
||||
nM := &NavigableMap{
|
||||
data: map[string]interface{}{
|
||||
|
||||
@@ -621,6 +621,7 @@ const (
|
||||
MaxCost = "MaxCost"
|
||||
MetaLoaders = "*loaders"
|
||||
TmpSuffix = ".tmp"
|
||||
MetaDiamreq = "*diamreq"
|
||||
)
|
||||
|
||||
// Migrator Action
|
||||
|
||||
Reference in New Issue
Block a user