diff --git a/config/xmlcdrc.go b/config/xmlcdrc.go
new file mode 100644
index 000000000..ea2ad43b9
--- /dev/null
+++ b/config/xmlcdrc.go
@@ -0,0 +1,50 @@
+/*
+Real-time Charging System for Telecom & ISP environments
+Copyright (C) 2012-2014 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 (
+ "encoding/xml"
+ "github.com/cgrates/cgrates/utils"
+)
+
+type CgrXmlCdrcCfg struct {
+ Enabled bool `xml:"enabled"` // Enable/Disable the
+ CdrsAddress string `xml:"cdrs_address"` // The address where CDRs can be reached
+ CdrsMethod string `xml:"cdrs_method"` // Method to use when posting CDRs
+ CdrType string `xml:"cdr_type"` // The type of CDR to process
+ RunDelay int64 `xml:"run_delay"` // Delay between runs
+ CdrInDir string `xml:"cdr_in_dir"` // Folder to process CDRs from
+ CdrOutDir string `xml:"cdr_out_dir"` // Folder to move processed CDRs to
+ CdrSourceId string `xml:"cdr_source_id"` // Source identifier for the processed CDRs
+ CdrFields []CdrcField `xml:"fields>field"`
+}
+
+type CdrcField struct {
+ XMLName xml.Name `xml:"field"`
+ Id string `xml:"id,attr"`
+ Filter string `xml:"filter,attr"`
+ RSRField *utils.RSRField
+}
+
+func (cdrcFld *CdrcField) PopulateRSRFIeld() (err error) {
+ if cdrcFld.RSRField, err = utils.NewRSRField(cdrcFld.Filter); err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/config/xmlcdrc_test.go b/config/xmlcdrc_test.go
new file mode 100644
index 000000000..140eb2d1a
--- /dev/null
+++ b/config/xmlcdrc_test.go
@@ -0,0 +1,116 @@
+/*
+Real-time Charging System for Telecom & ISP environments
+Copyright (C) 2012-2014 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 (
+ "encoding/xml"
+ "github.com/cgrates/cgrates/utils"
+ "reflect"
+ "strings"
+ "testing"
+)
+
+var cfgDocCdrc *CgrXmlCfgDocument // Will be populated by first test
+
+func TestPopulateRSRFIeld(t *testing.T) {
+ cdrcField := CdrcField{Id: "TEST1", Filter: `~effective_caller_id_number:s/(\d+)/+$1/`}
+ if err := cdrcField.PopulateRSRFIeld(); err != nil {
+ t.Error("Unexpected error: ", err.Error())
+ } else if cdrcField.RSRField == nil {
+ t.Error("Failed loading the RSRField")
+ }
+ cdrcField = CdrcField{Id: "TEST2", Filter: `1`}
+ if err := cdrcField.PopulateRSRFIeld(); err != nil {
+ t.Error("Unexpected error: ", err.Error())
+ } else if cdrcField.RSRField == nil {
+ t.Error("Failed loading the RSRField")
+ }
+}
+
+func TestParseXmlCdrcConfig(t *testing.T) {
+ cfgXmlStr := `
+
+
+ true
+ internal
+ http_cgr
+ csv
+ 0
+ /var/log/cgrates/cdrc/in
+ /var/log/cgrates/cdrc/out
+ freeswitch_csv
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+`
+ var err error
+ reader := strings.NewReader(cfgXmlStr)
+ if cfgDocCdrc, err = ParseCgrXmlConfig(reader); err != nil {
+ t.Error(err.Error())
+ } else if cfgDocCdrc == nil {
+ t.Fatal("Could not parse xml configuration document")
+ }
+ if len(cfgDocCdrc.cdrcs) != 1 {
+ t.Error("Did not cache")
+ }
+}
+
+func TestGetCdrcCfg(t *testing.T) {
+ cdrcfg, err := cfgDocCdrc.GetCdrcCfg("CDRC-CSV1")
+ if err != nil {
+ t.Error("Unexpected error: ", err)
+ } else if cdrcfg == nil {
+ t.Error("No config instance returned")
+ }
+ expectCdrc := &CgrXmlCdrcCfg{Enabled: true, CdrsAddress: "internal", CdrsMethod: "http_cgr", CdrType: "csv",
+ RunDelay: 0, CdrInDir: "/var/log/cgrates/cdrc/in", CdrOutDir: "/var/log/cgrates/cdrc/out", CdrSourceId: "freeswitch_csv"}
+ cdrFlds := []CdrcField{CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.ACCID, Filter: "0"},
+ CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.REQTYPE, Filter: "1"},
+ CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.DIRECTION, Filter: "2"},
+ CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.TENANT, Filter: "3"},
+ CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.CATEGORY, Filter: "4"},
+ CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.ACCOUNT, Filter: "5"},
+ CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.SUBJECT, Filter: "6"},
+ CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.DESTINATION, Filter: "7"},
+ CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.SETUP_TIME, Filter: "8"},
+ CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.ANSWER_TIME, Filter: "9"},
+ CdrcField{XMLName: xml.Name{Local: "field"}, Id: utils.USAGE, Filter: "10"},
+ CdrcField{XMLName: xml.Name{Local: "field"}, Id: "extr1", Filter: "11"},
+ CdrcField{XMLName: xml.Name{Local: "field"}, Id: "extr2", Filter: "12"}}
+ for _, fld := range cdrFlds {
+ fld.PopulateRSRFIeld()
+ }
+ expectCdrc.CdrFields = cdrFlds
+ if !reflect.DeepEqual(expectCdrc, cdrcfg) {
+ t.Errorf("Expecting: %v, received: %v", expectCdrc, cdrcfg)
+ }
+}
diff --git a/config/xmlcdre.go b/config/xmlcdre.go
new file mode 100644
index 000000000..a1a68da82
--- /dev/null
+++ b/config/xmlcdre.go
@@ -0,0 +1,61 @@
+/*
+Real-time Charging System for Telecom & ISP environments
+Copyright (C) 2012-2014 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 (
+ "encoding/xml"
+)
+
+// The CdrExporter Fixed Width configuration instance
+type CgrXmlCdreFwCfg struct {
+ Header *CgrXmlCfgCdrHeader `xml:"header"`
+ Content *CgrXmlCfgCdrContent `xml:"content"`
+ Trailer *CgrXmlCfgCdrTrailer `xml:"trailer"`
+}
+
+// CDR header
+type CgrXmlCfgCdrHeader struct {
+ XMLName xml.Name `xml:"header"`
+ Fields []*CgrXmlCfgCdrField `xml:"fields>field"`
+}
+
+// CDR content
+type CgrXmlCfgCdrContent struct {
+ XMLName xml.Name `xml:"content"`
+ Fields []*CgrXmlCfgCdrField `xml:"fields>field"`
+}
+
+// CDR trailer
+type CgrXmlCfgCdrTrailer struct {
+ XMLName xml.Name `xml:"trailer"`
+ Fields []*CgrXmlCfgCdrField `xml:"fields>field"`
+}
+
+// CDR field
+type CgrXmlCfgCdrField struct {
+ XMLName xml.Name `xml:"field"`
+ Name string `xml:"name,attr"`
+ Type string `xml:"type,attr"`
+ Value string `xml:"value,attr"`
+ Width int `xml:"width,attr"` // Field width
+ Strip string `xml:"strip,attr"` // Strip strategy in case value is bigger than field width <""|left|xleft|right|xright>
+ Padding string `xml:"padding,attr"` // Padding strategy in case of value is smaller than width <""left|zeroleft|right>
+ Layout string `xml:"layout,attr"` // Eg. time format layout
+ Mandatory bool `xml:"mandatory,attr"` // If field is mandatory, empty value will be considered as error and CDR will not be exported
+}
diff --git a/config/xmlconfig_test.go b/config/xmlcdre_test.go
similarity index 93%
rename from config/xmlconfig_test.go
rename to config/xmlcdre_test.go
index 922747a6a..7840b402a 100644
--- a/config/xmlconfig_test.go
+++ b/config/xmlcdre_test.go
@@ -1,6 +1,6 @@
/*
-Rating system designed to be used in VoIP Carriers World
-Copyright (C) 2013 ITsysCOM
+Real-time Charging System for Telecom & ISP environments
+Copyright (C) 2012-2014 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
@@ -87,15 +87,7 @@ func TestParseXmlConfig(t *testing.T) {
} else if cfgDoc == nil {
t.Fatal("Could not parse xml configuration document")
}
-}
-
-func TestCacheCdreFWCfgs(t *testing.T) {
- if len(cfgDoc.cdrefws) != 0 {
- t.Error("Cache should be empty before caching")
- }
- if err := cfgDoc.cacheCdreFWCfgs(); err != nil {
- t.Error(err)
- } else if len(cfgDoc.cdrefws) != 1 {
+ if len(cfgDoc.cdrefws) != 1 {
t.Error("Did not cache")
}
}
diff --git a/config/xmlconfig.go b/config/xmlconfig.go
index 289375620..585b30587 100644
--- a/config/xmlconfig.go
+++ b/config/xmlconfig.go
@@ -1,6 +1,6 @@
/*
-Rating system designed to be used in VoIP Carriers World
-Copyright (C) 2013 ITsysCOM
+Real-time Charging System for Telecom & ISP environments
+Copyright (C) 2012-2014 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
@@ -32,6 +32,9 @@ func ParseCgrXmlConfig(reader io.Reader) (*CgrXmlCfgDocument, error) {
if err := decoder.Decode(xmlConfig); err != nil {
return nil, err
}
+ if err := xmlConfig.cacheAll(); err != nil {
+ return nil, err
+ }
return xmlConfig, nil
}
@@ -41,6 +44,7 @@ type CgrXmlCfgDocument struct {
Type string `xml:"type,attr"`
Configurations []*CgrXmlConfiguration `xml:"configuration"`
cdrefws map[string]*CgrXmlCdreFwCfg // Cache for processed fixed width config instances, key will be the id of the instance
+ cdrcs map[string]*CgrXmlCdrcCfg
}
// Storage for raw configuration
@@ -52,42 +56,19 @@ type CgrXmlConfiguration struct {
RawConfig []byte `xml:",innerxml"` // Used to store the configuration struct, as raw so we can store different types
}
-// The CdrExporter Fixed Width configuration instance
-type CgrXmlCdreFwCfg struct {
- Header *CgrXmlCfgCdrHeader `xml:"header"`
- Content *CgrXmlCfgCdrContent `xml:"content"`
- Trailer *CgrXmlCfgCdrTrailer `xml:"trailer"`
+func (cfgInst *CgrXmlConfiguration) rawConfigElement() []byte {
+ rawConfig := append([]byte(""), cfgInst.RawConfig...) // Encapsulate the rawConfig in one element so we can Unmarshall into one struct
+ rawConfig = append(rawConfig, []byte("")...)
+ return rawConfig
}
-// CDR header
-type CgrXmlCfgCdrHeader struct {
- XMLName xml.Name `xml:"header"`
- Fields []*CgrXmlCfgCdrField `xml:"fields>field"`
-}
-
-// CDR content
-type CgrXmlCfgCdrContent struct {
- XMLName xml.Name `xml:"content"`
- Fields []*CgrXmlCfgCdrField `xml:"fields>field"`
-}
-
-// CDR trailer
-type CgrXmlCfgCdrTrailer struct {
- XMLName xml.Name `xml:"trailer"`
- Fields []*CgrXmlCfgCdrField `xml:"fields>field"`
-}
-
-// CDR field
-type CgrXmlCfgCdrField struct {
- XMLName xml.Name `xml:"field"`
- Name string `xml:"name,attr"`
- Type string `xml:"type,attr"`
- Value string `xml:"value,attr"`
- Width int `xml:"width,attr"` // Field width
- Strip string `xml:"strip,attr"` // Strip strategy in case value is bigger than field width <""|left|xleft|right|xright>
- Padding string `xml:"padding,attr"` // Padding strategy in case of value is smaller than width <""left|zeroleft|right>
- Layout string `xml:"layout,attr"` // Eg. time format layout
- Mandatory bool `xml:"mandatory,attr"` // If field is mandatory, empty value will be considered as error and CDR will not be exported
+func (xmlCfg *CgrXmlCfgDocument) cacheAll() error {
+ for _, cacheFunc := range []func() error{xmlCfg.cacheCdreFWCfgs, xmlCfg.cacheCdrcCfgs} {
+ if err := cacheFunc(); err != nil {
+ return err
+ }
+ }
+ return nil
}
// Avoid building from raw config string always, so build cache here
@@ -110,14 +91,42 @@ func (xmlCfg *CgrXmlCfgDocument) cacheCdreFWCfgs() error {
return nil
}
-func (xmlCfg *CgrXmlCfgDocument) GetCdreFWCfg(instName string) (*CgrXmlCdreFwCfg, error) {
- if len(xmlCfg.cdrefws) == 0 { // First time, cache also
- if err := xmlCfg.cacheCdreFWCfgs(); err != nil {
- return nil, err
+// Avoid building from raw config string always, so build cache here
+func (xmlCfg *CgrXmlCfgDocument) cacheCdrcCfgs() error {
+ xmlCfg.cdrcs = make(map[string]*CgrXmlCdrcCfg)
+ for _, cfgInst := range xmlCfg.Configurations {
+ if cfgInst.Section != utils.CDRC {
+ continue // Another type of config instance, not interesting to process
}
+ cdrcCfg := new(CgrXmlCdrcCfg)
+ if err := xml.Unmarshal(cfgInst.rawConfigElement(), cdrcCfg); err != nil {
+ return err
+ } else if cdrcCfg == nil {
+ return fmt.Errorf("Could not unmarshal config instance: %s", cfgInst.Id)
+ }
+ // Cache rsr fields
+ for _, fld := range cdrcCfg.CdrFields {
+ if err := fld.PopulateRSRFIeld(); err != nil {
+ return fmt.Errorf("Populating field %s, error: %s", fld.Id, err.Error())
+ }
+ }
+ xmlCfg.cdrcs[cfgInst.Id] = cdrcCfg
}
- if cfg, hasIt := xmlCfg.cdrefws[instName]; hasIt {
+ return nil
+}
+
+func (xmlCfg *CgrXmlCfgDocument) GetCdreFWCfg(instName string) (*CgrXmlCdreFwCfg, error) {
+ if cfg, hasIt := xmlCfg.cdrefws[instName]; !hasIt {
+ return nil, nil
+ } else {
+ return cfg, nil
+ }
+}
+
+func (xmlCfg *CgrXmlCfgDocument) GetCdrcCfg(instName string) (*CgrXmlCdrcCfg, error) {
+ if cfg, hasIt := xmlCfg.cdrcs[instName]; !hasIt {
+ return nil, nil
+ } else {
return cfg, nil
}
- return nil, nil
}
diff --git a/utils/consts.go b/utils/consts.go
index 4c3d9c77d..6dee4842c 100644
--- a/utils/consts.go
+++ b/utils/consts.go
@@ -100,6 +100,7 @@ const (
CDRE_FIXED_WIDTH = "fwv"
XML_PROFILE_PREFIX = "*xml:"
CDRE = "cdre"
+ CDRC = "cdrc"
MASK_CHAR = "*"
CONCATENATED_KEY_SEP = ":"
META_DEFAULT = "*default"
diff --git a/utils/rsrfield.go b/utils/rsrfield.go
index aed9133cc..4af340f7f 100644
--- a/utils/rsrfield.go
+++ b/utils/rsrfield.go
@@ -1,6 +1,6 @@
/*
-Rating system designed to be used in VoIP Carriers World
-Copyright (C) 2013 ITsysCOM
+Real-time Charging System for Telecom & ISP environments
+Copyright (C) 2012-2014 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
diff --git a/utils/rsrfield_test.go b/utils/rsrfield_test.go
index 539b319ce..fcf466540 100644
--- a/utils/rsrfield_test.go
+++ b/utils/rsrfield_test.go
@@ -1,6 +1,6 @@
/*
-Rating system designed to be used in VoIP Carriers World
-Copyright (C) 2013 ITsysCOM
+Real-time Charging System for Telecom & ISP environments
+Copyright (C) 2012-2014 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