diff --git a/agents/agentreq.go b/agents/agentreq.go index 6b7789da7..1ff54b4fe 100644 --- a/agents/agentreq.go +++ b/agents/agentreq.go @@ -29,8 +29,7 @@ import ( func newAgentRequest(req config.DataProvider, vars map[string]interface{}, tntTpl config.RSRParsers, - dfltTenant string, filterS *engine.FilterS, - templates map[string][]*config.FCTemplate) (ar *AgentRequest) { + dfltTenant string, filterS *engine.FilterS) (ar *AgentRequest) { ar = &AgentRequest{ Request: req, Vars: config.NewNavigableMap(vars), @@ -38,7 +37,6 @@ func newAgentRequest(req config.DataProvider, vars map[string]interface{}, CGRReply: config.NewNavigableMap(nil), Reply: config.NewNavigableMap(nil), filterS: filterS, - templates: templates, } // populate tenant if tntIf, err := ar.ParseField( @@ -61,7 +59,6 @@ type AgentRequest struct { CGRReply *config.NavigableMap Reply *config.NavigableMap filterS *engine.FilterS - templates map[string][]*config.FCTemplate } // String implements engine.DataProvider @@ -109,29 +106,6 @@ func (ar *AgentRequest) FieldAsString(fldPath []string) (val string, err error) func (ar *AgentRequest) AsNavigableMap(tplFlds []*config.FCTemplate) ( nM *config.NavigableMap, err error) { nM = config.NewNavigableMap(nil) - // expand template fields - for i := 0; i < len(tplFlds); { - if tplFlds[i].Type == utils.MetaTemplate { - tplId, err := tplFlds[i].Value.ParseDataProvider(ar, utils.NestingSep) - if err != nil { - return nil, err - } - refTpl, has := ar.templates[tplId] - if !has { - return nil, fmt.Errorf("no template with id: <%s>", tplId) - } else if len(refTpl) == 0 { - continue - } - wrkSlice := make([]*config.FCTemplate, len(refTpl)+len(tplFlds[i:])-1) // so we can cover tplFlds[i+1:] - copy(wrkSlice[:len(refTpl)], refTpl) // copy fields out of referenced template - if len(tplFlds[i:]) > 1 { // copy the rest of the fields after MetaTemplate - copy(wrkSlice[len(refTpl):], tplFlds[i+1:]) - } - tplFlds = append(tplFlds[:i], wrkSlice...) // append the work - continue // don't increase index so we can recheck - } - i++ - } for _, tplFld := range tplFlds { if pass, err := ar.filterS.Pass(ar.Tenant, tplFld.Filters, ar); err != nil { diff --git a/agents/agentreq_test.go b/agents/agentreq_test.go index 046508e6b..45608d215 100644 --- a/agents/agentreq_test.go +++ b/agents/agentreq_test.go @@ -33,8 +33,7 @@ func TestAgReqAsNavigableMap(t *testing.T) { dm := engine.NewDataManager(data) cfg, _ := config.NewDefaultCGRConfig() filterS := engine.NewFilterS(cfg, nil, dm) - agReq := newAgentRequest(nil, nil, nil, - "cgrates.org", filterS, nil) + agReq := newAgentRequest(nil, nil, nil, "cgrates.org", filterS) // populate request, emulating the way will be done in HTTPAgent agReq.CGRRequest.Set([]string{utils.CGRID}, utils.Sha1("dsafdsaf", time.Date(2013, 11, 7, 8, 42, 26, 0, time.UTC).String()), false) diff --git a/agents/dmtagent.go b/agents/dmtagent.go index c3a6ca1d0..df4fc1bd0 100644 --- a/agents/dmtagent.go +++ b/agents/dmtagent.go @@ -47,6 +47,16 @@ func NewDiameterAgent(cgrCfg *config.CGRConfig, filterS *engine.FilterS, return nil, err } } + msgTemplates := da.cgrCfg.DiameterAgentCfg().Templates + // Inflate *template field types + for _, procsr := range da.cgrCfg.DiameterAgentCfg().RequestProcessors { + if err := procsr.RequestFields.InflateTemplates(msgTemplates); err != nil { + return nil, err + } + if err := procsr.ReplyFields.InflateTemplates(msgTemplates); err != nil { + return nil, err + } + } return da, nil } @@ -111,8 +121,8 @@ func (da *DiameterAgent) handleMessage(c diam.Conn, m *diam.Message) { reqProcessor, newAgentRequest( newDADataProvider(m), reqVars, - reqProcessor.Tenant, da.cgrCfg.DefaultTenant, da.filterS, - da.cgrCfg.DiameterAgentCfg().Templates), + reqProcessor.Tenant, + da.cgrCfg.DefaultTenant, da.filterS), rply) if lclProcessed { processed = lclProcessed diff --git a/agents/httpagent.go b/agents/httpagent.go index 2775099fe..50c769e8d 100644 --- a/agents/httpagent.go +++ b/agents/httpagent.go @@ -62,7 +62,7 @@ func (ha *HTTPAgent) ServeHTTP(w http.ResponseWriter, req *http.Request) { utils.HTTPAgent, err.Error())) return } - agReq := newAgentRequest(dcdr, nil, ha.tenantCfg, ha.dfltTenant, ha.filterS, nil) + agReq := newAgentRequest(dcdr, nil, ha.tenantCfg, ha.dfltTenant, ha.filterS) var processed bool for _, reqProcessor := range ha.reqProcessors { var lclProcessed bool diff --git a/agents/librad_test.go b/agents/librad_test.go index 370a31917..523d71cea 100644 --- a/agents/librad_test.go +++ b/agents/librad_test.go @@ -97,7 +97,7 @@ func TestRadComposedFieldValue(t *testing.T) { if err := pkt.AddAVPWithName("Cisco-NAS-Port", "CGR1", "Cisco"); err != nil { t.Error(err) } - agReq := newAgentRequest(nil, nil, nil, "cgrates.org", nil, nil) + agReq := newAgentRequest(nil, nil, nil, "cgrates.org", nil) agReq.Vars.Set([]string{MetaRadReqType}, MetaRadAcctStart, false) agReq.Vars.Set([]string{"Cisco"}, "CGR1", false) agReq.Vars.Set([]string{"User-Name"}, "flopsy", false) @@ -117,7 +117,7 @@ func TestRadFieldOutVal(t *testing.T) { t.Error(err) } eOut := fmt.Sprintf("%s|flopsy|CGR1", MetaRadAcctStart) - agReq := newAgentRequest(nil, nil, nil, "cgrates.org", nil, nil) + agReq := newAgentRequest(nil, nil, nil, "cgrates.org", nil) agReq.Vars.Set([]string{MetaRadReqType}, MetaRadAcctStart, false) agReq.Vars.Set([]string{"Cisco"}, "CGR1", false) agReq.Vars.Set([]string{"User-Name"}, "flopsy", false) @@ -139,7 +139,7 @@ func TestRadReplyAppendAttributes(t *testing.T) { &config.FCTemplate{Tag: "Acct-Session-Time", FieldId: "Acct-Session-Time", Type: utils.META_COMPOSED, Value: config.NewRSRParsersMustCompile("~*cgrep.MaxUsage{*duration_seconds}", true)}, } - agReq := newAgentRequest(nil, nil, nil, "cgrates.org", nil, nil) + agReq := newAgentRequest(nil, nil, nil, "cgrates.org", nil) agReq.CGRReply.Set([]string{utils.CapMaxUsage}, time.Duration(time.Hour), false) agReq.CGRReply.Set([]string{utils.CapAttributes, "RadReply"}, "AccessAccept", false) agReq.CGRReply.Set([]string{utils.CapAttributes, utils.Account}, "1001", false) diff --git a/agents/radagent.go b/agents/radagent.go index 5b30a1429..9f8724158 100644 --- a/agents/radagent.go +++ b/agents/radagent.go @@ -84,7 +84,7 @@ func (ra *RadiusAgent) handleAuth(req *radigo.Packet) (rpl *radigo.Packet, err e var processed bool for _, reqProcessor := range ra.cgrCfg.RadiusAgentCfg().RequestProcessors { agReq := newAgentRequest(dcdr, nil, reqProcessor.Tenant, - ra.cgrCfg.DefaultTenant, ra.filterS, nil) + ra.cgrCfg.DefaultTenant, ra.filterS) agReq.Vars.Set([]string{MetaRadReqType}, utils.StringToInterface(MetaRadAuth), true) var lclProcessed bool if lclProcessed, err = ra.processRequest(reqProcessor, agReq, rpl); lclProcessed { @@ -123,7 +123,7 @@ func (ra *RadiusAgent) handleAcct(req *radigo.Packet) (rpl *radigo.Packet, err e var processed bool for _, reqProcessor := range ra.cgrCfg.RadiusAgentCfg().RequestProcessors { agReq := newAgentRequest(dcdr, nil, reqProcessor.Tenant, - ra.cgrCfg.DefaultTenant, ra.filterS, nil) + ra.cgrCfg.DefaultTenant, ra.filterS) var lclProcessed bool if lclProcessed, err = ra.processRequest(reqProcessor, agReq, rpl); lclProcessed { processed = lclProcessed diff --git a/config/daconfig.go b/config/daconfig.go index 15dd442b7..2772a31d7 100644 --- a/config/daconfig.go +++ b/config/daconfig.go @@ -31,7 +31,7 @@ type DiameterAgentCfg struct { OriginRealm string VendorId int ProductName string - Templates map[string][]*FCTemplate + Templates map[string]FCTemplates RequestProcessors []*DARequestProcessor } @@ -69,7 +69,7 @@ func (da *DiameterAgentCfg) loadFromJsonCfg(jsnCfg *DiameterAgentJsonCfg) (err e } if jsnCfg.Templates != nil { if da.Templates == nil { - da.Templates = make(map[string][]*FCTemplate) + da.Templates = make(map[string]FCTemplates) } for k, jsnTpls := range jsnCfg.Templates { if da.Templates[k], err = FCTemplatesFromFCTemplatesJsonCfg(jsnTpls); err != nil { @@ -107,8 +107,8 @@ type DARequestProcessor struct { Flags utils.StringMap Timezone string // timezone for timestamps where not specified <""|UTC|Local|$IANA_TZ_DB> ContinueOnSuccess bool - RequestFields []*FCTemplate - ReplyFields []*FCTemplate + RequestFields FCTemplates + ReplyFields FCTemplates } func (dap *DARequestProcessor) loadFromJsonCfg(jsnCfg *DARequestProcessorJsnCfg) (err error) { diff --git a/config/fctemplate.go b/config/fctemplate.go index d138eca71..7f57270db 100755 --- a/config/fctemplate.go +++ b/config/fctemplate.go @@ -18,6 +18,12 @@ along with this program. If not, see package config +import ( + "fmt" + + "github.com/cgrates/cgrates/utils" +) + func NewFCTemplateFromFCTemplateJsonCfg(jsnCfg *FcTemplateJsonCfg) (*FCTemplate, error) { fcTmp := new(FCTemplate) var err error @@ -122,3 +128,32 @@ func FCTemplatesFromFCTemplatesJsonCfg(jsnCfgFlds []*FcTemplateJsonCfg) ([]*FCTe } return retFields, nil } + +type FCTemplates []*FCTemplate + +// PopulateFromTemplates will replace fields of type "*template" with values out of map +func (tpls FCTemplates) InflateTemplates(msgTemplates map[string]FCTemplates) (err error) { + for i := 0; i < len(tpls); { + if tpls[i].Type == utils.MetaTemplate { + var tplID string + if tplID, err = tpls[i].Value.ParseValue(nil); err != nil { + return + } + refTpl, has := msgTemplates[tplID] + if !has { + return fmt.Errorf("no template with id: <%s>", tplID) + } else if len(refTpl) == 0 { + continue + } + wrkSlice := make([]*FCTemplate, len(refTpl)+len(tpls[i:])-1) // so we can cover tpls[i+1:] + copy(wrkSlice[:len(refTpl)], refTpl) // copy fields out of referenced template + if len(tpls[i:]) > 1 { // copy the rest of the fields after MetaTemplate + copy(wrkSlice[len(refTpl):], tpls[i+1:]) + } + tpls = append(tpls[:i], wrkSlice...) // append the work + continue // don't increase index so we can recheck + } + i++ + } + return +}